From bb625e523867d3b8391a76e5aa7c22c081036835 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 16 Aug 2019 09:59:57 -0700 Subject: [PATCH 0001/1244] Remove the native delta client from Android Summary: This was an experiment to patch individual deltas in development instead of reloading the whole JS bundle. With improvements such as Fast Refresh that reduces the need for reloads and bundle splitting that reduces the number of modules and memory by 10x, we won't be needing this complex optimization that we never properly made work. This diff removes that code and I will be removing the JS side of things in Metro in a follow-up diff. Reviewed By: fkgozali Differential Revision: D16832709 fbshipit-source-id: 46596a3126d52d7d74f4b9ffc9a6ee9d82ec9522 --- .../facebook/react/ReactInstanceManager.java | 16 +- .../react/bridge/CatalystInstanceImpl.java | 10 - .../facebook/react/bridge/JSBundleLoader.java | 22 -- .../react/bridge/JSBundleLoaderDelegate.java | 11 - .../react/bridge/NativeDeltaClient.java | 25 -- .../react/devsupport/BundleDeltaClient.java | 202 ---------------- .../react/devsupport/BundleDownloader.java | 76 +----- .../react/devsupport/DevInternalSettings.java | 38 --- .../react/devsupport/DevServerHelper.java | 21 +- .../devsupport/DevSupportManagerImpl.java | 7 +- .../ReactInstanceManagerDevHelper.java | 3 +- .../interfaces/DevBundleDownloadListener.java | 3 +- .../jni/react/jni/CatalystInstanceImpl.cpp | 216 ++++++++++-------- .../main/jni/react/jni/CatalystInstanceImpl.h | 58 +++-- .../main/jni/react/jni/NativeDeltaClient.cpp | 57 ----- .../main/jni/react/jni/NativeDeltaClient.h | 41 ---- .../src/main/jni/react/jni/OnLoad.cpp | 35 +-- .../res/devsupport/xml/rn_dev_preferences.xml | 18 +- .../devsupport/BundleDeltaClientTest.java | 135 ----------- 19 files changed, 198 insertions(+), 796 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java delete mode 100644 ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp delete mode 100644 ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h delete mode 100644 ReactAndroid/src/test/java/com/facebook/react/devsupport/BundleDeltaClientTest.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index ec98de63758763..48dcbc93471fd3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -56,7 +56,6 @@ import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; -import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.bridge.NativeModuleCallExceptionHandler; import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; @@ -279,8 +278,8 @@ public void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { } @Override - public void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient) { - ReactInstanceManager.this.onJSBundleLoadedFromServer(nativeDeltaClient); + public void onJSBundleLoadedFromServer() { + ReactInstanceManager.this.onJSBundleLoadedFromServer(); } @Override @@ -389,7 +388,7 @@ public void run() { && !devSettings.isRemoteJSDebugEnabled()) { // If there is a up-to-date bundle downloaded from server, // with remote JS debugging disabled, always use that. - onJSBundleLoadedFromServer(null); + onJSBundleLoadedFromServer(); } else { // If dev server is down, disable the remote JS debugging. devSettings.setRemoteJSDebugEnabled(false); @@ -883,15 +882,12 @@ private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { } @ThreadConfined(UI) - private void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient) { + private void onJSBundleLoadedFromServer() { Log.d(ReactConstants.TAG, "ReactInstanceManager.onJSBundleLoadedFromServer()"); JSBundleLoader bundleLoader = - nativeDeltaClient == null - ? JSBundleLoader.createCachedBundleFromNetworkLoader( - mDevSupportManager.getSourceUrl(), mDevSupportManager.getDownloadedJSBundleFile()) - : JSBundleLoader.createDeltaFromNetworkLoader( - mDevSupportManager.getSourceUrl(), nativeDeltaClient); + JSBundleLoader.createCachedBundleFromNetworkLoader( + mDevSupportManager.getSourceUrl(), mDevSupportManager.getDownloadedJSBundleFile()); recreateReactContextInBackground(mJavaScriptExecutorFactory, bundleLoader); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java index d2aa466665d7d1..c2da5a77e5f532 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java @@ -233,13 +233,6 @@ public void loadScriptFromFile(String fileName, String sourceURL, boolean loadSy jniLoadScriptFromFile(fileName, sourceURL, loadSynchronously); } - @Override - public void loadScriptFromDeltaBundle( - String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously) { - mSourceURL = sourceURL; - jniLoadScriptFromDeltaBundle(sourceURL, deltaClient, loadSynchronously); - } - private native void jniSetSourceURL(String sourceURL); private native void jniRegisterSegment(int segmentId, String path); @@ -250,9 +243,6 @@ private native void jniLoadScriptFromAssets( private native void jniLoadScriptFromFile( String fileName, String sourceURL, boolean loadSynchronously); - private native void jniLoadScriptFromDeltaBundle( - String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously); - @Override public void runJSBundle() { Log.d(ReactConstants.TAG, "CatalystInstanceImpl.runJSBundle()"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java index 12b35eb17a8319..c83a40766a0225 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java @@ -72,28 +72,6 @@ public String loadScript(JSBundleLoaderDelegate delegate) { }; } - /** - * This loader is used to load delta bundles from the dev server. We pass each delta message to - * the loader and process it in C++. Passing it as a string leads to inefficiencies due to memory - * copies, which will have to be addressed in a follow-up. - * - * @param nativeDeltaClient - */ - public static JSBundleLoader createDeltaFromNetworkLoader( - final String sourceURL, final NativeDeltaClient nativeDeltaClient) { - return new JSBundleLoader() { - @Override - public String loadScript(JSBundleLoaderDelegate delegate) { - try { - delegate.loadScriptFromDeltaBundle(sourceURL, nativeDeltaClient, false); - return sourceURL; - } catch (Exception e) { - throw DebugServerException.makeGeneric(sourceURL, e.getMessage(), e); - } - } - }; - } - /** * This loader is used when proxy debugging is enabled. In that case there is no point in fetching * the bundle from device as remote executor will have to do it anyway. diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java index b21c5b6887d658..d4e6bb1cb93906 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoaderDelegate.java @@ -32,17 +32,6 @@ public interface JSBundleLoaderDelegate { */ void loadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously); - /** - * Load a delta bundle from Metro. See {@link JSBundleLoader#createDeltaFromNetworkLoader(String, - * NativeDeltaClient)} - * - * @param sourceURL - * @param deltaClient - * @param loadSynchronously - */ - void loadScriptFromDeltaBundle( - String sourceURL, NativeDeltaClient deltaClient, boolean loadSynchronously); - /** * This API is used in situations where the JS bundle is being executed not on the device, but on * a host machine. In that case, we must provide two source URLs for the JS bundle: One to be used diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java deleted file mode 100644 index 39ebf53b6360c3..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeDeltaClient.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.facebook.react.bridge; - -import com.facebook.jni.HybridData; -import java.nio.channels.ReadableByteChannel; - -public class NativeDeltaClient { - static { - ReactBridge.staticInit(); - } - - // C++ parts - private final HybridData mHybridData = initHybrid(); - - private static native HybridData initHybrid(); - - public native void reset(); - - public native void processDelta(ReadableByteChannel deltaMessage); -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java deleted file mode 100644 index 5dceb37de0e091..00000000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDeltaClient.java +++ /dev/null @@ -1,202 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.facebook.react.devsupport; - -import android.util.JsonReader; -import android.util.Pair; -import androidx.annotation.Nullable; -import com.facebook.react.bridge.NativeDeltaClient; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.TreeMap; -import okhttp3.Headers; -import okio.BufferedSource; - -public abstract class BundleDeltaClient { - - private static final String METRO_DELTA_ID_HEADER = "X-Metro-Delta-ID"; - @Nullable private String mRevisionId; - - public enum ClientType { - NONE, - DEV_SUPPORT, - NATIVE - } - - static boolean isDeltaUrl(String bundleUrl) { - return bundleUrl.indexOf(".delta?") != -1; - } - - @Nullable - static BundleDeltaClient create(ClientType type) { - switch (type) { - case DEV_SUPPORT: - return new BundleDeltaJavaClient(); - case NATIVE: - return new BundleDeltaNativeClient(); - } - return null; - } - - public abstract boolean canHandle(ClientType type); - - protected abstract Pair processDelta( - BufferedSource body, File outputFile) throws IOException; - - public final synchronized String extendUrlForDelta(String bundleURL) { - return mRevisionId != null ? bundleURL + "&revisionId=" + mRevisionId : bundleURL; - } - - public synchronized void reset() { - mRevisionId = null; - } - - public synchronized Pair processDelta( - Headers headers, BufferedSource body, File outputFile) throws IOException { - - mRevisionId = headers.get(METRO_DELTA_ID_HEADER); - return processDelta(body, outputFile); - } - - private static class BundleDeltaJavaClient extends BundleDeltaClient { - - byte[] mPreCode; - byte[] mPostCode; - final TreeMap mModules = new TreeMap(); - - @Override - public boolean canHandle(ClientType type) { - return type == ClientType.DEV_SUPPORT; - } - - public synchronized void reset() { - super.reset(); - mPreCode = null; - mPostCode = null; - mModules.clear(); - } - - @Override - public synchronized Pair processDelta( - BufferedSource body, File outputFile) throws IOException { - JsonReader jsonReader = new JsonReader(new InputStreamReader(body.inputStream())); - jsonReader.beginObject(); - int numChangedModules = 0; - - while (jsonReader.hasNext()) { - String name = jsonReader.nextName(); - if (name.equals("pre")) { - mPreCode = jsonReader.nextString().getBytes(); - } else if (name.equals("post")) { - mPostCode = jsonReader.nextString().getBytes(); - } else if (name.equals("modules")) { - numChangedModules += setModules(jsonReader, mModules); - } else if (name.equals("added")) { - numChangedModules += setModules(jsonReader, mModules); - } else if (name.equals("modified")) { - numChangedModules += setModules(jsonReader, mModules); - } else if (name.equals("deleted")) { - numChangedModules += removeModules(jsonReader, mModules); - } else { - jsonReader.skipValue(); - } - } - - jsonReader.endObject(); - jsonReader.close(); - - if (numChangedModules == 0) { - // If we receive an empty delta, we don't need to save the file again (it'll have the - // same content). - return Pair.create(Boolean.FALSE, null); - } - - FileOutputStream fileOutputStream = new FileOutputStream(outputFile); - - try { - fileOutputStream.write(mPreCode); - fileOutputStream.write('\n'); - - for (byte[] code : mModules.values()) { - fileOutputStream.write(code); - fileOutputStream.write('\n'); - } - - fileOutputStream.write(mPostCode); - fileOutputStream.write('\n'); - } finally { - fileOutputStream.flush(); - fileOutputStream.close(); - } - - return Pair.create(Boolean.TRUE, null); - } - - private static int setModules(JsonReader jsonReader, TreeMap map) - throws IOException { - jsonReader.beginArray(); - - int numModules = 0; - while (jsonReader.hasNext()) { - jsonReader.beginArray(); - - int moduleId = jsonReader.nextInt(); - - map.put(moduleId, jsonReader.nextString().getBytes()); - - jsonReader.endArray(); - numModules++; - } - - jsonReader.endArray(); - - return numModules; - } - - private static int removeModules(JsonReader jsonReader, TreeMap map) - throws IOException { - jsonReader.beginArray(); - - int numModules = 0; - while (jsonReader.hasNext()) { - int moduleId = jsonReader.nextInt(); - - map.remove(moduleId); - - numModules++; - } - - jsonReader.endArray(); - - return numModules; - } - } - - private static class BundleDeltaNativeClient extends BundleDeltaClient { - private final NativeDeltaClient nativeClient = new NativeDeltaClient(); - - @Override - public boolean canHandle(ClientType type) { - return type == ClientType.NATIVE; - } - - @Override - protected Pair processDelta(BufferedSource body, File outputFile) - throws IOException { - nativeClient.processDelta(body); - return Pair.create(Boolean.FALSE, nativeClient); - } - - @Override - public void reset() { - super.reset(); - nativeClient.reset(); - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java index 6478591c588dae..f5984bc8bb2ae6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java @@ -7,11 +7,9 @@ package com.facebook.react.devsupport; import android.util.Log; -import android.util.Pair; import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.common.DebugServerException; import com.facebook.react.common.ReactConstants; import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener; @@ -41,12 +39,9 @@ public class BundleDownloader { private final OkHttpClient mClient; - private BundleDeltaClient mBundleDeltaClient; - private @Nullable Call mDownloadBundleFromURLCall; public static class BundleInfo { - private @Nullable String mDeltaClientName; private @Nullable String mUrl; private int mFilesChangedCount; @@ -59,7 +54,6 @@ public static class BundleInfo { try { JSONObject obj = new JSONObject(jsonStr); - info.mDeltaClientName = obj.getString("deltaClient"); info.mUrl = obj.getString("url"); info.mFilesChangedCount = obj.getInt("filesChangedCount"); } catch (JSONException e) { @@ -74,7 +68,6 @@ public static class BundleInfo { JSONObject obj = new JSONObject(); try { - obj.put("deltaClient", mDeltaClientName); obj.put("url", mUrl); obj.put("filesChangedCount", mFilesChangedCount); } catch (JSONException e) { @@ -85,10 +78,6 @@ public static class BundleInfo { return obj.toString(); } - public @Nullable String getDeltaClient() { - return mDeltaClientName; - } - public String getUrl() { return mUrl != null ? mUrl : "unknown"; } @@ -106,10 +95,8 @@ public void downloadBundleFromURL( final DevBundleDownloadListener callback, final File outputFile, final String bundleURL, - final @Nullable BundleInfo bundleInfo, - final BundleDeltaClient.ClientType clientType) { - downloadBundleFromURL( - callback, outputFile, bundleURL, bundleInfo, clientType, new Request.Builder()); + final @Nullable BundleInfo bundleInfo) { + downloadBundleFromURL(callback, outputFile, bundleURL, bundleInfo, new Request.Builder()); } public void downloadBundleFromURL( @@ -117,12 +104,11 @@ public void downloadBundleFromURL( final File outputFile, final String bundleURL, final @Nullable BundleInfo bundleInfo, - final BundleDeltaClient.ClientType clientType, Request.Builder requestBuilder) { final Request request = requestBuilder - .url(formatBundleUrl(bundleURL, clientType)) + .url(formatBundleUrl(bundleURL)) // FIXME: there is a bug that makes MultipartStreamReader to never find the end of the // multipart message. This temporarily disables the multipart mode to work around it, // but @@ -165,8 +151,7 @@ public void onResponse(Call call, final Response response) throws IOException { Matcher match = regex.matcher(contentType); try (Response r = response) { if (match.find()) { - processMultipartResponse( - url, r, match.group(1), outputFile, bundleInfo, clientType, callback); + processMultipartResponse(url, r, match.group(1), outputFile, bundleInfo, callback); } else { // In case the server doesn't support multipart/mixed responses, fallback to normal // download. @@ -177,7 +162,6 @@ public void onResponse(Call call, final Response response) throws IOException { Okio.buffer(r.body().source()), outputFile, bundleInfo, - clientType, callback); } } @@ -185,12 +169,8 @@ public void onResponse(Call call, final Response response) throws IOException { }); } - private String formatBundleUrl(String bundleURL, BundleDeltaClient.ClientType clientType) { - return BundleDeltaClient.isDeltaUrl(bundleURL) - && mBundleDeltaClient != null - && mBundleDeltaClient.canHandle(clientType) - ? mBundleDeltaClient.extendUrlForDelta(bundleURL) - : bundleURL; + private String formatBundleUrl(String bundleURL) { + return bundleURL; } private void processMultipartResponse( @@ -199,7 +179,6 @@ private void processMultipartResponse( String boundary, final File outputFile, @Nullable final BundleInfo bundleInfo, - final BundleDeltaClient.ClientType clientType, final DevBundleDownloadListener callback) throws IOException { @@ -223,14 +202,7 @@ public void onChunkComplete( status = Integer.parseInt(headers.get("X-Http-Status")); } processBundleResult( - url, - status, - Headers.of(headers), - body, - outputFile, - bundleInfo, - clientType, - callback); + url, status, Headers.of(headers), body, outputFile, bundleInfo, callback); } else { if (!headers.containsKey("Content-Type") || !headers.get("Content-Type").equals("application/json")) { @@ -286,7 +258,6 @@ private void processBundleResult( BufferedSource body, File outputFile, BundleInfo bundleInfo, - BundleDeltaClient.ClientType clientType, DevBundleDownloadListener callback) throws IOException { // Check for server errors. If the server error has the expected form, fail with more info. @@ -311,41 +282,19 @@ private void processBundleResult( } if (bundleInfo != null) { - populateBundleInfo(url, headers, clientType, bundleInfo); + populateBundleInfo(url, headers, bundleInfo); } File tmpFile = new File(outputFile.getPath() + ".tmp"); - boolean bundleWritten; - NativeDeltaClient nativeDeltaClient = null; - - if (BundleDeltaClient.isDeltaUrl(url)) { - // If the bundle URL has the delta extension, we need to use the delta patching logic. - BundleDeltaClient deltaClient = getBundleDeltaClient(clientType); - Assertions.assertNotNull(deltaClient); - Pair result = deltaClient.processDelta(headers, body, tmpFile); - bundleWritten = result.first; - nativeDeltaClient = result.second; - } else { - mBundleDeltaClient = null; - bundleWritten = storePlainJSInFile(body, tmpFile); - } - - if (bundleWritten) { + if (storePlainJSInFile(body, tmpFile)) { // If we have received a new bundle from the server, move it to its final destination. if (!tmpFile.renameTo(outputFile)) { throw new IOException("Couldn't rename " + tmpFile + " to " + outputFile); } } - callback.onSuccess(nativeDeltaClient); - } - - private BundleDeltaClient getBundleDeltaClient(BundleDeltaClient.ClientType clientType) { - if (mBundleDeltaClient == null || !mBundleDeltaClient.canHandle(clientType)) { - mBundleDeltaClient = BundleDeltaClient.create(clientType); - } - return mBundleDeltaClient; + callback.onSuccess(); } private static boolean storePlainJSInFile(BufferedSource body, File outputFile) @@ -363,10 +312,7 @@ private static boolean storePlainJSInFile(BufferedSource body, File outputFile) return true; } - private static void populateBundleInfo( - String url, Headers headers, BundleDeltaClient.ClientType clientType, BundleInfo bundleInfo) { - bundleInfo.mDeltaClientName = - clientType == BundleDeltaClient.ClientType.NONE ? null : clientType.name(); + private static void populateBundleInfo(String url, Headers headers, BundleInfo bundleInfo) { bundleInfo.mUrl = url; String filesChangedCountStr = headers.get("X-Metro-Files-Changed-Count"); diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java index c4a48a4281b309..4465e8a6e9d75d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevInternalSettings.java @@ -6,7 +6,6 @@ */ package com.facebook.react.devsupport; -import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -27,8 +26,6 @@ public class DevInternalSettings private static final String PREFS_FPS_DEBUG_KEY = "fps_debug"; private static final String PREFS_JS_DEV_MODE_DEBUG_KEY = "js_dev_mode_debug"; private static final String PREFS_JS_MINIFY_DEBUG_KEY = "js_minify_debug"; - private static final String PREFS_JS_BUNDLE_DELTAS_KEY = "js_bundle_deltas"; - private static final String PREFS_JS_BUNDLE_DELTAS_CPP_KEY = "js_bundle_deltas_cpp"; private static final String PREFS_ANIMATIONS_DEBUG_KEY = "animations_debug"; // This option is no longer exposed in the dev menu UI. // It was renamed in D15958697 so it doesn't get stuck with no way to turn it off: @@ -42,24 +39,12 @@ public class DevInternalSettings private final SharedPreferences mPreferences; private final Listener mListener; private final PackagerConnectionSettings mPackagerConnectionSettings; - private final boolean mSupportsNativeDeltaClients; - - public static DevInternalSettings withoutNativeDeltaClient( - Context applicationContext, Listener listener) { - return new DevInternalSettings(applicationContext, listener, false); - } public DevInternalSettings(Context applicationContext, Listener listener) { - this(applicationContext, listener, true); - } - - private DevInternalSettings( - Context applicationContext, Listener listener, boolean supportsNativeDeltaClients) { mListener = listener; mPreferences = PreferenceManager.getDefaultSharedPreferences(applicationContext); mPreferences.registerOnSharedPreferenceChangeListener(this); mPackagerConnectionSettings = new PackagerConnectionSettings(applicationContext); - mSupportsNativeDeltaClients = supportsNativeDeltaClients; } public PackagerConnectionSettings getPackagerConnectionSettings() { @@ -99,8 +84,6 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin if (PREFS_FPS_DEBUG_KEY.equals(key) || PREFS_RELOAD_ON_JS_CHANGE_KEY.equals(key) || PREFS_JS_DEV_MODE_DEBUG_KEY.equals(key) - || PREFS_JS_BUNDLE_DELTAS_KEY.equals(key) - || PREFS_JS_BUNDLE_DELTAS_CPP_KEY.equals(key) || PREFS_START_SAMPLING_PROFILER_ON_INIT.equals(key) || PREFS_JS_MINIFY_DEBUG_KEY.equals(key)) { mListener.onInternalSettingsChanged(); @@ -132,27 +115,6 @@ public void setElementInspectorEnabled(boolean enabled) { mPreferences.edit().putBoolean(PREFS_INSPECTOR_DEBUG_KEY, enabled).apply(); } - @SuppressLint("SharedPreferencesUse") - public boolean isBundleDeltasEnabled() { - return mPreferences.getBoolean(PREFS_JS_BUNDLE_DELTAS_KEY, false); - } - - @SuppressLint("SharedPreferencesUse") - public void setBundleDeltasEnabled(boolean enabled) { - mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_KEY, enabled).apply(); - } - - @SuppressLint("SharedPreferencesUse") - public boolean isBundleDeltasCppEnabled() { - return mSupportsNativeDeltaClients - && mPreferences.getBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, false); - } - - @SuppressLint("SharedPreferencesUse") - public void setBundleDeltasCppEnabled(boolean enabled) { - mPreferences.edit().putBoolean(PREFS_JS_BUNDLE_DELTAS_CPP_KEY, enabled).apply(); - } - @Override public boolean isNuclideJSDebugEnabled() { return ReactBuildConfig.IS_INTERNAL_BUILD && ReactBuildConfig.DEBUG; diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java index 09681da38cffe2..52c6477761108b 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevServerHelper.java @@ -102,7 +102,6 @@ public interface SymbolicationListener { private enum BundleType { BUNDLE("bundle"), - DELTA("delta"), MAP("map"); private final String mTypeID; @@ -397,8 +396,7 @@ public void downloadBundleFromURL( File outputFile, String bundleURL, BundleDownloader.BundleInfo bundleInfo) { - mBundleDownloader.downloadBundleFromURL( - callback, outputFile, bundleURL, bundleInfo, getDeltaClientType()); + mBundleDownloader.downloadBundleFromURL(callback, outputFile, bundleURL, bundleInfo); } public void downloadBundleFromURL( @@ -408,17 +406,7 @@ public void downloadBundleFromURL( BundleDownloader.BundleInfo bundleInfo, Request.Builder requestBuilder) { mBundleDownloader.downloadBundleFromURL( - callback, outputFile, bundleURL, bundleInfo, getDeltaClientType(), requestBuilder); - } - - private BundleDeltaClient.ClientType getDeltaClientType() { - if (mSettings.isBundleDeltasCppEnabled()) { - return BundleDeltaClient.ClientType.NATIVE; - } else if (mSettings.isBundleDeltasEnabled()) { - return BundleDeltaClient.ClientType.DEV_SUPPORT; - } else { - return BundleDeltaClient.ClientType.NONE; - } + callback, outputFile, bundleURL, bundleInfo, requestBuilder); } /** @return the host to use when connecting to the bundle server from the host itself. */ @@ -475,7 +463,7 @@ private static String createOpenStackFrameURL(String host) { public String getDevServerBundleURL(final String jsModulePath) { return createBundleURL( jsModulePath, - mSettings.isBundleDeltasEnabled() ? BundleType.DELTA : BundleType.BUNDLE, + BundleType.BUNDLE, mSettings.getPackagerConnectionSettings().getDebugServerHost()); } @@ -652,8 +640,7 @@ public String getSourceMapUrl(String mainModuleName) { } public String getSourceUrl(String mainModuleName) { - return createBundleURL( - mainModuleName, mSettings.isBundleDeltasEnabled() ? BundleType.DELTA : BundleType.BUNDLE); + return createBundleURL(mainModuleName, BundleType.BUNDLE); } public String getJSBundleURLForRemoteDebugging(String mainModuleName) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java index 70b3eb954d0982..163e27e4ef6637 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerImpl.java @@ -30,7 +30,6 @@ import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler; import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; -import com.facebook.react.bridge.NativeDeltaClient; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactMarker; import com.facebook.react.bridge.ReactMarkerConstants; @@ -1026,7 +1025,7 @@ public void reloadJSFromServer(final String bundleURL) { mDevServerHelper.downloadBundleFromURL( new DevBundleDownloadListener() { @Override - public void onSuccess(final @Nullable NativeDeltaClient nativeDeltaClient) { + public void onSuccess() { mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; synchronized (DevSupportManagerImpl.this) { @@ -1034,7 +1033,7 @@ public void onSuccess(final @Nullable NativeDeltaClient nativeDeltaClient) { mBundleStatus.updateTimestamp = System.currentTimeMillis(); } if (mBundleDownloadListener != null) { - mBundleDownloadListener.onSuccess(nativeDeltaClient); + mBundleDownloadListener.onSuccess(); } UiThreadUtil.runOnUiThread( new Runnable() { @@ -1042,7 +1041,7 @@ public void onSuccess(final @Nullable NativeDeltaClient nativeDeltaClient) { public void run() { ReactMarker.logMarker( ReactMarkerConstants.DOWNLOAD_END, bundleInfo.toJSONString()); - mReactInstanceManagerHelper.onJSBundleLoadedFromServer(nativeDeltaClient); + mReactInstanceManagerHelper.onJSBundleLoadedFromServer(); } }); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java index 6cb86590225487..5807b243d00563 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/ReactInstanceManagerDevHelper.java @@ -10,7 +10,6 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.JavaJSExecutor; import com.facebook.react.bridge.JavaScriptExecutorFactory; -import com.facebook.react.bridge.NativeDeltaClient; /** * Interface used by {@link DevSupportManager} for accessing some fields and methods of {@link @@ -22,7 +21,7 @@ public interface ReactInstanceManagerDevHelper { void onReloadWithJSDebugger(JavaJSExecutor.Factory proxyExecutorFactory); /** Notify react instance manager about new JS bundle version downloaded from the server. */ - void onJSBundleLoadedFromServer(@Nullable NativeDeltaClient nativeDeltaClient); + void onJSBundleLoadedFromServer(); /** Request to toggle the react element inspector. */ void toggleElementInspector(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java index 8ddd20af41c41e..00ed879e3554b1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/interfaces/DevBundleDownloadListener.java @@ -7,10 +7,9 @@ package com.facebook.react.devsupport.interfaces; import androidx.annotation.Nullable; -import com.facebook.react.bridge.NativeDeltaClient; public interface DevBundleDownloadListener { - void onSuccess(@Nullable NativeDeltaClient nativeDeltaClient); + void onSuccess(); void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total); diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp index 3782296ea2887f..1f03c154ae8aea 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.cpp @@ -5,32 +5,31 @@ #include "CatalystInstanceImpl.h" -#include #include +#include #include #include +#include #include #include #include #include -#include #include #include #include -#include #include -#include +#include #include -#include +#include #include +#include #include #include -#include #include "CxxModuleWrapper.h" -#include "JavaScriptExecutorHolder.h" #include "JNativeRunnable.h" +#include "JavaScriptExecutorHolder.h" #include "JniJSModulesUnbundle.h" #include "NativeArray.h" @@ -48,14 +47,15 @@ class Exception : public jni::JavaClass { class JInstanceCallback : public InstanceCallback { public: explicit JInstanceCallback( - alias_ref jobj, - std::shared_ptr messageQueueThread) - : jobj_(make_global(jobj)), messageQueueThread_(std::move(messageQueueThread)) {} + alias_ref jobj, + std::shared_ptr messageQueueThread) + : jobj_(make_global(jobj)), + messageQueueThread_(std::move(messageQueueThread)) {} void onBatchComplete() override { messageQueueThread_->runOnQueue([this] { - static auto method = - ReactCallback::javaClassStatic()->getMethod("onBatchComplete"); + static auto method = ReactCallback::javaClassStatic()->getMethod( + "onBatchComplete"); method(jobj_); }); } @@ -65,15 +65,15 @@ class JInstanceCallback : public InstanceCallback { // managed by the module, via callJSCallback or callJSFunction. So, // we ensure that it is registered with the JVM. jni::ThreadScope guard; - static auto method = - ReactCallback::javaClassStatic()->getMethod("incrementPendingJSCalls"); + static auto method = ReactCallback::javaClassStatic()->getMethod( + "incrementPendingJSCalls"); method(jobj_); } void decrementPendingJSCalls() override { jni::ThreadScope guard; - static auto method = - ReactCallback::javaClassStatic()->getMethod("decrementPendingJSCalls"); + static auto method = ReactCallback::javaClassStatic()->getMethod( + "decrementPendingJSCalls"); method(jobj_); } @@ -82,15 +82,15 @@ class JInstanceCallback : public InstanceCallback { std::shared_ptr messageQueueThread_; }; -} +} // namespace -jni::local_ref CatalystInstanceImpl::initHybrid( - jni::alias_ref) { +jni::local_ref +CatalystInstanceImpl::initHybrid(jni::alias_ref) { return makeCxxInstance(); } CatalystInstanceImpl::CatalystInstanceImpl() - : instance_(folly::make_unique()) {} + : instance_(folly::make_unique()) {} CatalystInstanceImpl::~CatalystInstanceImpl() { if (moduleMessageQueue_ != NULL) { @@ -100,20 +100,34 @@ CatalystInstanceImpl::~CatalystInstanceImpl() { void CatalystInstanceImpl::registerNatives() { registerHybrid({ - makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid), - makeNativeMethod("initializeBridge", CatalystInstanceImpl::initializeBridge), - makeNativeMethod("jniExtendNativeModules", CatalystInstanceImpl::extendNativeModules), - makeNativeMethod("jniSetSourceURL", CatalystInstanceImpl::jniSetSourceURL), - makeNativeMethod("jniRegisterSegment", CatalystInstanceImpl::jniRegisterSegment), - makeNativeMethod("jniLoadScriptFromAssets", CatalystInstanceImpl::jniLoadScriptFromAssets), - makeNativeMethod("jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile), - makeNativeMethod("jniLoadScriptFromDeltaBundle", CatalystInstanceImpl::jniLoadScriptFromDeltaBundle), - makeNativeMethod("jniCallJSFunction", CatalystInstanceImpl::jniCallJSFunction), - makeNativeMethod("jniCallJSCallback", CatalystInstanceImpl::jniCallJSCallback), - makeNativeMethod("setGlobalVariable", CatalystInstanceImpl::setGlobalVariable), - makeNativeMethod("getJavaScriptContext", CatalystInstanceImpl::getJavaScriptContext), - makeNativeMethod("getJSCallInvokerHolder", CatalystInstanceImpl::getJSCallInvokerHolder), - makeNativeMethod("jniHandleMemoryPressure", CatalystInstanceImpl::handleMemoryPressure), + makeNativeMethod("initHybrid", CatalystInstanceImpl::initHybrid), + makeNativeMethod( + "initializeBridge", CatalystInstanceImpl::initializeBridge), + makeNativeMethod( + "jniExtendNativeModules", CatalystInstanceImpl::extendNativeModules), + makeNativeMethod( + "jniSetSourceURL", CatalystInstanceImpl::jniSetSourceURL), + makeNativeMethod( + "jniRegisterSegment", CatalystInstanceImpl::jniRegisterSegment), + makeNativeMethod( + "jniLoadScriptFromAssets", + CatalystInstanceImpl::jniLoadScriptFromAssets), + makeNativeMethod( + "jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile), + makeNativeMethod( + "jniCallJSFunction", CatalystInstanceImpl::jniCallJSFunction), + makeNativeMethod( + "jniCallJSCallback", CatalystInstanceImpl::jniCallJSCallback), + makeNativeMethod( + "setGlobalVariable", CatalystInstanceImpl::setGlobalVariable), + makeNativeMethod( + "getJavaScriptContext", CatalystInstanceImpl::getJavaScriptContext), + makeNativeMethod( + "getJSCallInvokerHolder", + CatalystInstanceImpl::getJSCallInvokerHolder), + makeNativeMethod( + "jniHandleMemoryPressure", + CatalystInstanceImpl::handleMemoryPressure), }); JNativeRunnable::registerNatives(); @@ -122,18 +136,23 @@ void CatalystInstanceImpl::registerNatives() { void CatalystInstanceImpl::initializeBridge( jni::alias_ref callback, // This executor is actually a factory holder. - JavaScriptExecutorHolder* jseh, + JavaScriptExecutorHolder *jseh, jni::alias_ref jsQueue, jni::alias_ref nativeModulesQueue, - jni::alias_ref::javaobject> javaModules, - jni::alias_ref::javaobject> cxxModules) { + jni::alias_ref::javaobject> + javaModules, + jni::alias_ref::javaobject> + cxxModules) { // TODO mhorowitz: how to assert here? - // Assertions.assertCondition(mBridge == null, "initializeBridge should be called once"); - moduleMessageQueue_ = std::make_shared(nativeModulesQueue); + // Assertions.assertCondition(mBridge == null, "initializeBridge should be + // called once"); + moduleMessageQueue_ = + std::make_shared(nativeModulesQueue); // This used to be: // - // Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> Bridge::Callback + // Java CatalystInstanceImpl -> C++ CatalystInstanceImpl -> Bridge -> + // Bridge::Callback // --weak--> ReactCallback -> Java CatalystInstanceImpl // // Now the weak ref is a global ref. So breaking the loop depends on @@ -147,45 +166,46 @@ void CatalystInstanceImpl::initializeBridge( // don't need jsModuleDescriptions any more, all the way up and down the // stack. - moduleRegistry_ = std::make_shared( - buildNativeModuleList( - std::weak_ptr(instance_), - javaModules, - cxxModules, - moduleMessageQueue_)); + moduleRegistry_ = std::make_shared(buildNativeModuleList( + std::weak_ptr(instance_), + javaModules, + cxxModules, + moduleMessageQueue_)); instance_->initializeBridge( - std::make_unique( - callback, - moduleMessageQueue_), - jseh->getExecutorFactory(), - folly::make_unique(jsQueue), - moduleRegistry_); + std::make_unique(callback, moduleMessageQueue_), + jseh->getExecutorFactory(), + folly::make_unique(jsQueue), + moduleRegistry_); } void CatalystInstanceImpl::extendNativeModules( - jni::alias_ref::javaobject> javaModules, - jni::alias_ref::javaobject> cxxModules) { + jni::alias_ref::javaobject> + javaModules, + jni::alias_ref::javaobject> + cxxModules) { moduleRegistry_->registerModules(buildNativeModuleList( - std::weak_ptr(instance_), - javaModules, - cxxModules, - moduleMessageQueue_)); + std::weak_ptr(instance_), + javaModules, + cxxModules, + moduleMessageQueue_)); } -void CatalystInstanceImpl::jniSetSourceURL(const std::string& sourceURL) { +void CatalystInstanceImpl::jniSetSourceURL(const std::string &sourceURL) { instance_->setSourceURL(sourceURL); } -void CatalystInstanceImpl::jniRegisterSegment(int segmentId, const std::string& path) { +void CatalystInstanceImpl::jniRegisterSegment( + int segmentId, + const std::string &path) { instance_->registerBundle((uint32_t)segmentId, path); } void CatalystInstanceImpl::jniLoadScriptFromAssets( jni::alias_ref assetManager, - const std::string& assetURL, + const std::string &assetURL, bool loadSynchronously) { - const int kAssetsLength = 9; // strlen("assets://"); + const int kAssetsLength = 9; // strlen("assets://"); auto sourceURL = assetURL.substr(kAssetsLength); auto manager = extractAssetManager(assetManager); @@ -194,47 +214,37 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets( auto bundle = JniJSModulesUnbundle::fromEntryFile(manager, sourceURL); auto registry = RAMBundleRegistry::singleBundleRegistry(std::move(bundle)); instance_->loadRAMBundle( - std::move(registry), - std::move(script), - sourceURL, - loadSynchronously); + std::move(registry), std::move(script), sourceURL, loadSynchronously); return; } else if (Instance::isIndexedRAMBundle(&script)) { instance_->loadRAMBundleFromString(std::move(script), sourceURL); } else { - instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); + instance_->loadScriptFromString( + std::move(script), sourceURL, loadSynchronously); } } -void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName, - const std::string& sourceURL, - bool loadSynchronously) { +void CatalystInstanceImpl::jniLoadScriptFromFile( + const std::string &fileName, + const std::string &sourceURL, + bool loadSynchronously) { if (Instance::isIndexedRAMBundle(fileName.c_str())) { instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously); } else { std::unique_ptr script; RecoverableError::runRethrowingAsRecoverable( - [&fileName, &script]() { - script = JSBigFileString::fromPath(fileName); - }); - instance_->loadScriptFromString(std::move(script), sourceURL, loadSynchronously); + [&fileName, &script]() { + script = JSBigFileString::fromPath(fileName); + }); + instance_->loadScriptFromString( + std::move(script), sourceURL, loadSynchronously); } } -void CatalystInstanceImpl::jniLoadScriptFromDeltaBundle( - const std::string& sourceURL, - jni::alias_ref jDeltaClient, - bool loadSynchronously) { - - auto deltaClient = jDeltaClient->cthis()->getDeltaClient(); - auto registry = RAMBundleRegistry::singleBundleRegistry( - folly::make_unique(deltaClient)); - - instance_->loadRAMBundle( - std::move(registry), deltaClient->getStartupCode(), sourceURL, loadSynchronously); -} - -void CatalystInstanceImpl::jniCallJSFunction(std::string module, std::string method, NativeArray* arguments) { +void CatalystInstanceImpl::jniCallJSFunction( + std::string module, + std::string method, + NativeArray *arguments) { // We want to share the C++ code, and on iOS, modules pass module/method // names as strings all the way through to JS, and there's no way to do // string -> id mapping on the objc side. So on Android, we convert the @@ -242,39 +252,45 @@ void CatalystInstanceImpl::jniCallJSFunction(std::string module, std::string met // used as ids if isFinite(), which handles this case, and looked up as // strings otherwise. Eventually, we'll probably want to modify the stack // from the JS proxy through here to use strings, too. - instance_->callJSFunction(std::move(module), - std::move(method), - arguments->consume()); + instance_->callJSFunction( + std::move(module), std::move(method), arguments->consume()); } -void CatalystInstanceImpl::jniCallJSCallback(jint callbackId, NativeArray* arguments) { +void CatalystInstanceImpl::jniCallJSCallback( + jint callbackId, + NativeArray *arguments) { instance_->callJSCallback(callbackId, arguments->consume()); } -void CatalystInstanceImpl::setGlobalVariable(std::string propName, - std::string&& jsonValue) { +void CatalystInstanceImpl::setGlobalVariable( + std::string propName, + std::string &&jsonValue) { // This is only ever called from Java with short strings, and only // for testing, so no need to try hard for zero-copy here. - instance_->setGlobalVariable(std::move(propName), - folly::make_unique(std::move(jsonValue))); + instance_->setGlobalVariable( + std::move(propName), + folly::make_unique(std::move(jsonValue))); } jlong CatalystInstanceImpl::getJavaScriptContext() { - return (jlong) (intptr_t) instance_->getJavaScriptContext(); + return (jlong)(intptr_t)instance_->getJavaScriptContext(); } void CatalystInstanceImpl::handleMemoryPressure(int pressureLevel) { instance_->handleMemoryPressure(pressureLevel); } -jni::alias_ref CatalystInstanceImpl::getJSCallInvokerHolder() { +jni::alias_ref +CatalystInstanceImpl::getJSCallInvokerHolder() { if (!javaInstanceHolder_) { jsCallInvoker_ = std::make_shared(instance_); - javaInstanceHolder_ = jni::make_global(JSCallInvokerHolder::newObjectCxxArgs(jsCallInvoker_)); + javaInstanceHolder_ = + jni::make_global(JSCallInvokerHolder::newObjectCxxArgs(jsCallInvoker_)); } return javaInstanceHolder_; } -}} +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h index dab2007434e8bc..6c39ae90f5cd67 100644 --- a/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h +++ b/ReactAndroid/src/main/jni/react/jni/CatalystInstanceImpl.h @@ -5,17 +5,16 @@ #include +#include +#include #include #include -#include -#include #include "CxxModuleWrapper.h" -#include "JavaModuleWrapper.h" #include "JMessageQueueThread.h" #include "JSLoader.h" +#include "JavaModuleWrapper.h" #include "ModuleRegistryBuilder.h" -#include "NativeDeltaClient.h" namespace facebook { namespace react { @@ -25,12 +24,14 @@ class JavaScriptExecutorHolder; class NativeArray; struct ReactCallback : public jni::JavaClass { - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ReactCallback;"; + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridge/ReactCallback;"; }; class CatalystInstanceImpl : public jni::HybridClass { public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/CatalystInstanceImpl;"; + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridge/CatalystInstanceImpl;"; static jni::local_ref initHybrid(jni::alias_ref); ~CatalystInstanceImpl() override; @@ -49,35 +50,47 @@ class CatalystInstanceImpl : public jni::HybridClass { void initializeBridge( jni::alias_ref callback, // This executor is actually a factory holder. - JavaScriptExecutorHolder* jseh, + JavaScriptExecutorHolder *jseh, jni::alias_ref jsQueue, jni::alias_ref moduleQueue, - jni::alias_ref::javaobject> javaModules, - jni::alias_ref::javaobject> cxxModules); + jni::alias_ref< + jni::JCollection::javaobject> + javaModules, + jni::alias_ref::javaobject> + cxxModules); void extendNativeModules( - jni::alias_ref::javaobject> javaModules, - jni::alias_ref::javaobject> cxxModules); + jni::alias_ref::javaobject> javaModules, + jni::alias_ref::javaobject> + cxxModules); /** * Sets the source URL of the underlying bridge without loading any JS code. */ - void jniSetSourceURL(const std::string& sourceURL); + void jniSetSourceURL(const std::string &sourceURL); /** * Registers the file path of an additional JS segment by its ID. * */ - void jniRegisterSegment(int segmentId, const std::string& path); - - void jniLoadScriptFromAssets(jni::alias_ref assetManager, const std::string& assetURL, bool loadSynchronously); - void jniLoadScriptFromFile(const std::string& fileName, const std::string& sourceURL, bool loadSynchronously); - void jniLoadScriptFromDeltaBundle(const std::string& sourceURL, jni::alias_ref deltaClient, bool loadSynchronously); - void jniCallJSFunction(std::string module, std::string method, NativeArray* arguments); - void jniCallJSCallback(jint callbackId, NativeArray* arguments); + void jniRegisterSegment(int segmentId, const std::string &path); + + void jniLoadScriptFromAssets( + jni::alias_ref assetManager, + const std::string &assetURL, + bool loadSynchronously); + void jniLoadScriptFromFile( + const std::string &fileName, + const std::string &sourceURL, + bool loadSynchronously); + void jniCallJSFunction( + std::string module, + std::string method, + NativeArray *arguments); + void jniCallJSCallback(jint callbackId, NativeArray *arguments); jni::alias_ref getJSCallInvokerHolder(); - void setGlobalVariable(std::string propName, - std::string&& jsonValue); + void setGlobalVariable(std::string propName, std::string &&jsonValue); jlong getJavaScriptContext(); void handleMemoryPressure(int pressureLevel); @@ -90,4 +103,5 @@ class CatalystInstanceImpl : public jni::HybridClass { std::shared_ptr jsCallInvoker_; }; -}} +} // namespace react +} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp deleted file mode 100644 index 5a9c007bb24f01..00000000000000 --- a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#include "NativeDeltaClient.h" - -#include -#include -#include - -namespace facebook { -namespace react { - -jni::local_ref NativeDeltaClient::initHybrid( - jni::alias_ref) { - return makeCxxInstance(); -} - -void NativeDeltaClient::registerNatives() { - registerHybrid({ - makeNativeMethod("initHybrid", NativeDeltaClient::initHybrid), - makeNativeMethod("processDelta", NativeDeltaClient::jniProcessDelta), - makeNativeMethod("reset", NativeDeltaClient::jniReset), - }); -} - -void NativeDeltaClient::jniProcessDelta( - jni::alias_ref delta) { - - std::ostringstream deltaMessage; - std::vector buffer(8192); - auto byteBuffer = jni::JByteBuffer::wrapBytes(buffer.data(), buffer.size()); - - size_t pos = 0; - int read = 0; - do { - read = delta->read(byteBuffer); - if (read < 1) { - deltaMessage.write(reinterpret_cast(buffer.data()), pos); - byteBuffer->rewind(); - pos = 0; - } else { - pos += read; - } - } while (read != -1); - - - deltaClient_->patch(folly::parseJson(deltaMessage.str())); -} - -void NativeDeltaClient::jniReset() { - deltaClient_->clear(); -} - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h b/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h deleted file mode 100644 index a991e3a2c03ad3..00000000000000 --- a/ReactAndroid/src/main/jni/react/jni/NativeDeltaClient.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Facebook, Inc. and its affiliates. - -// This source code is licensed under the MIT license found in the -// LICENSE file in the root directory of this source tree. - -#pragma once - -#include - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -class NativeDeltaClient : public jni::HybridClass { - -public: - static constexpr auto kJavaDescriptor = - "Lcom/facebook/react/bridge/NativeDeltaClient;"; - static jni::local_ref initHybrid(jni::alias_ref); - static void registerNatives(); - - ~NativeDeltaClient() override = default; - - std::shared_ptr getDeltaClient() { - return deltaClient_; - } - -private: - friend HybridBase; - void jniProcessDelta(jni::alias_ref delta); - void jniReset(); - const std::shared_ptr deltaClient_ = - std::make_shared(); -}; - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index c754eb12b162e2..8c11fb99eb1c34 100644 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -13,9 +13,8 @@ #include "CatalystInstanceImpl.h" #include "CxxModuleWrapper.h" -#include "JavaScriptExecutorHolder.h" #include "JCallback.h" -#include "NativeDeltaClient.h" +#include "JavaScriptExecutorHolder.h" #include "ProxyExecutor.h" #include "WritableNativeArray.h" #include "WritableNativeMap.h" @@ -32,24 +31,28 @@ namespace react { namespace { struct JavaJSExecutor : public JavaClass { - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/JavaJSExecutor;"; + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridge/JavaJSExecutor;"; }; -class ProxyJavaScriptExecutorHolder : public HybridClass { +class ProxyJavaScriptExecutorHolder : public HybridClass< + ProxyJavaScriptExecutorHolder, + JavaScriptExecutorHolder> { public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ProxyJavaScriptExecutor;"; + static constexpr auto kJavaDescriptor = + "Lcom/facebook/react/bridge/ProxyJavaScriptExecutor;"; static local_ref initHybrid( - alias_ref, alias_ref executorInstance) { - return makeCxxInstance( - std::make_shared( + alias_ref, + alias_ref executorInstance) { + return makeCxxInstance(std::make_shared( make_global(executorInstance))); } static void registerNatives() { registerHybrid({ - makeNativeMethod("initHybrid", ProxyJavaScriptExecutorHolder::initHybrid), + makeNativeMethod( + "initHybrid", ProxyJavaScriptExecutorHolder::initHybrid), }); } @@ -58,9 +61,9 @@ class ProxyJavaScriptExecutorHolder : public HybridClass - - + - - This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.facebook.react.devsupport; - -import static org.fest.assertions.api.Assertions.assertThat; - -import com.facebook.react.common.StandardCharsets; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import okio.BufferedSource; -import okio.Okio; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -public class BundleDeltaClientTest { - private BundleDeltaClient mClient; - - @Rule public TemporaryFolder mFolder = new TemporaryFolder(); - - @Before - public void setUp() { - mClient = BundleDeltaClient.create(BundleDeltaClient.ClientType.DEV_SUPPORT); - } - - @Test - public void testAcceptsSimpleInitialBundle() throws IOException { - File file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"pre\": \"console.log('Hello World!');\"," - + "\"post\": \"console.log('That is all folks!');\"," - + "\"modules\": [[0, \"console.log('Best module.');\"]]" - + "}"), - file); - assertThat(contentOf(file)) - .isEqualTo( - "console.log('Hello World!');\n" - + "console.log('Best module.');\n" - + "console.log('That is all folks!');\n"); - } - - @Test - public void testPatchesInitialBundleWithDeltaBundle() throws IOException { - File file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"pre\": \"pre\"," - + "\"post\": \"post\"," - + "\"modules\": [[0, \"0\"], [1, \"1\"]]" - + "}"), - file); - file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"added\": [[2, \"2\"]]," - + "\"modified\": [[0, \"0.1\"]]," - + "\"deleted\": [1]" - + "}"), - file); - assertThat(contentOf(file)).isEqualTo("pre\n" + "0.1\n" + "2\n" + "post\n"); - } - - @Test - public void testSortsModulesByIdInInitialBundle() throws IOException { - File file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"pre\": \"console.log('Hello World!');\"," - + "\"post\": \"console.log('That is all folks!');\"," - + "\"modules\": [[3, \"3\"], [0, \"0\"], [2, \"2\"], [1, \"1\"]]" - + "}"), - file); - assertThat(contentOf(file)) - .isEqualTo( - "console.log('Hello World!');\n" - + "0\n" - + "1\n" - + "2\n" - + "3\n" - + "console.log('That is all folks!');\n"); - } - - @Test - public void testSortsModulesByIdInPatchedBundle() throws IOException { - File file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"pre\": \"console.log('Hello World!');\"," - + "\"post\": \"console.log('That is all folks!');\"," - + "\"modules\": [[3, \"3\"], [0, \"0\"], [1, \"1\"]]" - + "}"), - file); - file = mFolder.newFile(); - mClient.processDelta( - bufferedSource( - "{" - + "\"added\": [[2, \"2\"]]," - + "\"modified\": [[0, \"0.1\"]]," - + "\"deleted\": [1]" - + "}"), - file); - assertThat(contentOf(file)) - .isEqualTo( - "console.log('Hello World!');\n" - + "0.1\n" - + "2\n" - + "3\n" - + "console.log('That is all folks!');\n"); - } - - private static BufferedSource bufferedSource(String string) { - return Okio.buffer( - Okio.source(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)))); - } - - private static String contentOf(File file) throws IOException { - return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - } -} From 88d0ac17e8bf20c4134ba1b17827fa33eeec2ed2 Mon Sep 17 00:00:00 2001 From: Christoph Nakazawa Date: Fri, 16 Aug 2019 10:35:31 -0700 Subject: [PATCH 0002/1244] Metro Bundler -> Metro Summary: This bothers me, we renamed the project to drop the "Metro" a while ago. Reviewed By: rubennorte Differential Revision: D16831281 fbshipit-source-id: bb6de412eccda61b617580f3660e3e635f2d2815 --- RNTester/README.md | 2 +- .../DevSupport/RCTInspectorDevServerHelper.mm | 71 +++++++++---------- scripts/launchPackager.bat | 2 +- scripts/launchPackager.command | 2 +- scripts/react-native-xcode.sh | 2 +- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/RNTester/README.md b/RNTester/README.md index 33dfed103e0796..14133712cafcf1 100644 --- a/RNTester/README.md +++ b/RNTester/README.md @@ -70,7 +70,7 @@ When developing E2E tests, you may want to run in development mode, so that chan detox build -c ios.sim.debug detox test -c ios.sim.debug -You will also need to have Metro Bundler running in another terminal. Note that if you've previously run the E2E tests in release mode, you may need to delete the `RNTester/build` folder before rerunning `detox build`. +You will also need to have Metro running in another terminal. Note that if you've previously run the E2E tests in release mode, you may need to delete the `RNTester/build` folder before rerunning `detox build`. ## Building from source diff --git a/React/DevSupport/RCTInspectorDevServerHelper.mm b/React/DevSupport/RCTInspectorDevServerHelper.mm index ab339f5da14195..466eb8f543659d 100644 --- a/React/DevSupport/RCTInspectorDevServerHelper.mm +++ b/React/DevSupport/RCTInspectorDevServerHelper.mm @@ -7,8 +7,8 @@ #if RCT_DEV && !TARGET_OS_UIKITFORMAC -#import #import +#import #import #import @@ -37,12 +37,14 @@ if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) { inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]]; } - NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; - NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; + NSString *escapedDeviceName = [[[UIDevice currentDevice] name] + stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; + NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] + stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@", - getServerHost(bundleURL, inspectorProxyPort), - escapedDeviceName, - escapedAppName]]; + getServerHost(bundleURL, inspectorProxyPort), + escapedDeviceName, + escapedAppName]]; } static NSURL *getAttachDeviceUrl(NSURL *bundleURL, NSString *title) @@ -52,18 +54,20 @@ if (metroBundlerPortStr && [metroBundlerPortStr length] > 0) { metroBundlerPort = [NSNumber numberWithInt:[metroBundlerPortStr intValue]]; } - NSString *escapedDeviceName = [[[UIDevice currentDevice] name] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; - NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; + NSString *escapedDeviceName = [[[UIDevice currentDevice] name] + stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; + NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier] + stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet]; return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/attach-debugger-nuclide?title=%@&device=%@&app=%@", - getServerHost(bundleURL, metroBundlerPort), - title, - escapedDeviceName, - escapedAppName]]; + getServerHost(bundleURL, metroBundlerPort), + title, + escapedDeviceName, + escapedAppName]]; } @implementation RCTInspectorDevServerHelper -RCT_NOT_IMPLEMENTED(- (instancetype)init) +RCT_NOT_IMPLEMENTED(-(instancetype)init) static NSMutableDictionary *socketConnections = nil; @@ -74,23 +78,18 @@ static void sendEventToAllConnections(NSString *event) } } -static void displayErrorAlert(UIViewController *view, NSString *message) { - UIAlertController *alert = - [UIAlertController alertControllerWithTitle:nil - message:message - preferredStyle:UIAlertControllerStyleAlert]; +static void displayErrorAlert(UIViewController *view, NSString *message) +{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil + message:message + preferredStyle:UIAlertControllerStyleAlert]; [view presentViewController:alert animated:YES completion:nil]; - dispatch_after( - dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2.5), - dispatch_get_main_queue(), - ^{ - [alert dismissViewControllerAnimated:YES completion:nil]; - }); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2.5), dispatch_get_main_queue(), ^{ + [alert dismissViewControllerAnimated:YES completion:nil]; + }); } -+ (void)attachDebugger:(NSString *)owner - withBundleURL:(NSURL *)bundleURL - withView:(UIViewController *)view ++ (void)attachDebugger:(NSString *)owner withBundleURL:(NSURL *)bundleURL withView:(UIViewController *)view { NSURL *url = getAttachDeviceUrl(bundleURL, owner); @@ -98,15 +97,15 @@ + (void)attachDebugger:(NSString *)owner [request setHTTPMethod:@"GET"]; __weak UIViewController *viewCapture = view; - [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler: - ^(__unused NSData *_Nullable data, - __unused NSURLResponse *_Nullable response, - NSError *_Nullable error) { - UIViewController *viewCaptureStrong = viewCapture; - if (error != nullptr && viewCaptureStrong != nullptr) { - displayErrorAlert(viewCaptureStrong, @"The request to attach Nuclide couldn't reach Metro Bundler!"); - } - }] resume]; + [[[NSURLSession sharedSession] + dataTaskWithRequest:request + completionHandler:^( + __unused NSData *_Nullable data, __unused NSURLResponse *_Nullable response, NSError *_Nullable error) { + UIViewController *viewCaptureStrong = viewCapture; + if (error != nullptr && viewCaptureStrong != nullptr) { + displayErrorAlert(viewCaptureStrong, @"The request to attach Nuclide couldn't reach Metro!"); + } + }] resume]; } + (void)disableDebugger diff --git a/scripts/launchPackager.bat b/scripts/launchPackager.bat index 83bfb8dc138a57..ce71959a16d046 100644 --- a/scripts/launchPackager.bat +++ b/scripts/launchPackager.bat @@ -4,7 +4,7 @@ :: LICENSE file in the root directory of this source tree. @echo off -title Metro Bundler +title Metro call .packager.bat cd ../../../ node "%~dp0..\cli.js" start diff --git a/scripts/launchPackager.command b/scripts/launchPackager.command index 1c1278deb129a3..4a7748141bb639 100755 --- a/scripts/launchPackager.command +++ b/scripts/launchPackager.command @@ -5,7 +5,7 @@ # LICENSE file in the root directory of this source tree. # Set terminal title -echo -en "\\033]0;Metro Bundler\\a" +echo -en "\\033]0;Metro\\a" clear THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) diff --git a/scripts/react-native-xcode.sh b/scripts/react-native-xcode.sh index 8192eb94bc749e..3cee642678315e 100755 --- a/scripts/react-native-xcode.sh +++ b/scripts/react-native-xcode.sh @@ -12,7 +12,7 @@ set -x DEST=$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH -# Enables iOS devices to get the IP address of the machine running Metro Bundler +# Enables iOS devices to get the IP address of the machine running Metro if [[ "$CONFIGURATION" = *Debug* && ! "$PLATFORM_NAME" == *simulator ]]; then IP=$(ipconfig getifaddr en0) if [ -z "$IP" ]; then From 9a3d722ccb523f227ffd7770a809996e6cfe75d9 Mon Sep 17 00:00:00 2001 From: Tim Yung Date: Fri, 16 Aug 2019 10:51:40 -0700 Subject: [PATCH 0003/1244] RN: Delete Long Press Error in Touchable Summary: This error is not actionable or valuable right now. Reviewed By: cpojer Differential Revision: D16859423 fbshipit-source-id: b25504a9556b4d3102b35b2bffcd2d01566e0399 --- Libraries/Components/Touchable/Touchable.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index a37a4fa24d4f78..2e39937dce20a0 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -722,18 +722,9 @@ const TouchableMixin = { this.longPressDelayTimeout = null; const curState = this.state.touchable.touchState; if ( - curState !== States.RESPONDER_ACTIVE_PRESS_IN && - curState !== States.RESPONDER_ACTIVE_LONG_PRESS_IN + curState === States.RESPONDER_ACTIVE_PRESS_IN || + curState === States.RESPONDER_ACTIVE_LONG_PRESS_IN ) { - console.error( - 'Attempted to transition from state `' + - curState + - '` to `' + - States.RESPONDER_ACTIVE_LONG_PRESS_IN + - '`, which is not supported. This is ' + - 'most likely due to `Touchable.longPressDelayTimeout` not being cancelled.', - ); - } else { this._receiveSignal(Signals.LONG_PRESS_DETECTED, e); } }, From 81733d9e15c84e99c783bb5b9c63a7e9f1213201 Mon Sep 17 00:00:00 2001 From: Chet Corcos Date: Mon, 19 Aug 2019 02:48:19 -0700 Subject: [PATCH 0004/1244] Don't call sharedApplication in App Extension (#26077) Summary: Related to this bug: https://github.com/facebook/react-native/pull/25769 Note I also had to add to the bottom of my podfile because RCTLinking had APPLICATION_EXTENSION_API_ONLY='YES' by default somehow. ``` post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'NO' end end end ``` Pull Request resolved: https://github.com/facebook/react-native/pull/26077 Test Plan: Sandcastle should be sufficient. Reviewed By: shergin Differential Revision: D16860356 Pulled By: sammy-SC fbshipit-source-id: 02cb3fd3f977420ccdc2991f0c3666ab0186b7bf --- React/DevSupport/RCTDevLoadingView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/DevSupport/RCTDevLoadingView.m b/React/DevSupport/RCTDevLoadingView.m index ec53d8a98d7618..793c90b7ca89c6 100644 --- a/React/DevSupport/RCTDevLoadingView.m +++ b/React/DevSupport/RCTDevLoadingView.m @@ -74,7 +74,7 @@ - (void)setBridge:(RCTBridge *)bridge CGSize screenSize = [UIScreen mainScreen].bounds.size; if (@available(iOS 11.0, *)) { - UIWindow *window = UIApplication.sharedApplication.keyWindow; + UIWindow *window = RCTSharedApplication().keyWindow; self->_window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, window.safeAreaInsets.top + 30)]; self->_label = [[UILabel alloc] initWithFrame:CGRectMake(0, window.safeAreaInsets.top, screenSize.width, 30)]; } else { From bb272baccaf6a3a9d0849478855ab17dd197e412 Mon Sep 17 00:00:00 2001 From: Ram N Date: Mon, 19 Aug 2019 07:33:53 -0700 Subject: [PATCH 0005/1244] Don't enable Flipper in React Native by default Summary: Removing default integration of Flipper from OSS till discussions happen. To enable Flipper, just download the Flipper desktop app and uncomment the line in MainApplication.java. Flipper should automatically connect to your app. Reviewed By: rickhanlonii Differential Revision: D6654890 fbshipit-source-id: 692cf04fec3273703c0571d04f0100c0dbb8269b --- .../app/src/main/java/com/helloworld/MainApplication.java | 1 - 1 file changed, 1 deletion(-) diff --git a/template/android/app/src/main/java/com/helloworld/MainApplication.java b/template/android/app/src/main/java/com/helloworld/MainApplication.java index ae1ff7cf28e462..bd315af77c37ca 100644 --- a/template/android/app/src/main/java/com/helloworld/MainApplication.java +++ b/template/android/app/src/main/java/com/helloworld/MainApplication.java @@ -43,7 +43,6 @@ public ReactNativeHost getReactNativeHost() { public void onCreate() { super.onCreate(); SoLoader.init(this, /* native exopackage */ false); - initializeFlipper(this); // Remove this line if you don't want Flipper enabled } /** From 84f148ba440d6bfea56b77a10b4be4730a626d66 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:03:25 -0700 Subject: [PATCH 0006/1244] Delete UIManagerStatTracker Summary: This code was added in D2442406 in Sep 2015. We have other ways to track the calls to these methods these days. I'm not even sure if this works anymore and it isn't called anywhere. Reviewed By: JoshuaGross Differential Revision: D16833299 fbshipit-source-id: cad70c06b149ed424122a9a464564835e7a877e5 --- Libraries/ReactNative/UIManager.js | 7 +-- Libraries/ReactNative/UIManagerStatTracker.js | 62 ------------------- 2 files changed, 3 insertions(+), 66 deletions(-) delete mode 100644 Libraries/ReactNative/UIManagerStatTracker.js diff --git a/Libraries/ReactNative/UIManager.js b/Libraries/ReactNative/UIManager.js index 15a74e2bef0310..035a667099a236 100644 --- a/Libraries/ReactNative/UIManager.js +++ b/Libraries/ReactNative/UIManager.js @@ -13,15 +13,14 @@ import type {Spec} from './NativeUIManager'; interface UIManagerJSInterface extends Spec { +getViewManagerConfig: (viewManagerName: string) => Object; - // The following are not marked read-only due to logic in UIManagerStatTracker. - createView: ( + +createView: ( reactTag: ?number, viewName: string, rootTag: number, props: Object, ) => void; - updateView: (reactTag: number, viewName: string, props: Object) => void; - manageChildren: ( + +updateView: (reactTag: number, viewName: string, props: Object) => void; + +manageChildren: ( containerTag: ?number, moveFromIndices: Array, moveToIndices: Array, diff --git a/Libraries/ReactNative/UIManagerStatTracker.js b/Libraries/ReactNative/UIManagerStatTracker.js deleted file mode 100644 index 85aaa6ba7707a7..00000000000000 --- a/Libraries/ReactNative/UIManagerStatTracker.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow strict-local - * @format - */ -'use strict'; - -const UIManager = require('./UIManager'); - -let installed = false; -const UIManagerStatTracker = { - install: function() { - if (installed) { - return; - } - installed = true; - let statLogHandle; - const stats = {}; - function printStats() { - console.log({UIManagerStatTracker: stats}); - statLogHandle = null; - } - function incStat(key: string, increment: number) { - stats[key] = (stats[key] || 0) + increment; - if (!statLogHandle) { - statLogHandle = setImmediate(printStats); - } - } - const createViewOrig = UIManager.createView; - UIManager.createView = function(tag, className, rootTag, props) { - incStat('createView', 1); - incStat('setProp', Object.keys(props || []).length); - createViewOrig(tag, className, rootTag, props); - }; - const updateViewOrig = UIManager.updateView; - UIManager.updateView = function(tag, className, props) { - incStat('updateView', 1); - incStat('setProp', Object.keys(props || []).length); - updateViewOrig(tag, className, props); - }; - const manageChildrenOrig = UIManager.manageChildren; - UIManager.manageChildren = function( - tag, - moveFrom, - moveTo, - addTags, - addIndices, - remove, - ) { - incStat('manageChildren', 1); - incStat('move', moveFrom.length); - incStat('remove', remove.length); - manageChildrenOrig(tag, moveFrom, moveTo, addTags, addIndices, remove); - }; - }, -}; - -module.exports = UIManagerStatTracker; From 2d937c63e4b25bcbf69a44937ae22beda6613361 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:24:49 -0700 Subject: [PATCH 0007/1244] Add recursive types for Object types Summary: We weren't adding the local imports recursively as well. This is a similar change as was made when creating the CppHelpers.getImports in D16759170. Reviewed By: rickhanlonii, JoshuaGross Differential Revision: D16840667 fbshipit-source-id: 1090a774c9e96798d5900bc0b4bf1be29b3ba090 --- .../generators/components/GeneratePropsH.js | 28 +++++++++++++++---- .../__snapshots__/GeneratePropsH-test.js.snap | 4 +++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 4312a63e4a7eb8..1462ce882acd05 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -17,7 +17,11 @@ const { getImports, } = require('./CppHelpers.js'); -import type {PropTypeShape, SchemaType} from '../../CodegenSchema'; +import type { + ExtendsPropsShape, + PropTypeShape, + SchemaType, +} from '../../CodegenSchema'; // File path -> contents type FilesOutput = Map; @@ -420,10 +424,12 @@ function generatePropsString( .join('\n' + ' '); } -function getLocalImports(component): Set { +function getExtendsImports( + extendsProps: $ReadOnlyArray, +): Set { const imports: Set = new Set(); - component.extendsProps.forEach(extendProps => { + extendsProps.forEach(extendProps => { switch (extendProps.type) { case 'ReactNativeBuiltInType': switch (extendProps.knownTypeName) { @@ -440,6 +446,14 @@ function getLocalImports(component): Set { } }); + return imports; +} + +function getLocalImports( + properties: $ReadOnlyArray, +): Set { + const imports: Set = new Set(); + function addImportsForNativeName(name) { switch (name) { case 'ColorPrimitive': @@ -459,7 +473,7 @@ function getLocalImports(component): Set { } } - component.props.forEach(prop => { + properties.forEach(prop => { const typeAnnotation = prop.typeAnnotation; if (typeAnnotation.type === 'NativePrimitiveTypeAnnotation') { @@ -483,7 +497,9 @@ function getLocalImports(component): Set { if (typeAnnotation.type === 'ObjectTypeAnnotation') { imports.add('#include '); const objectImports = getImports(typeAnnotation.properties); + const localImports = getLocalImports(typeAnnotation.properties); objectImports.forEach(imports.add, imports); + localImports.forEach(imports.add, imports); } }); @@ -631,8 +647,10 @@ module.exports = { component.props, ); const extendString = getClassExtendString(component); - const imports = getLocalImports(component); + const extendsImports = getExtendsImports(component.extendsProps); + const imports = getLocalImports(component.props); + extendsImports.forEach(allImports.add, allImports); imports.forEach(allImports.add, allImports); const replacedTemplate = classTemplate diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index fd790ab50d5b55..67dd0c601fa4ab 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -658,6 +658,10 @@ Map { #include #include #include +#include +#include +#include +#include namespace facebook { namespace react { From 6ee56795820acab51805441fb3fc654312b883b2 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:24:49 -0700 Subject: [PATCH 0008/1244] Add Fixture for Array with Primitives Summary: The codegen has a bug with arrays that have objects that contain native primitives. This diff adds a fixture to demonstrate that bug. I don't change any behavior in this diff. This is just to make the change in the next diff easier to read. Reviewed By: JoshuaGross Differential Revision: D16846290 fbshipit-source-id: 06f477b9e3b77cbc1faee11c78d031b45c094d31 --- .../components/__test_fixtures__/fixtures.js | 67 ++++++++++++++++++ .../GenerateComponentDescriptorH-test.js.snap | 26 +++++++ .../GenerateComponentHObjCpp-test.js.snap | 23 +++++++ .../GenerateEventEmitterCpp-test.js.snap | 23 +++++++ .../GenerateEventEmitterH-test.js.snap | 24 +++++++ .../GeneratePropsCpp-test.js.snap | 29 ++++++++ .../__snapshots__/GeneratePropsH-test.js.snap | 69 +++++++++++++++++++ .../GeneratePropsJavaDelegate-test.js.snap | 31 +++++++++ .../GeneratePropsJavaInterface-test.js.snap | 16 +++++ .../GenerateShadowNodeCpp-test.js.snap | 23 +++++++ .../GenerateShadowNodeH-test.js.snap | 33 +++++++++ .../__snapshots__/GenerateTests-test.js.snap | 28 ++++++++ .../GenerateViewConfigJs-test.js.snap | 35 ++++++++++ 13 files changed, 427 insertions(+) diff --git a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js index ce824990eb60d1..3783b8ee2fa884 100644 --- a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js @@ -612,6 +612,72 @@ const ARRAY_PROPS: SchemaType = { }, }; +const ARRAY_PROPS_WITH_NESTED_OBJECT: SchemaType = { + modules: { + Slider: { + components: { + ArrayPropsNativeComponent: { + extendsProps: [ + { + type: 'ReactNativeBuiltInType', + knownTypeName: 'ReactNativeCoreViewProps', + }, + ], + events: [], + props: [ + { + name: 'nativePrimitives', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'colors', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'ColorPrimitive', + }, + }, + }, + { + name: 'srcs', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'ImageSourcePrimitive', + }, + }, + }, + { + name: 'points', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'NativePrimitiveTypeAnnotation', + name: 'PointPrimitive', + }, + }, + }, + ], + }, + }, + }, + ], + commands: [], + }, + }, + }, + }, +}; + const OBJECT_PROPS: SchemaType = { modules: { ObjectPropsNativeComponent: { @@ -1254,6 +1320,7 @@ module.exports = { IMAGE_PROP, POINT_PROP, ARRAY_PROPS, + ARRAY_PROPS_WITH_NESTED_OBJECT, OBJECT_PROPS, MULTI_NATIVE_PROP, ENUM_PROP, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentDescriptorH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentDescriptorH-test.js.snap index efbb916a117c52..839f67d4fec81c 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentDescriptorH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentDescriptorH-test.js.snap @@ -26,6 +26,32 @@ using ArrayPropsNativeComponentComponentDescriptor = ConcreteComponentDescriptor } `; +exports[`GenerateComponentDescriptorH can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "ComponentDescriptors.h" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +using ArrayPropsNativeComponentComponentDescriptor = ConcreteComponentDescriptor; + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GenerateComponentDescriptorH can generate fixture BOOLEAN_PROP 1`] = ` Map { "ComponentDescriptors.h" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentHObjCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentHObjCpp-test.js.snap index 63244336cf3789..b7533f3d2678e9 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentHObjCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateComponentHObjCpp-test.js.snap @@ -23,6 +23,29 @@ NS_ASSUME_NONNULL_END", } `; +exports[`GenerateComponentHObjCpp can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "RCTComponentViewHelpers.h" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol RCTArrayPropsNativeComponentViewProtocol + +@end + +NS_ASSUME_NONNULL_END", +} +`; + exports[`GenerateComponentHObjCpp can generate fixture BOOLEAN_PROP 1`] = ` Map { "RCTComponentViewHelpers.h" => "/** diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap index 3ab1646e61f816..2b31ca86cac878 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterCpp-test.js.snap @@ -17,6 +17,29 @@ namespace react { +} // namespace react +} // namespace facebook +", +} +`; + +exports[`GenerateEventEmitterCpp can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "EventEmitters.cpp" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +namespace facebook { +namespace react { + + + } // namespace react } // namespace facebook ", diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap index f8f8f28e9b78d5..d1ab6358079494 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateEventEmitterH-test.js.snap @@ -18,6 +18,30 @@ namespace react { +} // namespace react +} // namespace facebook +", +} +`; + +exports[`GenerateEventEmitterH can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "EventEmitters.h" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +#include + +namespace facebook { +namespace react { + + + } // namespace react } // namespace facebook ", diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap index ebe2c9dc604a73..04ee681f63227d 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap @@ -38,6 +38,35 @@ ArrayPropsNativeComponentProps::ArrayPropsNativeComponentProps( } `; +exports[`GeneratePropsCpp can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "Props.cpp" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +namespace facebook { +namespace react { + +ArrayPropsNativeComponentProps::ArrayPropsNativeComponentProps( + const ArrayPropsNativeComponentProps &sourceProps, + const RawProps &rawProps): ViewProps(sourceProps, rawProps), + + nativePrimitives(convertRawProp(rawProps, \\"nativePrimitives\\", sourceProps.nativePrimitives, nativePrimitives)) + {} + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GeneratePropsCpp can generate fixture BOOLEAN_PROP 1`] = ` Map { "Props.cpp" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 67dd0c601fa4ab..cbee2a92661286 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -126,6 +126,75 @@ class ArrayPropsNativeComponentProps final : public ViewProps { } `; +exports[`GeneratePropsH can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "Props.h" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +struct ArrayPropsNativeComponentNativePrimitivesStruct { + std::vector colors; + std::vector srcs; + std::vector points; +}; + +static inline void fromRawValue(const RawValue &value, ArrayPropsNativeComponentNativePrimitivesStruct &result) { + auto map = (better::map)value; + + auto colors = map.find(\\"colors\\"); + if (colors != map.end()) { + fromRawValue(colors->second, result.colors); + } + auto srcs = map.find(\\"srcs\\"); + if (srcs != map.end()) { + fromRawValue(srcs->second, result.srcs); + } + auto points = map.find(\\"points\\"); + if (points != map.end()) { + fromRawValue(points->second, result.points); + } +} + +static inline std::string toString(const ArrayPropsNativeComponentNativePrimitivesStruct &value) { + return \\"[Object ArrayPropsNativeComponentNativePrimitivesStruct]\\"; +} + +static inline void fromRawValue(const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + ArrayPropsNativeComponentNativePrimitivesStruct newItem; + fromRawValue(item, newItem); + result.emplace_back(newItem); + } +} + +class ArrayPropsNativeComponentProps final : public ViewProps { + public: + ArrayPropsNativeComponentProps() = default; + ArrayPropsNativeComponentProps(const ArrayPropsNativeComponentProps &sourceProps, const RawProps &rawProps); + +#pragma mark - Props + + const std::vector nativePrimitives{}; +}; + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GeneratePropsH can generate fixture BOOLEAN_PROP 1`] = ` Map { "Props.h" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap index 0ec550484a3fde..2155770c410d84 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap @@ -55,6 +55,37 @@ public class ArrayPropsNativeComponentManagerDelegate " +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class ArrayPropsNativeComponentManagerDelegate & ArrayPropsNativeComponentManagerInterface> extends BaseViewManagerDelegate { + public ArrayPropsNativeComponentManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case \\"nativePrimitives\\": + mViewManager.setNativePrimitives(view, (ReadableArray) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} +", +} +`; + exports[`GeneratePropsJavaDelegate can generate fixture BOOLEAN_PROP 1`] = ` Map { "BooleanPropNativeComponentManagerDelegate.java" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap index 5086a60f71386b..9db234c73dd5f4 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap @@ -24,6 +24,22 @@ public interface ArrayPropsNativeComponentManagerInterface { } `; +exports[`GeneratePropsJavaInterface can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "ArrayPropsNativeComponentManagerInterface.java" => " +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; + +public interface ArrayPropsNativeComponentManagerInterface { + void setNativePrimitives(T view, @Nullable ReadableArray value); +} +", +} +`; + exports[`GeneratePropsJavaInterface can generate fixture BOOLEAN_PROP 1`] = ` Map { "BooleanPropNativeComponentManagerInterface.java" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeCpp-test.js.snap index fc8a56a468af6d..f0de514d50210e 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeCpp-test.js.snap @@ -23,6 +23,29 @@ extern const char ArrayPropsNativeComponentComponentName[] = \\"ArrayPropsNative } `; +exports[`GenerateShadowNodeCpp can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "ShadowNodes.cpp" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +namespace facebook { +namespace react { + +extern const char ArrayPropsNativeComponentComponentName[] = \\"ArrayPropsNativeComponent\\"; + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GenerateShadowNodeCpp can generate fixture BOOLEAN_PROP 1`] = ` Map { "ShadowNodes.cpp" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeH-test.js.snap index 97e18f65ea198b..fdac199168327d 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateShadowNodeH-test.js.snap @@ -33,6 +33,39 @@ using ArrayPropsNativeComponentShadowNode = ConcreteViewShadowNode< } `; +exports[`GenerateShadowNodeH can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "ShadowNodes.h" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace react { + +extern const char ArrayPropsNativeComponentComponentName[]; + +/* + * \`ShadowNode\` for component. + */ +using ArrayPropsNativeComponentShadowNode = ConcreteViewShadowNode< + ArrayPropsNativeComponentComponentName, + ArrayPropsNativeComponentProps>; + +} // namespace react +} // namespace facebook +", +} +`; + exports[`GenerateShadowNodeH can generate fixture BOOLEAN_PROP 1`] = ` Map { "ShadowNodes.h" => " diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap index 7f3ef3a72b8b41..8ad7f402c12aa5 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateTests-test.js.snap @@ -29,6 +29,34 @@ TEST(ArrayPropsNativeComponentProps_DoesNotDie, etc) { } `; +exports[`GenerateTests can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "Tests.cpp" => "/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include +#include + +using namespace facebook::react; + +TEST(ArrayPropsNativeComponentProps_DoesNotDie, etc) { + auto propParser = RawPropsParser(); + propParser.prepare(); + auto const &sourceProps = ArrayPropsNativeComponentProps(); + auto const &rawProps = RawProps(folly::dynamic::object(\\"xx_invalid_xx\\", \\"xx_invalid_xx\\")); + rawProps.parse(propParser); + ArrayPropsNativeComponentProps(sourceProps, rawProps); +}", +} +`; + exports[`GenerateTests can generate fixture BOOLEAN_PROP 1`] = ` Map { "Tests.cpp" => "/** diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 4af7b4a7f174c2..2e6f84a7828215 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -43,6 +43,41 @@ export default nativeComponentName; } `; +exports[`GenerateViewConfigJs can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` +Map { + "ARRAY_PROPS_WITH_NESTED_OBJECTNativeViewConfig.js" => " +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +'use strict'; + +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); + +const ArrayPropsNativeComponentViewConfig = { + uiViewClassName: 'ArrayPropsNativeComponent', + + validAttributes: { + nativePrimitives: true, + }, +}; + +let nativeComponentName = 'ArrayPropsNativeComponent'; + +registerGeneratedViewConfig(nativeComponentName, ArrayPropsNativeComponentViewConfig); + +export const __INTERNAL_VIEW_CONFIG = ArrayPropsNativeComponentViewConfig; + +export default nativeComponentName; +", +} +`; + exports[`GenerateViewConfigJs can generate fixture BOOLEAN_PROP 1`] = ` Map { "BOOLEAN_PROPNativeViewConfig.js" => " From 685a25ca2ea5bfeeaef9802fd031e8a972561811 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:24:49 -0700 Subject: [PATCH 0009/1244] Add recursive imports for Array types Summary: Supporting the native primitives fixture added in the previous diff Reviewed By: JoshuaGross Differential Revision: D16846289 fbshipit-source-id: 4c6afdabba0fe4b55990d25adec21cf65d8beff3 --- .../src/generators/components/GeneratePropsH.js | 10 ++++++++++ .../__snapshots__/GeneratePropsH-test.js.snap | 3 +++ 2 files changed, 13 insertions(+) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 1462ce882acd05..5c81d8ee6a80b0 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -494,6 +494,16 @@ function getLocalImports( addImportsForNativeName(typeAnnotation.elementType.name); } + if ( + typeAnnotation.type === 'ArrayTypeAnnotation' && + typeAnnotation.elementType.type === 'ObjectTypeAnnotation' + ) { + const localImports = getLocalImports( + typeAnnotation.elementType.properties, + ); + localImports.forEach(imports.add, imports); + } + if (typeAnnotation.type === 'ObjectTypeAnnotation') { imports.add('#include '); const objectImports = getImports(typeAnnotation.properties); diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index cbee2a92661286..b804dfd2cb10b7 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -138,6 +138,9 @@ Map { #pragma once #include +#include +#include +#include #include namespace facebook { From e9ef560e87eda386396f540c8a15c48fbb263e3b Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:24:49 -0700 Subject: [PATCH 0010/1244] Add fixture for nested objects Summary: Adding this fixture in a standalone diff so it is easier to see the change on the next one. Reviewed By: JoshuaGross Differential Revision: D16852439 fbshipit-source-id: 3f167509b78ebb95f31e44fbf40e9551d4a5500b --- .../components/__test_fixtures__/fixtures.js | 26 +++++++++++++ .../__snapshots__/GeneratePropsH-test.js.snap | 39 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js index 3783b8ee2fa884..7b57d4449a3224 100644 --- a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js @@ -794,6 +794,32 @@ const OBJECT_PROPS: SchemaType = { ], }, }, + { + name: 'nestedPropA', + optional: false, + typeAnnotation: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'nestedPropB', + optional: false, + typeAnnotation: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'nestedPropC', + optional: true, + typeAnnotation: { + type: 'StringTypeAnnotation', + default: '', + }, + }, + ], + }, + }, + ], + }, + }, ], }, }, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index b804dfd2cb10b7..c23e155d1f7bee 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -795,6 +795,40 @@ static inline std::string toString(const ObjectPropsObjectPropObjectPrimitiveReq return \\"[Object ObjectPropsObjectPropObjectPrimitiveRequiredPropStruct]\\"; } +struct ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct { + std::string stringProp; +}; + +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct &result) { + auto map = (better::map)value; + + auto stringProp = map.find(\\"stringProp\\"); + if (stringProp != map.end()) { + fromRawValue(stringProp->second, result.stringProp); + } +} + +static inline std::string toString(const ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct]\\"; +} + +struct ObjectPropsObjectPropNestedObjectPropStruct { + ObjectPropsNestedObjectInObjectPropStruct nestedObjectInObjectProp; +}; + +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedObjectPropStruct &result) { + auto map = (better::map)value; + + auto nestedObjectInObjectProp = map.find(\\"nestedObjectInObjectProp\\"); + if (nestedObjectInObjectProp != map.end()) { + fromRawValue(nestedObjectInObjectProp->second, result.nestedObjectInObjectProp); + } +} + +static inline std::string toString(const ObjectPropsObjectPropNestedObjectPropStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedObjectPropStruct]\\"; +} + struct ObjectPropsObjectPropStruct { std::string stringProp; bool booleanProp; @@ -803,6 +837,7 @@ struct ObjectPropsObjectPropStruct { ObjectPropsStringEnumProp stringEnumProp; ObjectPropsObjectArrayPropStruct objectArrayProp; ObjectPropsObjectPrimitiveRequiredPropStruct objectPrimitiveRequiredProp; + ObjectPropsNestedObjectPropStruct nestedObjectProp; }; static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStruct &result) { @@ -836,6 +871,10 @@ static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStru if (objectPrimitiveRequiredProp != map.end()) { fromRawValue(objectPrimitiveRequiredProp->second, result.objectPrimitiveRequiredProp); } + auto nestedObjectProp = map.find(\\"nestedObjectProp\\"); + if (nestedObjectProp != map.end()) { + fromRawValue(nestedObjectProp->second, result.nestedObjectProp); + } } static inline std::string toString(const ObjectPropsObjectPropStruct &value) { From b9899222a3f43fcdf84087529916ca9844a4583f Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:24:49 -0700 Subject: [PATCH 0011/1244] Fix naming of nested structs Summary: The names weren't matching and c++ wasn't compiling Reviewed By: rickhanlonii, JoshuaGross Differential Revision: D16852438 fbshipit-source-id: 9fa72aaec4e3071232b026ff99ba632a0834d50e --- .../generators/components/GeneratePropsH.js | 29 ++++++++---- .../__snapshots__/GeneratePropsH-test.js.snap | 44 +++++++++---------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 5c81d8ee6a80b0..b78ce425ca609d 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -171,7 +171,11 @@ function getClassExtendString(component): string { return extendString; } -function getNativeTypeFromAnnotation(componentName: string, prop): string { +function getNativeTypeFromAnnotation( + componentName: string, + prop, + nameParts: $ReadOnlyArray, +): string { const typeAnnotation = prop.typeAnnotation; switch (typeAnnotation.type) { @@ -200,21 +204,28 @@ function getNativeTypeFromAnnotation(componentName: string, prop): string { ); } if (typeAnnotation.elementType.type === 'ObjectTypeAnnotation') { - const structName = generateStructName(componentName, [prop.name]); + const structName = generateStructName( + componentName, + nameParts.concat([prop.name]), + ); return `std::vector<${structName}>`; } if (typeAnnotation.elementType.type === 'StringEnumTypeAnnotation') { const enumName = getEnumName(componentName, prop.name); return getEnumMaskName(enumName); } - const itemAnnotation = getNativeTypeFromAnnotation(componentName, { - typeAnnotation: typeAnnotation.elementType, - name: componentName, - }); + const itemAnnotation = getNativeTypeFromAnnotation( + componentName, + { + typeAnnotation: typeAnnotation.elementType, + name: componentName, + }, + nameParts, + ); return `std::vector<${itemAnnotation}>`; } case 'ObjectTypeAnnotation': { - return generateStructName(componentName, [prop.name]); + return generateStructName(componentName, nameParts.concat([prop.name])); } case 'StringEnumTypeAnnotation': return getEnumName(componentName, prop.name); @@ -416,7 +427,7 @@ function generatePropsString( ) { return props .map(prop => { - const nativeType = getNativeTypeFromAnnotation(componentName, prop); + const nativeType = getNativeTypeFromAnnotation(componentName, prop, []); const defaultValue = convertDefaultTypeToString(componentName, prop); return `const ${nativeType} ${prop.name}{${defaultValue}};`; @@ -563,7 +574,7 @@ function generateStruct( return `${getNativeTypeFromAnnotation( componentName, property, - // structNameParts, + structNameParts, )} ${property.name};`; }) .join('\n' + ' '); diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index c23e155d1f7bee..c3bdb753ffff67 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -795,38 +795,38 @@ static inline std::string toString(const ObjectPropsObjectPropObjectPrimitiveReq return \\"[Object ObjectPropsObjectPropObjectPrimitiveRequiredPropStruct]\\"; } -struct ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct { - std::string stringProp; +struct ObjectPropsObjectPropNestedPropANestedPropBStruct { + std::string nestedPropC; }; -static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct &result) { +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedPropANestedPropBStruct &result) { auto map = (better::map)value; - auto stringProp = map.find(\\"stringProp\\"); - if (stringProp != map.end()) { - fromRawValue(stringProp->second, result.stringProp); + auto nestedPropC = map.find(\\"nestedPropC\\"); + if (nestedPropC != map.end()) { + fromRawValue(nestedPropC->second, result.nestedPropC); } } -static inline std::string toString(const ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct &value) { - return \\"[Object ObjectPropsObjectPropNestedObjectPropNestedObjectInObjectPropStruct]\\"; +static inline std::string toString(const ObjectPropsObjectPropNestedPropANestedPropBStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedPropANestedPropBStruct]\\"; } -struct ObjectPropsObjectPropNestedObjectPropStruct { - ObjectPropsNestedObjectInObjectPropStruct nestedObjectInObjectProp; +struct ObjectPropsObjectPropNestedPropAStruct { + ObjectPropsObjectPropNestedPropANestedPropBStruct nestedPropB; }; -static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedObjectPropStruct &result) { +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedPropAStruct &result) { auto map = (better::map)value; - auto nestedObjectInObjectProp = map.find(\\"nestedObjectInObjectProp\\"); - if (nestedObjectInObjectProp != map.end()) { - fromRawValue(nestedObjectInObjectProp->second, result.nestedObjectInObjectProp); + auto nestedPropB = map.find(\\"nestedPropB\\"); + if (nestedPropB != map.end()) { + fromRawValue(nestedPropB->second, result.nestedPropB); } } -static inline std::string toString(const ObjectPropsObjectPropNestedObjectPropStruct &value) { - return \\"[Object ObjectPropsObjectPropNestedObjectPropStruct]\\"; +static inline std::string toString(const ObjectPropsObjectPropNestedPropAStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedPropAStruct]\\"; } struct ObjectPropsObjectPropStruct { @@ -835,9 +835,9 @@ struct ObjectPropsObjectPropStruct { Float floatProp; int intProp; ObjectPropsStringEnumProp stringEnumProp; - ObjectPropsObjectArrayPropStruct objectArrayProp; - ObjectPropsObjectPrimitiveRequiredPropStruct objectPrimitiveRequiredProp; - ObjectPropsNestedObjectPropStruct nestedObjectProp; + ObjectPropsObjectPropObjectArrayPropStruct objectArrayProp; + ObjectPropsObjectPropObjectPrimitiveRequiredPropStruct objectPrimitiveRequiredProp; + ObjectPropsObjectPropNestedPropAStruct nestedPropA; }; static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStruct &result) { @@ -871,9 +871,9 @@ static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStru if (objectPrimitiveRequiredProp != map.end()) { fromRawValue(objectPrimitiveRequiredProp->second, result.objectPrimitiveRequiredProp); } - auto nestedObjectProp = map.find(\\"nestedObjectProp\\"); - if (nestedObjectProp != map.end()) { - fromRawValue(nestedObjectProp->second, result.nestedObjectProp); + auto nestedPropA = map.find(\\"nestedPropA\\"); + if (nestedPropA != map.end()) { + fromRawValue(nestedPropA->second, result.nestedPropA); } } From cddc2c6c72a3d6dc5cfe46d16fafa55a81b8f644 Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:51:28 -0700 Subject: [PATCH 0012/1244] Fix Java compile errors in JS-generated receiveCommand method Summary: This diff adds a missing `switch` statement Reviewed By: makovkastar Differential Revision: D16892042 fbshipit-source-id: c162655445f3c0891d2377595a9389d419713bdf --- .../components/GeneratePropsJavaDelegate.js | 16 ++++++++------ .../GeneratePropsJavaDelegate-test.js.snap | 22 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js index efd48a1ff43ffb..ba673373e3c89c 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js @@ -43,7 +43,9 @@ const propSetterTemplate = ` const commandsTemplate = ` public void receiveCommand(::_INTERFACE_CLASSNAME_:: viewManager, T view, String commandName, ReadableArray args) { - ::_COMMAND_CASES_:: + switch (commandName) { + ::_COMMAND_CASES_:: + } } `; @@ -173,13 +175,13 @@ function generateCommandCasesString( const commandMethods = component.commands .map(command => { return `case "${command.name}": - viewManager.${toSafeJavaString( - command.name, - false, - )}(${getCommandArguments(command)}); - break;`; + viewManager.${toSafeJavaString( + command.name, + false, + )}(${getCommandArguments(command)}); + break;`; }) - .join('\n' + ' '); + .join('\n' + ' '); return commandMethods; } diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap index 2155770c410d84..6cb2a998962f72 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap @@ -168,12 +168,14 @@ public class CommandNativeComponentManagerDelegate viewManager, T view, String commandName, ReadableArray args) { - case \\"flashScrollIndicators\\": - viewManager.flashScrollIndicators(view); - break; - case \\"allTypes\\": - viewManager.allTypes(view, args.getInt(0), args.getFloat(1), args.getDouble(2), args.getString(3), args.getBoolean(4)); - break; + switch (commandName) { + case \\"flashScrollIndicators\\": + viewManager.flashScrollIndicators(view); + break; + case \\"allTypes\\": + viewManager.allTypes(view, args.getInt(0), args.getFloat(1), args.getDouble(2), args.getString(3), args.getBoolean(4)); + break; + } } } ", @@ -208,9 +210,11 @@ public class CommandNativeComponentManagerDelegate viewManager, T view, String commandName, ReadableArray args) { - case \\"hotspotUpdate\\": - viewManager.hotspotUpdate(view, args.getInt(0), args.getInt(1)); - break; + switch (commandName) { + case \\"hotspotUpdate\\": + viewManager.hotspotUpdate(view, args.getInt(0), args.getInt(1)); + break; + } } } ", From 0df5e5016da73c1d32ae73739e6669b06d399c0c Mon Sep 17 00:00:00 2001 From: Eli White Date: Mon, 19 Aug 2019 11:51:28 -0700 Subject: [PATCH 0013/1244] Cast double to float instead of .getFloat Summary: ReadableArray doesn't have a .getFloat, so casting double to floats instead. This is consistent with how the prop conversion happens as well. Reviewed By: makovkastar Differential Revision: D16897600 fbshipit-source-id: e8c76558f030d291960b5790a262fa49a9f358e7 --- .../components/GeneratePropsJavaDelegate.js | 18 +++++++----------- .../GeneratePropsJavaDelegate-test.js.snap | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js index ba673373e3c89c..9a902d0aa022f9 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js @@ -135,18 +135,18 @@ function generatePropCasesString( }`; } -function getCommandArgJavaType(param) { +function getCommandArgJavaType(param, index) { switch (param.typeAnnotation.type) { case 'BooleanTypeAnnotation': - return 'getBoolean'; + return `args.getBoolean(${index})`; case 'DoubleTypeAnnotation': - return 'getDouble'; + return `args.getDouble(${index})`; case 'FloatTypeAnnotation': - return 'getFloat'; + return `(float) args.getDouble(${index})`; case 'Int32TypeAnnotation': - return 'getInt'; + return `args.getInt(${index})`; case 'StringTypeAnnotation': - return 'getString'; + return `args.getString(${index})`; default: (param.typeAnnotation.type: empty); throw new Error('Receieved invalid typeAnnotation'); @@ -156,11 +156,7 @@ function getCommandArgJavaType(param) { function getCommandArguments(command: CommandTypeShape): string { return [ 'view', - ...command.typeAnnotation.params.map((param, index) => { - const commandArgJavaType = getCommandArgJavaType(param); - - return `args.${commandArgJavaType}(${index})`; - }), + ...command.typeAnnotation.params.map(getCommandArgJavaType), ].join(', '); } diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap index 6cb2a998962f72..39bab1b8a79862 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap @@ -173,7 +173,7 @@ public class CommandNativeComponentManagerDelegate Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0014/1244] Add new parser fixture for nested array objects Summary: This diff adds parser fixtures for nested array objects Reviewed By: TheSavior Differential Revision: D16858619 fbshipit-source-id: 22ce2f4c37c62032c768e149e8a1527df52857cd --- .../components/__test_fixtures__/fixtures.js | 26 ++++ .../component-parser-test.js.snap | 128 ++++++++++++++++++ 2 files changed, 154 insertions(+) diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js index 4482becedf1d91..6fae6b4a2138b6 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js @@ -367,6 +367,32 @@ type ModuleProps = $ReadOnly<{| array_object_optional_key?: $ReadOnlyArray<$ReadOnly<{| prop: string |}>>, array_object_optional_value: ?ArrayObjectType, array_object_optional_both?: ?$ReadOnlyArray, + + // Nested array object types + array_of_array_object_required: $ReadOnlyArray< + $ReadOnly<{| + // This needs to be the same name as the top level array above + array_object_required: $ReadOnlyArray<$ReadOnly<{| prop: string |}>>, + |}> + >, + array_of_array_object_optional_key?: $ReadOnlyArray< + $ReadOnly<{| + // This needs to be the same name as the top level array above + array_object_optional_key: $ReadOnlyArray<$ReadOnly<{| prop?: string |}>>, + |}> + >, + array_of_array_object_optional_value: ?$ReadOnlyArray< + $ReadOnly<{| + // This needs to be the same name as the top level array above + array_object_optional_value: $ReadOnlyArray<$ReadOnly<{| prop: ?string |}>>, + |}> + >, + array_of_array_object_optional_both?: ?$ReadOnlyArray< + $ReadOnly<{| + // This needs to be the same name as the top level array above + array_object_optional_both: $ReadOnlyArray<$ReadOnly<{| prop?: ?string |}>>, + |}> + >, |}>; export default (codegenNativeComponent( diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index 2f792c2295307f..958a44b947e8a2 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -901,6 +901,134 @@ Object { "type": "ArrayTypeAnnotation", }, }, + Object { + "name": "array_of_array_object_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "array_object_required", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "prop", + "optional": false, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_of_array_object_optional_key", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "array_object_optional_key", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "prop", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_of_array_object_optional_value", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "array_object_optional_value", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "prop", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + Object { + "name": "array_of_array_object_optional_both", + "optional": true, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "array_object_optional_both", + "optional": false, + "typeAnnotation": Object { + "elementType": Object { + "properties": Array [ + Object { + "name": "prop", + "optional": true, + "typeAnnotation": Object { + "default": null, + "type": "StringTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, + ], + "type": "ObjectTypeAnnotation", + }, + "type": "ArrayTypeAnnotation", + }, + }, ], }, }, From 8c995a2a0dd13933c7572ffea12826809f69bbd3 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0015/1244] Add broken generator fixtures for nested array props Summary: Adds a fixture for generating nested array objects (fix is on the next diff) Reviewed By: TheSavior Differential Revision: D16858626 fbshipit-source-id: c9543f4f8ecc073fd840edd94d47bdc911eaa69e --- .../components/__test_fixtures__/fixtures.js | 35 +++++++++++++++++++ .../GeneratePropsCpp-test.js.snap | 3 +- .../__snapshots__/GeneratePropsH-test.js.snap | 5 +-- .../GeneratePropsJavaDelegate-test.js.snap | 3 ++ .../GeneratePropsJavaInterface-test.js.snap | 1 + .../GenerateViewConfigJs-test.js.snap | 1 + 6 files changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js index 7b57d4449a3224..f231f7abf4012b 100644 --- a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js @@ -604,6 +604,41 @@ const ARRAY_PROPS: SchemaType = { }, }, }, + { + name: 'array', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ObjectTypeAnnotation', + properties: [ + { + // This needs to stay the same as the object above + // to confirm that the structs are generated + // with unique non-colliding names + name: 'object', + optional: true, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'stringProp', + optional: true, + typeAnnotation: { + type: 'StringTypeAnnotation', + default: '', + }, + }, + ], + }, + }, + }, + ], + }, + }, + }, ], commands: [], }, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap index 04ee681f63227d..4f81abf1dda663 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap @@ -29,7 +29,8 @@ ArrayPropsNativeComponentProps::ArrayPropsNativeComponentProps( srcs(convertRawProp(rawProps, \\"srcs\\", sourceProps.srcs, srcs)), points(convertRawProp(rawProps, \\"points\\", sourceProps.points, points)), sizes(convertRawProp(rawProps, \\"sizes\\", sourceProps.sizes, sizes)), - object(convertRawProp(rawProps, \\"object\\", sourceProps.object, object)) + object(convertRawProp(rawProps, \\"object\\", sourceProps.object, object)), + array(convertRawProp(rawProps, \\"array\\", sourceProps.array, array)) {} } // namespace react diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index c3bdb753ffff67..b7d96787ade306 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -93,10 +93,10 @@ static inline std::string toString(const ArrayPropsNativeComponentObjectStruct & return \\"[Object ArrayPropsNativeComponentObjectStruct]\\"; } -static inline void fromRawValue(const RawValue &value, std::vector &result) { +static inline void fromRawValue(const RawValue &value, std::vector &result) { auto items = (std::vector)value; for (const auto &item : items) { - ArrayPropsNativeComponentObjectStruct newItem; + ArrayPropsNativeComponentArrayStruct newItem; fromRawValue(item, newItem); result.emplace_back(newItem); } @@ -118,6 +118,7 @@ class ArrayPropsNativeComponentProps final : public ViewProps { const std::vector points{}; const ArrayPropsNativeComponentSizesMask sizes{static_cast(ArrayPropsNativeComponentSizes::Small)}; const std::vector object{}; + const std::vector array{}; }; } // namespace react diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap index 39bab1b8a79862..1e55210288591b 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap @@ -46,6 +46,9 @@ public class ArrayPropsNativeComponentManagerDelegate { void setPoints(T view, @Nullable ReadableArray value); void setSizes(T view, @Nullable ReadableArray value); void setObject(T view, @Nullable ReadableArray value); + void setArray(T view, @Nullable ReadableArray value); } ", } diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap index 2e6f84a7828215..cd999e23f4ff88 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GenerateViewConfigJs-test.js.snap @@ -29,6 +29,7 @@ const ArrayPropsNativeComponentViewConfig = { points: true, sizes: true, object: true, + array: true, }, }; From 3050ac2d2d926dc13e84b589912cda9cc5754871 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0016/1244] Fix nested array object structs Summary: Fixes some issues with generating deeply nested objects and arrays Reviewed By: TheSavior Differential Revision: D16858639 fbshipit-source-id: f9ca90da4fcef7f4fe795b38888c66ffef45c06b --- .../generators/components/GeneratePropsH.js | 71 ++++++++++++++----- .../__snapshots__/GeneratePropsH-test.js.snap | 54 ++++++++++++++ 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index b78ce425ca609d..36d679c993d587 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -220,7 +220,7 @@ function getNativeTypeFromAnnotation( typeAnnotation: typeAnnotation.elementType, name: componentName, }, - nameParts, + nameParts.concat([prop.name]), ); return `std::vector<${itemAnnotation}>`; } @@ -527,37 +527,71 @@ function getLocalImports( return imports; } -function generateStructs(componentName: string, component): string { +function generateStructsForComponent(componentName: string, component): string { + const structs = generateStructs(componentName, component.props, []); + const structArray = Array.from(structs.values()); + if (structArray.length < 1) { + return ''; + } + return structArray.join('\n\n'); +} + +function generateStructs( + componentName: string, + properties, + nameParts, +): StructsMap { const structs: StructsMap = new Map(); - component.props.forEach(prop => { - if (prop.typeAnnotation.type === 'ObjectTypeAnnotation') { + properties.forEach(prop => { + const typeAnnotation = prop.typeAnnotation; + if (typeAnnotation.type === 'ObjectTypeAnnotation') { generateStruct( structs, componentName, - [prop.name], - prop.typeAnnotation.properties, + nameParts.concat([prop.name]), + typeAnnotation.properties, ); - } else if ( + } + + if ( prop.typeAnnotation.type === 'ArrayTypeAnnotation' && prop.typeAnnotation.elementType.type === 'ObjectTypeAnnotation' ) { - const properties = prop.typeAnnotation.elementType.properties; - generateStruct(structs, componentName, [prop.name], properties); + // Recursively visit all of the object properties. + // Note: this is depth first so that the nested structs are ordered first. + const elementProperties = prop.typeAnnotation.elementType.properties; + const nestedStructs = generateStructs( + componentName, + elementProperties, + nameParts.concat([prop.name]), + ); + nestedStructs.forEach(function(value, key) { + structs.set(key, value); + }); + + // Generate this struct and its conversion function. + generateStruct( + structs, + componentName, + nameParts.concat([prop.name]), + elementProperties, + ); + + // Generate the conversion function for std:vector. + // Note: This needs to be at the end since it references the struct above. structs.set( - `${componentName}ArrayStruct`, + `${[componentName, ...nameParts.concat([prop.name])].join( + '', + )}ArrayStruct`, arrayConversionFunction.replace( /::_STRUCT_NAME_::/g, - generateStructName(componentName, [prop.name]), + generateStructName(componentName, nameParts.concat([prop.name])), ), ); } }); - const structArray = Array.from(structs.values()); - if (structArray.length < 1) { - return ''; - } - return structArray.join('\n\n'); + return structs; } function generateStruct( @@ -661,7 +695,10 @@ module.exports = { const component = components[componentName]; const newName = `${componentName}Props`; - const structString = generateStructs(componentName, component); + const structString = generateStructsForComponent( + componentName, + component, + ); const enumString = generateEnumString(componentName, component); const propsString = generatePropsString( componentName, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index b7d96787ade306..4adc14e203f635 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -93,6 +93,60 @@ static inline std::string toString(const ArrayPropsNativeComponentObjectStruct & return \\"[Object ArrayPropsNativeComponentObjectStruct]\\"; } +static inline void fromRawValue(const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + ArrayPropsNativeComponentObjectStruct newItem; + fromRawValue(item, newItem); + result.emplace_back(newItem); + } +} + + +struct ArrayPropsNativeComponentArrayObjectStruct { + std::string stringProp; +}; + +static inline void fromRawValue(const RawValue &value, ArrayPropsNativeComponentArrayObjectStruct &result) { + auto map = (better::map)value; + + auto stringProp = map.find(\\"stringProp\\"); + if (stringProp != map.end()) { + fromRawValue(stringProp->second, result.stringProp); + } +} + +static inline std::string toString(const ArrayPropsNativeComponentArrayObjectStruct &value) { + return \\"[Object ArrayPropsNativeComponentArrayObjectStruct]\\"; +} + +static inline void fromRawValue(const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + ArrayPropsNativeComponentArrayObjectStruct newItem; + fromRawValue(item, newItem); + result.emplace_back(newItem); + } +} + + +struct ArrayPropsNativeComponentArrayStruct { + std::vector object; +}; + +static inline void fromRawValue(const RawValue &value, ArrayPropsNativeComponentArrayStruct &result) { + auto map = (better::map)value; + + auto object = map.find(\\"object\\"); + if (object != map.end()) { + fromRawValue(object->second, result.object); + } +} + +static inline std::string toString(const ArrayPropsNativeComponentArrayStruct &value) { + return \\"[Object ArrayPropsNativeComponentArrayStruct]\\"; +} + static inline void fromRawValue(const RawValue &value, std::vector &result) { auto items = (std::vector)value; for (const auto &item : items) { From 5f09a1733b7c67ee9e761f029329a1be9ad808eb Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0017/1244] Add broken fixture for objects with array props Summary: Adds a broken fixture for arrays nested inside of objects (fixed in the next diffs) Reviewed By: TheSavior Differential Revision: D16896138 fbshipit-source-id: 355a71352a78ca076c1de56304908e664772c200 --- .../components/__test_fixtures__/fixtures.js | 29 +++++++++++++++++++ .../__snapshots__/GeneratePropsH-test.js.snap | 22 ++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js index f231f7abf4012b..f4b6c887e8cc87 100644 --- a/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/generators/components/__test_fixtures__/fixtures.js @@ -855,6 +855,35 @@ const OBJECT_PROPS: SchemaType = { ], }, }, + { + name: 'nestedArrayAsProperty', + optional: false, + typeAnnotation: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'arrayProp', + optional: false, + typeAnnotation: { + type: 'ArrayTypeAnnotation', + elementType: { + type: 'ObjectTypeAnnotation', + properties: [ + { + name: 'stringProp', + optional: false, + typeAnnotation: { + type: 'StringTypeAnnotation', + default: '', + }, + }, + ], + }, + }, + }, + ], + }, + }, ], }, }, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 4adc14e203f635..15764742370021 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -884,6 +884,23 @@ static inline std::string toString(const ObjectPropsObjectPropNestedPropAStruct return \\"[Object ObjectPropsObjectPropNestedPropAStruct]\\"; } +struct ObjectPropsObjectPropNestedArrayAsPropertyStruct { + std::vector arrayProp; +}; + +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedArrayAsPropertyStruct &result) { + auto map = (better::map)value; + + auto arrayProp = map.find(\\"arrayProp\\"); + if (arrayProp != map.end()) { + fromRawValue(arrayProp->second, result.arrayProp); + } +} + +static inline std::string toString(const ObjectPropsObjectPropNestedArrayAsPropertyStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedArrayAsPropertyStruct]\\"; +} + struct ObjectPropsObjectPropStruct { std::string stringProp; bool booleanProp; @@ -893,6 +910,7 @@ struct ObjectPropsObjectPropStruct { ObjectPropsObjectPropObjectArrayPropStruct objectArrayProp; ObjectPropsObjectPropObjectPrimitiveRequiredPropStruct objectPrimitiveRequiredProp; ObjectPropsObjectPropNestedPropAStruct nestedPropA; + ObjectPropsObjectPropNestedArrayAsPropertyStruct nestedArrayAsProperty; }; static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStruct &result) { @@ -930,6 +948,10 @@ static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropStru if (nestedPropA != map.end()) { fromRawValue(nestedPropA->second, result.nestedPropA); } + auto nestedArrayAsProperty = map.find(\\"nestedArrayAsProperty\\"); + if (nestedArrayAsProperty != map.end()) { + fromRawValue(nestedArrayAsProperty->second, result.nestedArrayAsProperty); + } } static inline std::string toString(const ObjectPropsObjectPropStruct &value) { From 4bf5e6313893c8eedb361484dd7a564c1a8d0ff1 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0018/1244] Recursively visit all object properties to generate structs Summary: Adds support for generating structs for object properties that are objects or arrays Reviewed By: TheSavior Differential Revision: D16896143 fbshipit-source-id: 6682d047e218fc774c8d0593dc2c66fe73615be7 --- .../generators/components/GeneratePropsH.js | 12 +++++++++ .../__snapshots__/GeneratePropsH-test.js.snap | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 36d679c993d587..50d8c5dce5784f 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -545,6 +545,18 @@ function generateStructs( properties.forEach(prop => { const typeAnnotation = prop.typeAnnotation; if (typeAnnotation.type === 'ObjectTypeAnnotation') { + // Recursively visit all of the object properties. + // Note: this is depth first so that the nested structs are ordered first. + const elementProperties = typeAnnotation.properties; + const nestedStructs = generateStructs( + componentName, + elementProperties, + nameParts.concat([prop.name]), + ); + nestedStructs.forEach(function(value, key) { + structs.set(key, value); + }); + generateStruct( structs, componentName, diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 15764742370021..52ca0874d632e4 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -884,6 +884,33 @@ static inline std::string toString(const ObjectPropsObjectPropNestedPropAStruct return \\"[Object ObjectPropsObjectPropNestedPropAStruct]\\"; } +struct ObjectPropsObjectPropNestedArrayAsPropertyArrayPropStruct { + std::string stringProp; +}; + +static inline void fromRawValue(const RawValue &value, ObjectPropsObjectPropNestedArrayAsPropertyArrayPropStruct &result) { + auto map = (better::map)value; + + auto stringProp = map.find(\\"stringProp\\"); + if (stringProp != map.end()) { + fromRawValue(stringProp->second, result.stringProp); + } +} + +static inline std::string toString(const ObjectPropsObjectPropNestedArrayAsPropertyArrayPropStruct &value) { + return \\"[Object ObjectPropsObjectPropNestedArrayAsPropertyArrayPropStruct]\\"; +} + +static inline void fromRawValue(const RawValue &value, std::vector &result) { + auto items = (std::vector)value; + for (const auto &item : items) { + ObjectPropsObjectPropNestedArrayAsPropertyArrayPropStruct newItem; + fromRawValue(item, newItem); + result.emplace_back(newItem); + } +} + + struct ObjectPropsObjectPropNestedArrayAsPropertyStruct { std::vector arrayProp; }; From f0600e00dc1c008b3f739c10de64655a7212f778 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Mon, 19 Aug 2019 15:22:16 -0700 Subject: [PATCH 0019/1244] Also add in converstion imports for arrays of objects Summary: Fixes an issue where we weren't traversing all the way into object properties to find imports we may need Reviewed By: TheSavior Differential Revision: D16896674 fbshipit-source-id: f95a4f84e51265962ddfd2aeea9da717df033879 --- .../src/generators/components/GeneratePropsH.js | 7 ++++--- .../__tests__/__snapshots__/GeneratePropsH-test.js.snap | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 50d8c5dce5784f..18808afe12e70e 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -509,9 +509,10 @@ function getLocalImports( typeAnnotation.type === 'ArrayTypeAnnotation' && typeAnnotation.elementType.type === 'ObjectTypeAnnotation' ) { - const localImports = getLocalImports( - typeAnnotation.elementType.properties, - ); + const objectProps = typeAnnotation.elementType.properties; + const objectImports = getImports(objectProps); + const localImports = getLocalImports(objectProps); + objectImports.forEach(imports.add, imports); localImports.forEach(imports.add, imports); } diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap index 52ca0874d632e4..efce8c2e44df69 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsH-test.js.snap @@ -192,6 +192,7 @@ Map { */ #pragma once +#include #include #include #include From 5808973964b262ee3d4a8d68e0f01753efcac36c Mon Sep 17 00:00:00 2001 From: Albert Sun Date: Tue, 20 Aug 2019 10:17:05 -0700 Subject: [PATCH 0020/1244] Fix bridge.imageLoader warning message Summary: Missing space was causing this to show up as "themoduleForClass". Reviewed By: shergin Differential Revision: D16918867 fbshipit-source-id: c4bd19ca873d07e30e3fe8fc2c20277aab2d26d5 --- React/CoreModules/RCTImageLoader.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/React/CoreModules/RCTImageLoader.mm b/React/CoreModules/RCTImageLoader.mm index 758c1f8b78585c..ca4bfac2368530 100644 --- a/React/CoreModules/RCTImageLoader.mm +++ b/React/CoreModules/RCTImageLoader.mm @@ -959,7 +959,7 @@ @implementation RCTBridge (RCTImageLoader) - (RCTImageLoader *)imageLoader { - RCTLogWarn(@"Calling bridge.imageLoader is deprecated and will not work in newer versions of RN. Please update to the" + RCTLogWarn(@"Calling bridge.imageLoader is deprecated and will not work in newer versions of RN. Please update to the " "moduleForClass API or turboModuleLookupDelegate API."); return [self moduleForClass:[RCTImageLoader class]]; } From 1013a010492a7bef5ff58073a088ac924a986e9e Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 20 Aug 2019 10:32:16 -0700 Subject: [PATCH 0021/1244] TextInput: include AndroidTextInputNativeComponent instead of calling requireNativeComponent directly Summary: Include AndroidTextInputNativeComponent so we can rely on codegen and flow typing in a future diff. Reviewed By: TheSavior Differential Revision: D16903634 fbshipit-source-id: 767d7c854533d641eb7fcb2147bf584621581411 --- Libraries/Components/TextInput/TextInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 94315aa884124b..eb1da1041f67a0 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -38,7 +38,7 @@ let RCTMultilineTextInputView; let RCTSinglelineTextInputView; if (Platform.OS === 'android') { - AndroidTextInput = requireNativeComponent('AndroidTextInput'); + AndroidTextInput = require('./AndroidTextInputNativeComponent').default; } else if (Platform.OS === 'ios') { RCTMultilineTextInputView = requireNativeComponent( 'RCTMultilineTextInputView', From b26acae6dd81eda6f013343c8dd80139e6ff8097 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 20 Aug 2019 15:49:40 -0700 Subject: [PATCH 0022/1244] Flow type and codegen RCTFbMap Summary: Flow type for Android-only RCTFbMap component. ViewManager in Java here: https://our.intern.facebook.com/intern/diffusion/FBS/browse/master/fbandroid/java/com/facebook/catalyst/views/maps/ReactFbMapViewManager.java View in Java here: https://our.intern.facebook.com/intern/diffusion/FBS/browse/master/fbandroid/java/com/facebook/catalyst/views/maps/ReactFbMapView.java Reviewed By: TheSavior Differential Revision: D16811331 fbshipit-source-id: 210d80143b4826fc2ffb3402066c8fd0653e6794 --- .../react-native-codegen/src/parsers/flow/components/props.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index cc91f552f49b6e..4489691da06f0e 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -118,7 +118,7 @@ function getTypeAnnotationForArray(name, typeAnnotation, defaultValue, types) { }; default: (type: empty); - throw new Error(`Unknown prop type for "${name}"`); + throw new Error(`Unknown prop type for "${name}": ${type}`); } } From b8d6ef372663fe6d467144abfc5d2c9352dc28d6 Mon Sep 17 00:00:00 2001 From: SachinTotale Date: Tue, 20 Aug 2019 17:11:50 -0700 Subject: [PATCH 0023/1244] Memory Leak due to JSStringRelease not called in multiple places in JSCRuntime.cpp (#25884) Summary: Memory Leak due to JSStringRelease not called in multiple places in JSCRuntime.cpp Issue: https://github.com/facebook/react-native/issues/25664 Reproducible repo: https://github.com/bhandarijiwan/memory_issue_repro ## Changelog [JSC] [JSCRuntime.cpp] - Added missing JSStringRelease calls in missing places Pull Request resolved: https://github.com/facebook/react-native/pull/25884 Test Plan: Tested that is no memory leak with various NativeModule to JS call flows Reviewed By: JoshuaGross Differential Revision: D16928985 Pulled By: TheSavior fbshipit-source-id: 65ce15ae32482d0db39bad7e22a2fed9ee04f230 --- ReactCommon/jsi/JSCRuntime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ReactCommon/jsi/JSCRuntime.cpp b/ReactCommon/jsi/JSCRuntime.cpp index a0457397bf22af..00c3a65dfdd5c7 100644 --- a/ReactCommon/jsi/JSCRuntime.cpp +++ b/ReactCommon/jsi/JSCRuntime.cpp @@ -630,7 +630,9 @@ jsi::String JSCRuntime::createStringFromUtf8( size_t length) { std::string tmp(reinterpret_cast(str), length); JSStringRef stringRef = JSStringCreateWithUTF8CString(tmp.c_str()); - return createString(stringRef); + auto result = createString(stringRef); + JSStringRelease(stringRef); + return result; } std::string JSCRuntime::utf8(const jsi::String& str) { From 43f042eb7db0fe97265e05ff39a7af6781530680 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 20 Aug 2019 22:26:57 -0700 Subject: [PATCH 0024/1244] Work around crashing redbox Summary: When debugging supporting a Fabric component, a redbox was being shown without a title which resulted in an infinite redbox loop, followed by OOM. That isn't helpful so we just safely work around the null title while indicating what happened to aid in debugging. Reviewed By: lunaleaps Differential Revision: D16921053 fbshipit-source-id: df1f4a691df0c10de53c91e4a9356a04a9005a97 --- .../java/com/facebook/react/devsupport/RedBoxDialog.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java b/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java index bf509d33455305..22e50da0f6caa9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java +++ b/ReactAndroid/src/main/java/com/facebook/react/devsupport/RedBoxDialog.java @@ -122,6 +122,8 @@ private FrameViewHolder(View v) { public StackAdapter(String title, StackFrame[] stack) { mTitle = title; mStack = stack; + Assertions.assertNotNull(mTitle); + Assertions.assertNotNull(mStack); } @Override @@ -169,7 +171,8 @@ public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater.from(parent.getContext()) .inflate(R.layout.redbox_item_title, parent, false); // Remove ANSI color codes from the title - title.setText(mTitle.replaceAll("\\x1b\\[[0-9;]*m", "")); + String titleSafe = (mTitle == null ? "" : mTitle); + title.setText(titleSafe.replaceAll("\\x1b\\[[0-9;]*m", "")); return title; } else { if (convertView == null) { From 11dc847ec9c491f5a8eeff1300bca02e040f5889 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 20 Aug 2019 22:26:57 -0700 Subject: [PATCH 0025/1244] Give a more explicit message about why `number` isn't supported Summary: Give a more explicit message about why `number` isn't supported Reviewed By: rickhanlonii Differential Revision: D16926698 fbshipit-source-id: 292cb13aa11205e1350209178bde1977a2a7ad4c --- .../components/__test_fixtures__/failures.js | 30 +++++++++++++++++++ .../component-parser-test.js.snap | 2 ++ .../src/parsers/flow/components/props.js | 4 +++ 3 files changed, 36 insertions(+) diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js index 7ce34a5e5ded9b..c814c352948839 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/failures.js @@ -403,6 +403,35 @@ export default (codegenNativeComponent( ): NativeComponent); `; +const PROP_NUMBER_TYPE = ` +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import type {ViewProps} from 'ViewPropTypes'; +import type {NativeComponent} from 'codegenNativeComponent'; + +const codegenNativeComponent = require('codegenNativeComponent'); + +export type ModuleProps = $ReadOnly<{| + ...ViewProps, + + someProp: number +|}>; + +export default (codegenNativeComponent( + 'Module', +): NativeComponent); +`; + module.exports = { COMMANDS_DEFINED_INLINE, COMMANDS_DEFINED_MULTIPLE_TIMES, @@ -415,4 +444,5 @@ module.exports = { PROPS_CONFLICT_NAMES, PROPS_CONFLICT_WITH_SPREAD_PROPS, PROPS_SPREAD_CONFLICTS_WITH_PROPS, + PROP_NUMBER_TYPE, }; diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index 958a44b947e8a2..83b2d69a2d25fe 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -16,6 +16,8 @@ exports[`RN Codegen Flow Parser Fails with error message NON_OPTIONAL_KEY_WITH_D exports[`RN Codegen Flow Parser Fails with error message NULLABLE_WITH_DEFAULT 1`] = `"WithDefault<> is optional and does not need to be marked as optional. Please remove the ? annotation in front of it."`; +exports[`RN Codegen Flow Parser Fails with error message PROP_NUMBER_TYPE 1`] = `"Cannot use \\"NumberTypeAnnotation\\" type annotation for \\"someProp\\": must use a specific numeric type like Int32, Double, or Float"`; + exports[`RN Codegen Flow Parser Fails with error message PROPS_CONFLICT_NAMES 1`] = `"A prop was already defined with the name isEnabled"`; exports[`RN Codegen Flow Parser Fails with error message PROPS_CONFLICT_WITH_SPREAD_PROPS 1`] = `"A prop was already defined with the name isEnabled"`; diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index 4489691da06f0e..3bd8591d9f41c7 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -229,6 +229,10 @@ function getTypeAnnotation(name, annotation, defaultValue, types) { }; } throw new Error(`A default enum value is required for "${name}"`); + case 'NumberTypeAnnotation': + throw new Error( + `Cannot use "${type}" type annotation for "${name}": must use a specific numeric type like Int32, Double, or Float`, + ); default: (type: empty); throw new Error(`Unknown prop type for "${name}": "${type}"`); From 219e1972d6f4ceeac4ffc41f8facc4205da78546 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 20 Aug 2019 22:26:57 -0700 Subject: [PATCH 0026/1244] Remove hack in C++ that prevents any real TextInputs from being rendered Summary: There's an old hack in the C++ code that prevents TextInputs from being rendered by forcing them to render as Views instead. We don't need this anymore. Reviewed By: shergin Differential Revision: D16932795 fbshipit-source-id: 347df106f638c2bf936e2312f42bcb9310d72c6d --- ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp index fbb8420b7a8846..63e23428619218 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorRegistry.cpp @@ -103,9 +103,7 @@ static std::string componentNameByReactViewName(std::string viewName) { // We need this temporarily for testing purposes until we have proper // implementation of core components. - if (viewName == "SinglelineTextInputView" || - viewName == "MultilineTextInputView" || viewName == "AndroidTextInput" || - viewName == "SafeAreaView" || viewName == "ScrollContentView" || + if (viewName == "SafeAreaView" || viewName == "ScrollContentView" || viewName == "AndroidHorizontalScrollContentView" // Android ) { return "View"; From 92073d4a71d50a1ed80cf9cb063a6144fcc8cf19 Mon Sep 17 00:00:00 2001 From: Logan Daniels Date: Wed, 21 Aug 2019 09:56:31 -0700 Subject: [PATCH 0027/1244] Clean-up $TEMPORARY$object in xplat/js/react-native-github Reviewed By: panagosg7 Differential Revision: D16931667 fbshipit-source-id: d87e5ed02bf7f95005cf0f36c3cd127026189058 --- IntegrationTests/AsyncStorageTest.js | 2 +- IntegrationTests/ImageCachePolicyTest.js | 2 +- Libraries/Animated/src/AnimatedEvent.js | 2 +- Libraries/Animated/src/animations/DecayAnimation.js | 4 ++-- .../Animated/src/animations/SpringAnimation.js | 4 ++-- .../Components/DatePicker/DatePickerIOS.ios.js | 4 +--- Libraries/Components/Keyboard/Keyboard.js | 4 ++-- .../Components/Keyboard/KeyboardAvoidingView.js | 5 +---- Libraries/Components/Picker/Picker.js | 4 +--- Libraries/Components/StatusBar/StatusBar.js | 4 ++-- .../Components/View/ReactNativeViewViewConfig.js | 4 ++-- Libraries/Components/View/ViewNativeComponent.js | 6 +++--- Libraries/Core/Timers/JSTimers.js | 4 ++-- Libraries/Experimental/Incremental.js | 6 +++--- Libraries/Experimental/IncrementalPresenter.js | 4 ++-- Libraries/Experimental/WindowedListView.js | 4 ++-- Libraries/Modal/Modal.js | 13 ++++--------- Libraries/ReactNative/AppContainer.js | 2 +- Libraries/ReactNative/DummyUIManager.js | 2 +- .../Renderer/shims/ReactNativeViewConfigRegistry.js | 8 ++++---- Libraries/UTFSequence.js | 4 ++-- .../verifyComponentAttributeEquivalence.js | 2 +- Libraries/YellowBox/UI/YellowBoxPressable.js | 6 +++--- Libraries/vendor/emitter/EventHolder.js | 2 +- RNTester/js/components/ListExampleShared.js | 2 +- RNTester/js/components/TextLegend.js | 4 ++-- .../js/examples/MultiColumn/MultiColumnExample.js | 4 ++-- .../js/examples/SectionList/SectionListExample.js | 4 ++-- RNTester/js/examples/XHR/XHRExampleBinaryUpload.js | 4 +--- RNTester/js/utils/RNTesterList.ios.js | 2 +- 30 files changed, 54 insertions(+), 68 deletions(-) diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js index 5df923c7f670ea..070e711b7e50c5 100644 --- a/IntegrationTests/AsyncStorageTest.js +++ b/IntegrationTests/AsyncStorageTest.js @@ -172,7 +172,7 @@ function testOptimizedMultiGet() { } class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { - state: any | $TEMPORARY$object<{|done: boolean, messages: string|}> = { + state: any | {|done: boolean, messages: string|} = { messages: 'Initializing...', done: false, }; diff --git a/IntegrationTests/ImageCachePolicyTest.js b/IntegrationTests/ImageCachePolicyTest.js index d25e6c2b86ede3..2a152ef98f23e3 100644 --- a/IntegrationTests/ImageCachePolicyTest.js +++ b/IntegrationTests/ImageCachePolicyTest.js @@ -36,7 +36,7 @@ type State = { }; class ImageCachePolicyTest extends React.Component { - state: $FlowFixMe | $TEMPORARY$object<{||}> = {}; + state: $FlowFixMe | {...} = {}; shouldComponentUpdate(nextProps: Props, nextState: State): boolean { const results: Array = TESTS.map(x => nextState[x]); diff --git a/Libraries/Animated/src/AnimatedEvent.js b/Libraries/Animated/src/AnimatedEvent.js index 8e8c9c24068ce9..40a3bd1ae282a9 100644 --- a/Libraries/Animated/src/AnimatedEvent.js +++ b/Libraries/Animated/src/AnimatedEvent.js @@ -27,7 +27,7 @@ function attachNativeEvent( viewRef: any, eventName: string, argMapping: Array, -): $TEMPORARY$object<{|detach: () => void|}> { +): {|detach: () => void|} { // Find animated values in `argMapping` and create an array representing their // key path inside the `nativeEvent` object. Ex.: ['contentOffset', 'x']. const eventMappings = []; diff --git a/Libraries/Animated/src/animations/DecayAnimation.js b/Libraries/Animated/src/animations/DecayAnimation.js index 27ec5d8dd51c54..68af7f5dcd12de 100644 --- a/Libraries/Animated/src/animations/DecayAnimation.js +++ b/Libraries/Animated/src/animations/DecayAnimation.js @@ -45,12 +45,12 @@ class DecayAnimation extends Animation { this.__iterations = config.iterations ?? 1; } - __getNativeAnimationConfig(): $TEMPORARY$object<{| + __getNativeAnimationConfig(): {| deceleration: number, iterations: number, type: $TEMPORARY$string<'decay'>, velocity: number, - |}> { + |} { return { type: 'decay', deceleration: this._deceleration, diff --git a/Libraries/Animated/src/animations/SpringAnimation.js b/Libraries/Animated/src/animations/SpringAnimation.js index 9a16bde6b71c5e..5e34faeb247e0b 100644 --- a/Libraries/Animated/src/animations/SpringAnimation.js +++ b/Libraries/Animated/src/animations/SpringAnimation.js @@ -138,7 +138,7 @@ class SpringAnimation extends Animation { invariant(this._mass > 0, 'Mass value must be greater than 0'); } - __getNativeAnimationConfig(): $TEMPORARY$object<{| + __getNativeAnimationConfig(): {| damping: number, initialVelocity: number, iterations: number, @@ -149,7 +149,7 @@ class SpringAnimation extends Animation { stiffness: number, toValue: any, type: $TEMPORARY$string<'spring'>, - |}> { + |} { return { type: 'spring', overshootClamping: this._overshootClamping, diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js index c01a3c495dd664..afae770d487df5 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js @@ -112,9 +112,7 @@ type Props = $ReadOnly<{| * source of truth. */ class DatePickerIOS extends React.Component { - static DefaultProps: $TEMPORARY$object<{| - mode: $TEMPORARY$string<'datetime'>, - |}> = { + static DefaultProps: {|mode: $TEMPORARY$string<'datetime'>|} = { mode: 'datetime', }; diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index a024a447861bcd..e113495f5cd9d5 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -111,7 +111,7 @@ type KeyboardEventListener = (e: KeyboardEvent) => void; let Keyboard: | NativeEventEmitter - | $TEMPORARY$object<{| + | {| addListener: ( eventName: KeyboardEventName, callback: KeyboardEventListener, @@ -123,7 +123,7 @@ let Keyboard: callback: KeyboardEventListener, ) => $FlowFixMe, scheduleLayoutAnimation: (event: KeyboardEvent) => $FlowFixMe, - |}> = { + |} = { /** * The `addListener` function connects a JavaScript function to an identified native * keyboard notification event. diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index ae0dd37fb0814c..e49e9aa7ea59b4 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -61,10 +61,7 @@ type State = {| * adjusting its height, position, or bottom padding. */ class KeyboardAvoidingView extends React.Component { - static defaultProps: $TEMPORARY$object<{| - enabled: boolean, - keyboardVerticalOffset: number, - |}> = { + static defaultProps: {|enabled: boolean, keyboardVerticalOffset: number|} = { enabled: true, keyboardVerticalOffset: 0, }; diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js index cded08c74d8d15..7e9960a4460c31 100644 --- a/Libraries/Components/Picker/Picker.js +++ b/Libraries/Components/Picker/Picker.js @@ -130,9 +130,7 @@ class Picker extends React.Component { static Item: typeof PickerItem = PickerItem; - static defaultProps: $TEMPORARY$object<{| - mode: $TEMPORARY$string<'dialog'>, - |}> = { + static defaultProps: {|mode: $TEMPORARY$string<'dialog'>|} = { mode: MODE_DIALOG, }; diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 4d50ce488015b4..1481b25d9a8604 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -376,10 +376,10 @@ class StatusBar extends React.Component { return newEntry; } - static defaultProps: $TEMPORARY$object<{| + static defaultProps: {| animated: boolean, showHideTransition: $TEMPORARY$string<'fade'>, - |}> = { + |} = { animated: false, showHideTransition: 'fade', }; diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 39a603a6eb7807..a5fbea0a588dbb 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -15,8 +15,8 @@ const ReactNativeViewConfig = { uiViewClassName: 'RCTView', baseModuleName: null, Manager: 'ViewManager', - Commands: ({}: $TEMPORARY$object<{||}>), - Constants: ({}: $TEMPORARY$object<{||}>), + Commands: ({}: {...}), + Constants: ({}: {...}), bubblingEventTypes: { ...ReactNativeViewViewConfigAndroid.bubblingEventTypes, topBlur: { diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index f954a2d6c2f474..c735b5b864a77b 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -25,8 +25,8 @@ export type ViewNativeComponentType = Class< let NativeViewComponent; let viewConfig: - | $TEMPORARY$object<{||}> - | $TEMPORARY$object<{| + | {...} + | {| bubblingEventTypes?: $ReadOnly<{ [eventName: string]: $ReadOnly<{| phasedRegistrationNames: $ReadOnly<{| @@ -47,7 +47,7 @@ let viewConfig: process?: (arg1: any) => any, |}>, }, - |}>; + |}; // Only use the JS view config in DEV if (__DEV__) { diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index e877680f778aad..5bdd927cda386d 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -497,7 +497,7 @@ function setSendIdleEvents(sendIdleEvents: boolean): void { NativeTiming.setSendIdleEvents(sendIdleEvents); } -let ExportedJSTimers: $TEMPORARY$object<{| +let ExportedJSTimers: {| callIdleCallbacks: (frameTime: number) => any | void, callImmediates: () => void, callTimers: (timersToCall: Array) => any | void, @@ -512,7 +512,7 @@ let ExportedJSTimers: $TEMPORARY$object<{| setImmediate: (func: any, ...args: any) => number, setInterval: (func: any, duration: number, ...args: any) => number, setTimeout: (func: any, duration: number, ...args: any) => number, -|}>; +|}; if (!NativeTiming) { console.warn("Timing native module is not available, can't set timers."); // $FlowFixMe: we can assume timers are generally available diff --git a/Libraries/Experimental/Incremental.js b/Libraries/Experimental/Incremental.js index 8ccb315d6a8dc0..ba16f91c93264e 100644 --- a/Libraries/Experimental/Incremental.js +++ b/Libraries/Experimental/Incremental.js @@ -103,16 +103,16 @@ class Incremental extends React.Component { _mounted: boolean; _rendered: boolean; - static defaultProps: $TEMPORARY$object<{|name: string|}> = { + static defaultProps: {|name: string|} = { name: '', }; static contextTypes: | any - | $TEMPORARY$object<{| + | {| incrementalGroup: React$PropType$Primitive, incrementalGroupEnabled: React$PropType$Primitive, - |}> = { + |} = { incrementalGroup: PropTypes.object, incrementalGroupEnabled: PropTypes.bool, }; diff --git a/Libraries/Experimental/IncrementalPresenter.js b/Libraries/Experimental/IncrementalPresenter.js index 561da9bbd83f17..74e147e998b39d 100644 --- a/Libraries/Experimental/IncrementalPresenter.js +++ b/Libraries/Experimental/IncrementalPresenter.js @@ -46,10 +46,10 @@ class IncrementalPresenter extends React.Component { static contextTypes: | any - | $TEMPORARY$object<{| + | {| incrementalGroup: React$PropType$Primitive, incrementalGroupEnabled: React$PropType$Primitive, - |}> = { + |} = { incrementalGroup: PropTypes.object, incrementalGroupEnabled: PropTypes.bool, }; diff --git a/Libraries/Experimental/WindowedListView.js b/Libraries/Experimental/WindowedListView.js index 05c2fa038f08b0..84ff57dc65c384 100644 --- a/Libraries/Experimental/WindowedListView.js +++ b/Libraries/Experimental/WindowedListView.js @@ -170,7 +170,7 @@ class WindowedListView extends React.Component { _scrollRef: ?ScrollView; _viewabilityHelper: ViewabilityHelper; - static defaultProps: $TEMPORARY$object<{| + static defaultProps: {| disableIncrementalRendering: boolean, initialNumToRender: number, maxNumToRender: number, @@ -178,7 +178,7 @@ class WindowedListView extends React.Component { recomputeRowsBatchingPeriod: number, renderScrollComponent: (props: any) => React.Node, viewablePercentThreshold: number, - |}> = { + |} = { initialNumToRender: 10, maxNumToRender: 30, numToRenderAhead: 10, diff --git a/Libraries/Modal/Modal.js b/Libraries/Modal/Modal.js index e21ed2ced51564..bfcac0aa319e6c 100644 --- a/Libraries/Modal/Modal.js +++ b/Libraries/Modal/Modal.js @@ -137,17 +137,12 @@ export type Props = $ReadOnly<{| |}>; class Modal extends React.Component { - static defaultProps: $TEMPORARY$object<{| - hardwareAccelerated: boolean, - visible: boolean, - |}> = { + static defaultProps: {|hardwareAccelerated: boolean, visible: boolean|} = { visible: true, hardwareAccelerated: false, }; - static contextTypes: - | any - | $TEMPORARY$object<{|rootTag: React$PropType$Primitive|}> = { + static contextTypes: any | {|rootTag: React$PropType$Primitive|} = { rootTag: PropTypes.number, }; @@ -162,11 +157,11 @@ class Modal extends React.Component { static childContextTypes: | any - | $TEMPORARY$object<{|virtualizedList: React$PropType$Primitive|}> = { + | {|virtualizedList: React$PropType$Primitive|} = { virtualizedList: PropTypes.object, }; - getChildContext(): $TEMPORARY$object<{|virtualizedList: null|}> { + getChildContext(): {|virtualizedList: null|} { // Reset the context so VirtualizedList doesn't get confused by nesting // in the React tree that doesn't reflect the native component hierarchy. return { diff --git a/Libraries/ReactNative/AppContainer.js b/Libraries/ReactNative/AppContainer.js index 39d3374a864a1d..2766e76c8dda37 100644 --- a/Libraries/ReactNative/AppContainer.js +++ b/Libraries/ReactNative/AppContainer.js @@ -44,7 +44,7 @@ class AppContainer extends React.Component { static childContextTypes: | any - | $TEMPORARY$object<{|rootTag: React$PropType$Primitive|}> = { + | {|rootTag: React$PropType$Primitive|} = { rootTag: PropTypes.number, }; diff --git a/Libraries/ReactNative/DummyUIManager.js b/Libraries/ReactNative/DummyUIManager.js index fb2a774b916fd9..a6ae78a9624566 100644 --- a/Libraries/ReactNative/DummyUIManager.js +++ b/Libraries/ReactNative/DummyUIManager.js @@ -16,7 +16,7 @@ module.exports = { ); return null; }, - getConstants: (): $TEMPORARY$object<{||}> => ({}), + getConstants: (): {...} => ({}), getConstantsForViewManager: (viewManagerName: string) => {}, getDefaultEventTypes: (): Array<$FlowFixMe> => [], playTouchSound: () => {}, diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js index c1e192abae644b..cf695bb782dc7a 100644 --- a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -12,16 +12,16 @@ 'use strict'; +const invariant = require('invariant'); + import type { ReactNativeBaseComponentViewConfig, ViewConfigGetter, } from './ReactNativeTypes'; -const invariant = require('invariant'); - // Event configs -const customBubblingEventTypes: $TEMPORARY$object<{||}> = {}; -const customDirectEventTypes: $TEMPORARY$object<{||}> = {}; +const customBubblingEventTypes: {...} = {}; +const customDirectEventTypes: {...} = {}; exports.customBubblingEventTypes = customBubblingEventTypes; exports.customDirectEventTypes = customDirectEventTypes; diff --git a/Libraries/UTFSequence.js b/Libraries/UTFSequence.js index 4e6c030ef20f20..70d17a3ba40a97 100644 --- a/Libraries/UTFSequence.js +++ b/Libraries/UTFSequence.js @@ -19,7 +19,7 @@ const deepFreezeAndThrowOnMutationInDev = require('./Utilities/deepFreezeAndThro * - Source code should be limitted to ASCII. * - Less chance of typos. */ -const UTFSequence: $TEMPORARY$object<{| +const UTFSequence: {| BOM: string, BULLET: string, BULLET_SP: string, @@ -34,7 +34,7 @@ const UTFSequence: $TEMPORARY$object<{| PIZZA: string, TRIANGLE_LEFT: string, TRIANGLE_RIGHT: string, -|}> = deepFreezeAndThrowOnMutationInDev({ +|} = deepFreezeAndThrowOnMutationInDev({ BOM: '\ufeff', // byte order mark BULLET: '\u2022', // bullet: • BULLET_SP: '\u00A0\u2022\u00A0', //  •  diff --git a/Libraries/Utilities/verifyComponentAttributeEquivalence.js b/Libraries/Utilities/verifyComponentAttributeEquivalence.js index 98a725ab02e319..37ff4ff198f7d7 100644 --- a/Libraries/Utilities/verifyComponentAttributeEquivalence.js +++ b/Libraries/Utilities/verifyComponentAttributeEquivalence.js @@ -105,7 +105,7 @@ export function lefthandObjectDiff(leftObj: Object, rightObj: Object): Object { export function getConfigWithoutViewProps( viewConfig: ReactNativeBaseComponentViewConfig<>, propName: string, -): $TEMPORARY$object<{||}> { +): {...} { if (!viewConfig[propName]) { return {}; } diff --git a/Libraries/YellowBox/UI/YellowBoxPressable.js b/Libraries/YellowBox/UI/YellowBoxPressable.js index ed7b688a76854d..766ed2600dd94d 100644 --- a/Libraries/YellowBox/UI/YellowBoxPressable.js +++ b/Libraries/YellowBox/UI/YellowBoxPressable.js @@ -36,9 +36,9 @@ type State = {| |}; class YellowBoxPressable extends React.Component { - static defaultProps: $TEMPORARY$object<{| - backgroundColor: $TEMPORARY$object<{|default: string, pressed: string|}>, - |}> = { + static defaultProps: {| + backgroundColor: {|default: string, pressed: string|}, + |} = { backgroundColor: { default: YellowBoxStyle.getBackgroundColor(0.95), pressed: YellowBoxStyle.getHighlightColor(1), diff --git a/Libraries/vendor/emitter/EventHolder.js b/Libraries/vendor/emitter/EventHolder.js index 54728e753904d1..ab71363b01ffb4 100644 --- a/Libraries/vendor/emitter/EventHolder.js +++ b/Libraries/vendor/emitter/EventHolder.js @@ -45,7 +45,7 @@ class EventHolder { holdEvent( eventType: string, ...args: any - ): $TEMPORARY$object<{|eventType: string, index: $FlowFixMeEmpty|}> { + ): {|eventType: string, index: $FlowFixMeEmpty|} { this._heldEvents[eventType] = this._heldEvents[eventType] || []; const eventsOfType = this._heldEvents[eventType]; const key = { diff --git a/RNTester/js/components/ListExampleShared.js b/RNTester/js/components/ListExampleShared.js index 69e3ecc1510611..b124122d09be7b 100644 --- a/RNTester/js/components/ListExampleShared.js +++ b/RNTester/js/components/ListExampleShared.js @@ -219,7 +219,7 @@ function getItemLayout( data: any, index: number, horizontal?: boolean, -): $TEMPORARY$object<{|index: number, length: number, offset: number|}> { +): {|index: number, length: number, offset: number|} { const [length, separator, header] = horizontal ? [HORIZ_WIDTH, 0, HEADER.width] : [ITEM_HEIGHT, SEPARATOR_HEIGHT, HEADER.height]; diff --git a/RNTester/js/components/TextLegend.js b/RNTester/js/components/TextLegend.js index b53bed9dd7d1df..dd4a1be526132e 100644 --- a/RNTester/js/components/TextLegend.js +++ b/RNTester/js/components/TextLegend.js @@ -15,12 +15,12 @@ const React = require('react'); const {Picker, Text, View} = require('react-native'); class TextLegend extends React.Component<*, *> { - state: $TEMPORARY$object<{| + state: {| alignment: $TEMPORARY$string<'left'>, fontSize: number, language: $TEMPORARY$string<'english'>, textMetrics: Array, - |}> = { + |} = { textMetrics: [], language: 'english', alignment: 'left', diff --git a/RNTester/js/examples/MultiColumn/MultiColumnExample.js b/RNTester/js/examples/MultiColumn/MultiColumnExample.js index 480090d1b1a502..aa1ea81b136619 100644 --- a/RNTester/js/examples/MultiColumn/MultiColumnExample.js +++ b/RNTester/js/examples/MultiColumn/MultiColumnExample.js @@ -35,14 +35,14 @@ class MultiColumnExample extends React.PureComponent< > { state: | any - | $TEMPORARY$object<{| + | {| data: Array, filterText: string, fixedHeight: boolean, logViewable: boolean, numColumns: number, virtualized: boolean, - |}> = { + |} = { data: genItemData(1000), filterText: '', fixedHeight: true, diff --git a/RNTester/js/examples/SectionList/SectionListExample.js b/RNTester/js/examples/SectionList/SectionListExample.js index 014fa48a0b14b9..3046602e30f244 100644 --- a/RNTester/js/examples/SectionList/SectionListExample.js +++ b/RNTester/js/examples/SectionList/SectionListExample.js @@ -70,14 +70,14 @@ const CustomSeparatorComponent = ({highlighted, text}) => ( class SectionListExample extends React.PureComponent<{}, $FlowFixMeState> { state: | any - | $TEMPORARY$object<{| + | {| data: Array, debug: boolean, filterText: string, inverted: boolean, logViewable: boolean, virtualized: boolean, - |}> = { + |} = { data: genItemData(1000), debug: false, filterText: '', diff --git a/RNTester/js/examples/XHR/XHRExampleBinaryUpload.js b/RNTester/js/examples/XHR/XHRExampleBinaryUpload.js index 962265116b187a..adf83002c5072e 100644 --- a/RNTester/js/examples/XHR/XHRExampleBinaryUpload.js +++ b/RNTester/js/examples/XHR/XHRExampleBinaryUpload.js @@ -72,9 +72,7 @@ class XHRExampleBinaryUpload extends React.Component<{}, $FlowFixMeState> { Linking.openURL(url); } - state: - | $FlowFixMe - | $TEMPORARY$object<{|type: $TEMPORARY$string<'Uint8Array'>|}> = { + state: $FlowFixMe | {|type: $TEMPORARY$string<'Uint8Array'>|} = { type: 'Uint8Array', }; diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index 4a9c7aa9442d54..33a698ddebafba 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -337,7 +337,7 @@ const APIExamples: Array = [ }, ]; -const Modules: $TEMPORARY$object<{||}> = {}; +const Modules: {...} = {}; APIExamples.concat(ComponentExamples).forEach(Example => { Modules[Example.key] = Example.module; From 869ddd701b39448d8db086167eb82b9222e7f4b2 Mon Sep 17 00:00:00 2001 From: Rick Hanlon Date: Wed, 21 Aug 2019 12:56:41 -0700 Subject: [PATCH 0028/1244] Add support for type exports to babel parser Summary: Updates the babel parser to support exports that include flow types Changelog: [Internal] Reviewed By: cpojer Differential Revision: D16927086 fbshipit-source-id: 526efd911c2492a67f618d2d8ad199a7a5a235ff --- .../__test_fixtures__/fixtures.js | 45 +++++++++++++ .../__snapshots__/index-test.js.snap | 65 +++++++++++++++++++ .../babel-plugin-inline-view-configs/index.js | 8 +++ .../package.json | 2 +- 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js index 9f0925af87f176..620c6fb7b73143 100644 --- a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -56,7 +56,52 @@ export default codegenNativeComponent('Module', { }); `; +const FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT = ` +// @flow + +const codegenNativeCommands = require('codegenNativeCommands'); +const codegenNativeComponent = require('codegenNativeComponent'); +import type {NativeComponent} from 'ReactNative'; + +import type { + Int32, + BubblingEventHandler, + DirectEventHandler, + WithDefault, +} from 'CodegenFlowtypes'; + +import type {ViewProps} from 'ViewPropTypes'; + +interface NativeCommands { + +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void; + +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void; +} + +type ModuleProps = $ReadOnly<{| + ...ViewProps, + + // Props + boolean_default_true_optional_both?: WithDefault, + + // Events + onDirectEventDefinedInlineNull: DirectEventHandler, + onBubblingEventDefinedInlineNull: BubblingEventHandler, +|}>; + +export const Commands = codegenNativeCommands({ + supportedCommands: ['hotspotUpdate', 'scrollTo'], +}); + +type NativeComponentType = Class>; + +export default (codegenNativeComponent('Module', { + interfaceOnly: true, + paperComponentName: 'RCTModule', +}): NativeComponentType); +`; + module.exports = { 'NotANativeComponent.js': NOT_A_NATIVE_COMPONENT, 'FullNativeComponent.js': FULL_NATIVE_COMPONENT, + 'FullTypedNativeComponent.js': FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT, }; diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap index 6258f1f15703ef..a7175adeb4dc95 100644 --- a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -63,6 +63,71 @@ export const Commands = { };" `; +exports[`Babel plugin inline view configs can inline config for FullTypedNativeComponent.js 1`] = ` +"// @flow +const codegenNativeCommands = require('codegenNativeCommands'); + +const codegenNativeComponent = require('codegenNativeComponent'); + +import type { NativeComponent } from 'ReactNative'; +import type { Int32, BubblingEventHandler, DirectEventHandler, WithDefault } from 'CodegenFlowtypes'; +import type { ViewProps } from 'ViewPropTypes'; +interface NativeCommands { + +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void, + +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void, +} +type ModuleProps = $ReadOnly<{| ...ViewProps, + // Props + boolean_default_true_optional_both?: WithDefault, + // Events + onDirectEventDefinedInlineNull: DirectEventHandler, + onBubblingEventDefinedInlineNull: BubblingEventHandler, +|}>; +type NativeComponentType = Class>; + +const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); + +const { + dispatchCommand +} = require(\\"react-native/Libraries/Renderer/shims/ReactNative\\"); + +const ModuleViewConfig = { + uiViewClassName: 'RCTModule', + bubblingEventTypes: { + topBubblingEventDefinedInlineNull: { + phasedRegistrationNames: { + captured: 'onBubblingEventDefinedInlineNullCapture', + bubbled: 'onBubblingEventDefinedInlineNull' + } + } + }, + directEventTypes: { + topDirectEventDefinedInlineNull: { + registrationName: 'onDirectEventDefinedInlineNull' + } + }, + validAttributes: { + boolean_default_true_optional_both: true, + onDirectEventDefinedInlineNull: true, + onBubblingEventDefinedInlineNull: true + } +}; +let nativeComponentName = 'RCTModule'; +registerGeneratedViewConfig(nativeComponentName, ModuleViewConfig); +export const __INTERNAL_VIEW_CONFIG = ModuleViewConfig; +export default nativeComponentName; +export const Commands = { + hotspotUpdate(ref, x, y) { + dispatchCommand(ref, \\"hotspotUpdate\\", [x, y]); + }, + + scrollTo(ref, y, animated) { + dispatchCommand(ref, \\"scrollTo\\", [y, animated]); + } + +};" +`; + exports[`Babel plugin inline view configs can inline config for NotANativeComponent.js 1`] = ` "const requireNativeComponent = require('requireNativeComponent'); diff --git a/packages/babel-plugin-inline-view-configs/index.js b/packages/babel-plugin-inline-view-configs/index.js index a6dc270b284d87..1a7171cfc79b5c 100644 --- a/packages/babel-plugin-inline-view-configs/index.js +++ b/packages/babel-plugin-inline-view-configs/index.js @@ -41,6 +41,14 @@ function isCodegenDeclaration(declaration) { declaration.callee.name === 'codegenNativeComponent' ) { return true; + } else if ( + declaration.type === 'TypeCastExpression' && + declaration.expression && + declaration.expression.callee && + declaration.expression.callee.name && + declaration.expression.callee.name === 'codegenNativeComponent' + ) { + return true; } return false; diff --git a/packages/babel-plugin-inline-view-configs/package.json b/packages/babel-plugin-inline-view-configs/package.json index ad1dc6e0d0c7e4..57d42284135502 100644 --- a/packages/babel-plugin-inline-view-configs/package.json +++ b/packages/babel-plugin-inline-view-configs/package.json @@ -1,5 +1,5 @@ { - "version": "0.0.4", + "version": "0.0.5", "name": "babel-plugin-inline-view-configs", "description": "Babel plugin to inline view configs for React Native", "repository": { From e94f2c362581c72e56a5436a2b9e67ca57901bda Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Wed, 21 Aug 2019 14:28:16 -0700 Subject: [PATCH 0029/1244] Adhere to main queue requirements of native modules Summary: Certain turbomodules set `requiresMainQueueSetup` to true. This is b/c they use some fancy APIs in setup that need main queue. TurboModuleManager mostly adhered to this restriction, the only case it didn't is when setting bridge. There is possibility that this happens on JS thread, which would crash the app for these certain TM. This diff fixes that. Reviewed By: RSNara Differential Revision: D16921644 fbshipit-source-id: 69b2410550360d3ccb03c0b71fb7dfccb889eda4 --- .../core/platform/ios/RCTTurboModuleManager.mm | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm index 3cb73b54c011e8..f3273629fdc4e2 100644 --- a/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm +++ b/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm @@ -284,6 +284,10 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name */ @try { /** + * If module requiresMainQueueSetup, dispatch to main queue. Bridge setup + * may call APIs which are main queue only, which crash if called from + * JS thread. + * * RCTBridgeModule declares the bridge property as readonly. * Therefore, when authors of NativeModules synthesize the bridge * via @synthesize bridge = bridge;, the ObjC runtime generates @@ -291,7 +295,16 @@ - (void)notifyAboutTurboModuleSetup:(const char *)name * generated, so we have have to rely on the KVC API of ObjC to set * the bridge property of these NativeModules. */ - [(id)module setValue:_bridge forKey:@"bridge"]; + if ([[module class] respondsToSelector:@selector(requiresMainQueueSetup)] && + [[module class] requiresMainQueueSetup]) { + __weak __typeof(self) weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + __strong __typeof(self) strongSelf = weakSelf; + [(id)module setValue:strongSelf->_bridge forKey:@"bridge"]; + }); + } else { + [(id)module setValue:_bridge forKey:@"bridge"]; + } } @catch (NSException *exception) { RCTLogError( @"%@ has no setter or ivar for its bridge, which is not " From 685c15a9554b4a78c41e615e47ab2374c539c252 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Wed, 21 Aug 2019 14:28:16 -0700 Subject: [PATCH 0030/1244] Make RCTDeviceInfo a TurboModule Summary: Follow pattern laid out by Kevin in D16001262 to convert a Core OSS native module to use TM generated spec. Reviewed By: RSNara Differential Revision: D16016391 fbshipit-source-id: f517777be44c68367d786f04c50cf12f240eed00 --- React/CoreModules/BUCK | 8 +++-- React/CoreModules/CoreModulesPlugins.h | 1 + React/CoreModules/CoreModulesPlugins.mm | 3 +- .../{Modules => CoreModules}/RCTDeviceInfo.h | 0 .../RCTDeviceInfo.mm} | 35 +++++++++++++------ 5 files changed, 34 insertions(+), 13 deletions(-) rename React/{Modules => CoreModules}/RCTDeviceInfo.h (100%) rename React/{Modules/RCTDeviceInfo.m => CoreModules/RCTDeviceInfo.mm} (88%) diff --git a/React/CoreModules/BUCK b/React/CoreModules/BUCK index 2fa8a4b5b16060..dfd93ea49631ea 100644 --- a/React/CoreModules/BUCK +++ b/React/CoreModules/BUCK @@ -38,8 +38,12 @@ rn_apple_library( ["-D PIC_MODIFIER=@PLT"], )], plugins = react_module_plugin_providers( - name = "ExceptionsManager", - native_class_func = "RCTExceptionsManagerCls", + name = "DeviceInfo", + native_class_func = "RCTDeviceInfoCls", + ) + + react_module_plugin_providers( + name = "ExceptionsManager", + native_class_func = "RCTExceptionsManagerCls", ) + react_module_plugin_providers( name = "ImageLoader", diff --git a/React/CoreModules/CoreModulesPlugins.h b/React/CoreModules/CoreModulesPlugins.h index 4fc55c0a140637..8d49aaf456f183 100644 --- a/React/CoreModules/CoreModulesPlugins.h +++ b/React/CoreModules/CoreModulesPlugins.h @@ -29,6 +29,7 @@ extern "C" { Class RCTCoreModulesClassProvider(const char *name); // Lookup functions +Class RCTDeviceInfoCls(void); Class RCTExceptionsManagerCls(void); Class RCTImageLoaderCls(void); Class RCTPlatformCls(void); diff --git a/React/CoreModules/CoreModulesPlugins.mm b/React/CoreModules/CoreModulesPlugins.mm index a404596d2d9946..4b7a90103c99c7 100644 --- a/React/CoreModules/CoreModulesPlugins.mm +++ b/React/CoreModules/CoreModulesPlugins.mm @@ -17,7 +17,8 @@ #import static std::unordered_map sCoreModuleClassMap = { - {"ExceptionsManager", RCTExceptionsManagerCls}, + {"DeviceInfo", RCTDeviceInfoCls}, +{"ExceptionsManager", RCTExceptionsManagerCls}, {"ImageLoader", RCTImageLoaderCls}, {"PlatformConstants", RCTPlatformCls}, }; diff --git a/React/Modules/RCTDeviceInfo.h b/React/CoreModules/RCTDeviceInfo.h similarity index 100% rename from React/Modules/RCTDeviceInfo.h rename to React/CoreModules/RCTDeviceInfo.h diff --git a/React/Modules/RCTDeviceInfo.m b/React/CoreModules/RCTDeviceInfo.mm similarity index 88% rename from React/Modules/RCTDeviceInfo.m rename to React/CoreModules/RCTDeviceInfo.mm index 940a1076ac02b3..063458143950c7 100644 --- a/React/Modules/RCTDeviceInfo.m +++ b/React/CoreModules/RCTDeviceInfo.mm @@ -7,11 +7,19 @@ #import "RCTDeviceInfo.h" -#import "RCTAccessibilityManager.h" -#import "RCTAssert.h" -#import "RCTEventDispatcher.h" -#import "RCTUIUtils.h" -#import "RCTUtils.h" +#import +#import +#import +#import +#import +#import + +#import "CoreModulesPlugins.h" + +using namespace facebook::react; + +@interface RCTDeviceInfo () +@end @implementation RCTDeviceInfo { #if !TARGET_OS_TV @@ -83,16 +91,15 @@ static BOOL RCTIsIPhoneX() { static NSDictionary *RCTExportedDimensions(RCTBridge *bridge) { RCTAssertMainQueue(); - RCTDimensions dimensions = RCTGetDimensions(bridge.accessibilityManager.multiplier); - typeof (dimensions.window) window = dimensions.window; + __typeof (dimensions.window) window = dimensions.window; NSDictionary *dimsWindow = @{ @"width": @(window.width), @"height": @(window.height), @"scale": @(window.scale), @"fontScale": @(window.fontScale) }; - typeof (dimensions.screen) screen = dimensions.screen; + __typeof(dimensions.screen) screen = dimensions.screen; NSDictionary *dimsScreen = @{ @"width": @(screen.width), @"height": @(screen.height), @@ -152,7 +159,7 @@ - (void)didReceiveNewContentSizeMultiplier - (void)interfaceOrientationDidChange { - __weak typeof(self) weakSelf = self; + __weak __typeof(self) weakSelf = self; RCTExecuteOnMainQueue(^{ [weakSelf _interfaceOrientationDidChange]; }); @@ -181,7 +188,7 @@ - (void)_interfaceOrientationDidChange - (void)interfaceFrameDidChange { - __weak typeof(self) weakSelf = self; + __weak __typeof(self) weakSelf = self; RCTExecuteOnMainQueue(^{ [weakSelf _interfaceFrameDidChange]; }); @@ -205,5 +212,13 @@ - (void)_interfaceFrameDidChange #endif // TARGET_OS_TV +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(self, jsInvoker); +} @end + +Class RCTDeviceInfoCls(void) { + return RCTDeviceInfo.class; +} From d8e335df0e9148d5bcfd865cdbe6e33c1106709f Mon Sep 17 00:00:00 2001 From: Anatolii Shevchenko Date: Wed, 21 Aug 2019 15:46:45 -0700 Subject: [PATCH 0031/1244] Remove ; from method implementation definition Summary: Removing excessive semicolon ";" symbol from method implementation definition. Reviewed By: adamjernst Differential Revision: D16912006 fbshipit-source-id: 9c3e778a107e8fd0055f40a95ea9ca58d461e1c5 --- .../Drivers/RCTDecayAnimation.m | 2 +- .../Drivers/RCTFrameAnimation.m | 2 +- .../Nodes/RCTPropsAnimatedNode.m | 2 +- .../Nodes/RCTStyleAnimatedNode.m | 2 +- .../Nodes/RCTTransformAnimatedNode.m | 2 +- Libraries/WebSocket/RCTSRWebSocket.m | 104 +++++++++--------- .../FBSnapshotTestController.m | 2 +- React/CxxBridge/RCTCxxBridge.mm | 2 +- React/CxxModule/RCTCxxModule.mm | 4 +- React/Fabric/RCTScheduler.mm | 2 +- React/Modules/RCTUIManager.m | 2 +- 11 files changed, 63 insertions(+), 63 deletions(-) diff --git a/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m b/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m index ca35c7d31466ee..63003a01728276 100644 --- a/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m +++ b/Libraries/NativeAnimation/Drivers/RCTDecayAnimation.m @@ -37,7 +37,7 @@ @implementation RCTDecayAnimation - (instancetype)initWithId:(NSNumber *)animationId config:(NSDictionary *)config forNode:(RCTValueAnimatedNode *)valueNode - callBack:(nullable RCTResponseSenderBlock)callback; + callBack:(nullable RCTResponseSenderBlock)callback { if ((self = [super init])) { _callback = [callback copy]; diff --git a/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m b/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m index 3fd8d33ac76daf..d7d6f804d66395 100644 --- a/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m +++ b/Libraries/NativeAnimation/Drivers/RCTFrameAnimation.m @@ -40,7 +40,7 @@ @implementation RCTFrameAnimation - (instancetype)initWithId:(NSNumber *)animationId config:(NSDictionary *)config forNode:(RCTValueAnimatedNode *)valueNode - callBack:(nullable RCTResponseSenderBlock)callback; + callBack:(nullable RCTResponseSenderBlock)callback { if ((self = [super init])) { _animationId = animationId; diff --git a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m index 3469d941026fb3..29937431cd5630 100644 --- a/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTPropsAnimatedNode.m @@ -28,7 +28,7 @@ @implementation RCTPropsAnimatedNode } - (instancetype)initWithTag:(NSNumber *)tag - config:(NSDictionary *)config; + config:(NSDictionary *)config { if (self = [super initWithTag:tag config:config]) { _propsDictionary = [NSMutableDictionary new]; diff --git a/Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m index 39385726716bce..accce5ee44cbb0 100644 --- a/Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTStyleAnimatedNode.m @@ -16,7 +16,7 @@ @implementation RCTStyleAnimatedNode } - (instancetype)initWithTag:(NSNumber *)tag - config:(NSDictionary *)config; + config:(NSDictionary *)config { if ((self = [super initWithTag:tag config:config])) { _propsDictionary = [NSMutableDictionary new]; diff --git a/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m b/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m index 5d1e0889473154..8daaae06c3a7cd 100644 --- a/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m +++ b/Libraries/NativeAnimation/Nodes/RCTTransformAnimatedNode.m @@ -14,7 +14,7 @@ @implementation RCTTransformAnimatedNode } - (instancetype)initWithTag:(NSNumber *)tag - config:(NSDictionary *)config; + config:(NSDictionary *)config { if ((self = [super initWithTag:tag config:config])) { _propsDictionary = [NSMutableDictionary new]; diff --git a/Libraries/WebSocket/RCTSRWebSocket.m b/Libraries/WebSocket/RCTSRWebSocket.m index a134d2e0dd010b..fc88b283c8bc48 100644 --- a/Libraries/WebSocket/RCTSRWebSocket.m +++ b/Libraries/WebSocket/RCTSRWebSocket.m @@ -115,7 +115,7 @@ @interface _RCTSRRunLoopThread : NSThread @implementation NSData (RCTSRWebSocket) -- (NSString *)stringBySHA1ThenBase64Encoding; +- (NSString *)stringBySHA1ThenBase64Encoding { return newSHA1String(self.bytes, self.length); } @@ -125,7 +125,7 @@ - (NSString *)stringBySHA1ThenBase64Encoding; @implementation NSString (RCTSRWebSocket) -- (NSString *)stringBySHA1ThenBase64Encoding; +- (NSString *)stringBySHA1ThenBase64Encoding { return newSHA1String(self.UTF8String, self.length); } @@ -248,17 +248,17 @@ - (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols; +- (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray *)protocols { NSMutableURLRequest *request; if (URL) { @@ -280,7 +280,7 @@ - (instancetype)initWithURL:(NSURL *)URL protocols:(NSArray *)protoc return [self initWithURLRequest:request protocols:protocols]; } -- (void)_RCTSR_commonInit; +- (void)_RCTSR_commonInit { NSString *scheme = _url.scheme.lowercaseString; assert([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]); @@ -316,7 +316,7 @@ - (void)_RCTSR_commonInit; // default handlers } -- (void)assertOnWorkQueue; +- (void)assertOnWorkQueue { assert(dispatch_get_specific((__bridge void *)self) == (__bridge void *)_workQueue); } @@ -337,7 +337,7 @@ - (void)dealloc #ifndef NDEBUG -- (void)setReadyState:(RCTSRReadyState)aReadyState; +- (void)setReadyState:(RCTSRReadyState)aReadyState { [self willChangeValueForKey:@"readyState"]; assert(aReadyState > _readyState); @@ -347,7 +347,7 @@ - (void)setReadyState:(RCTSRReadyState)aReadyState; #endif -- (void)open; +- (void)open { assert(_url); RCTAssert(_readyState == RCTSR_CONNECTING, @"Cannot call -(void)open on RCTSRWebSocket more than once"); @@ -358,7 +358,7 @@ - (void)open; } // Calls block on delegate queue -- (void)_performDelegateBlock:(dispatch_block_t)block; +- (void)_performDelegateBlock:(dispatch_block_t)block { if (_delegateOperationQueue) { [_delegateOperationQueue addOperationWithBlock:block]; @@ -368,12 +368,12 @@ - (void)_performDelegateBlock:(dispatch_block_t)block; } } -- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue; +- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue { _delegateDispatchQueue = queue; } -- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; +- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage { NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept"))); @@ -387,7 +387,7 @@ - (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage; return [acceptHeader isEqualToString:expectedAccept]; } -- (void)_HTTPHeadersDidFinish; +- (void)_HTTPHeadersDidFinish { NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders); @@ -426,7 +426,7 @@ - (void)_HTTPHeadersDidFinish; }]; } -- (void)_readHTTPHeader; +- (void)_readHTTPHeader { if (_receivedHTTPHeaders == NULL) { _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO); @@ -481,7 +481,7 @@ - (void)didConnect [self _readHTTPHeader]; } -- (void)_initializeStreams; +- (void)_initializeStreams { assert(_url.port.unsignedIntValue <= UINT32_MAX); uint32_t port = _url.port.unsignedIntValue; @@ -526,7 +526,7 @@ - (void)_initializeStreams; _outputStream.delegate = self; } -- (void)_connect; +- (void)_connect { if (!_scheduledRunloops.count) { [self scheduleInRunLoop:[NSRunLoop RCTSR_networkRunLoop] forMode:NSDefaultRunLoopMode]; @@ -536,7 +536,7 @@ - (void)_connect; [_inputStream open]; } -- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { [_outputStream scheduleInRunLoop:aRunLoop forMode:mode]; [_inputStream scheduleInRunLoop:aRunLoop forMode:mode]; @@ -544,7 +544,7 @@ - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; [_scheduledRunloops addObject:@[aRunLoop, mode]]; } -- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; +- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode { [_outputStream removeFromRunLoop:aRunLoop forMode:mode]; [_inputStream removeFromRunLoop:aRunLoop forMode:mode]; @@ -552,12 +552,12 @@ - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; [_scheduledRunloops removeObject:@[aRunLoop, mode]]; } -- (void)close; +- (void)close { [self closeWithCode:RCTSRStatusCodeNormal reason:nil]; } -- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; +- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason { assert(code); dispatch_async(_workQueue, ^{ @@ -601,7 +601,7 @@ - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason; }); } -- (void)_closeWithProtocolError:(NSString *)message; +- (void)_closeWithProtocolError:(NSString *)message { // Need to shunt this on the _callbackQueue first to see if they received any messages [self _performDelegateBlock:^{ @@ -612,7 +612,7 @@ - (void)_closeWithProtocolError:(NSString *)message; }]; } -- (void)_failWithError:(NSError *)error; +- (void)_failWithError:(NSError *)error { dispatch_async(_workQueue, ^{ if (self.readyState != RCTSR_CLOSED) { @@ -633,7 +633,7 @@ - (void)_failWithError:(NSError *)error; }); } -- (void)_writeData:(NSData *)data; +- (void)_writeData:(NSData *)data { [self assertOnWorkQueue]; @@ -644,7 +644,7 @@ - (void)_writeData:(NSData *)data; [self _pumpWriting]; } -- (void)send:(id)data; +- (void)send:(id)data { RCTAssert(self.readyState != RCTSR_CONNECTING, @"Invalid State: Cannot call send: until connection is open"); if (nil == data) { @@ -663,7 +663,7 @@ - (void)send:(id)data; }); } -- (void)sendPing:(NSData *)data; +- (void)sendPing:(NSData *)data { RCTAssert(self.readyState == RCTSR_OPEN, @"Invalid State: Cannot call send: until connection is open"); // TODO: maybe not copy this for performance @@ -673,7 +673,7 @@ - (void)sendPing:(NSData *)data; }); } -- (void)handlePing:(NSData *)pingData; +- (void)handlePing:(NSData *)pingData { // Need to pingpong this off _callbackQueue first to make sure messages happen in order [self _performDelegateBlock:^{ @@ -683,7 +683,7 @@ - (void)handlePing:(NSData *)pingData; }]; } -- (void)handlePong:(NSData *)pongData; +- (void)handlePong:(NSData *)pongData { RCTSRLog(@"Received pong"); [self _performDelegateBlock:^{ @@ -736,7 +736,7 @@ static inline BOOL closeCodeIsValid(int closeCode) // encoded data with value /reason/, the interpretation of which is not // defined by this specification. -- (void)handleCloseWithData:(NSData *)data; +- (void)handleCloseWithData:(NSData *)data { size_t dataSize = data.length; __block uint16_t closeCode = 0; @@ -775,7 +775,7 @@ - (void)handleCloseWithData:(NSData *)data; }); } -- (void)_disconnect; +- (void)_disconnect { [self assertOnWorkQueue]; RCTSRLog(@"Trying to disconnect"); @@ -783,7 +783,7 @@ - (void)_disconnect; [self _pumpWriting]; } -- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; +- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode { // Check that the current data is valid UTF8 @@ -829,7 +829,7 @@ - (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode; } } -- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; +- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData { assert(frame_header.opcode != 0); @@ -911,7 +911,7 @@ - (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData; static const uint8_t RCTSRMaskMask = 0x80; static const uint8_t RCTSRPayloadLenMask = 0x7F; -- (void)_readFrameContinue; +- (void)_readFrameContinue { assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0)); @@ -994,7 +994,7 @@ - (void)_readFrameContinue; } readToCurrentFrame:NO unmaskBytes:NO]; } -- (void)_readFrameNew; +- (void)_readFrameNew { dispatch_async(_workQueue, ^{ self->_currentFrameData.length = 0; @@ -1008,7 +1008,7 @@ - (void)_readFrameNew; }); } -- (void)_pumpWriting; +- (void)_pumpWriting { [self assertOnWorkQueue]; @@ -1047,13 +1047,13 @@ - (void)_pumpWriting; } } -- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback { [self assertOnWorkQueue]; [self _addConsumerWithScanner:consumer callback:callback dataLength:0]; } -- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes { [self assertOnWorkQueue]; assert(dataLength); @@ -1062,7 +1062,7 @@ - (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)ca [self _pumpScanner]; } -- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength; +- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength { [self assertOnWorkQueue]; [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]]; @@ -1071,12 +1071,12 @@ - (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'}; -- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler; +- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler { [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler]; } -- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler; +- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler { // TODO: optimize so this can continue from where we last searched stream_scanner consumer = ^size_t(NSData *data) { @@ -1207,7 +1207,7 @@ - (BOOL)_innerPumpScanner return didWork; } -- (void)_pumpScanner; +- (void)_pumpScanner { [self assertOnWorkQueue]; @@ -1226,7 +1226,7 @@ - (void)_pumpScanner; static const size_t RCTSRFrameHeaderOverhead = 32; -- (void)_sendFrameWithOpcode:(RCTSROpCode)opcode data:(NSData *)data; +- (void)_sendFrameWithOpcode:(RCTSROpCode)opcode data:(NSData *)data { [self assertOnWorkQueue]; @@ -1296,7 +1296,7 @@ - (void)_sendFrameWithOpcode:(RCTSROpCode)opcode data:(NSData *)data; [self _writeData:frame]; } -- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode; +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode { if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) { NSArray *sslCerts = _urlRequest.RCTSR_SSLPinnedCertificates; @@ -1471,7 +1471,7 @@ - (void)_cleanupSelfReference:(NSTimer *)timer @implementation RCTSRIOConsumer -- (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes { _consumer = [scanner copy]; _handler = [handler copy]; @@ -1489,7 +1489,7 @@ @implementation RCTSRIOConsumerPool NSMutableArray *_bufferedConsumers; } -- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize; +- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize { if ((self = [super init])) { _poolSize = poolSize; @@ -1503,7 +1503,7 @@ - (instancetype)init return [self initWithBufferCapacity:8]; } -- (RCTSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes; +- (RCTSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes { RCTSRIOConsumer *consumer = nil; if (_bufferedConsumers.count) { @@ -1518,7 +1518,7 @@ - (RCTSRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_c return consumer; } -- (void)returnConsumer:(RCTSRIOConsumer *)consumer; +- (void)returnConsumer:(RCTSRIOConsumer *)consumer { if (_bufferedConsumers.count < _poolSize) { [_bufferedConsumers addObject:consumer]; @@ -1529,7 +1529,7 @@ - (void)returnConsumer:(RCTSRIOConsumer *)consumer; @implementation NSURLRequest (CertificateAdditions) -- (NSArray *)RCTSR_SSLPinnedCertificates; +- (NSArray *)RCTSR_SSLPinnedCertificates { return [NSURLProtocol propertyForKey:@"RCTSR_SSLPinnedCertificates" inRequest:self]; } @@ -1538,12 +1538,12 @@ - (NSArray *)RCTSR_SSLPinnedCertificates; @implementation NSMutableURLRequest (CertificateAdditions) -- (NSArray *)RCTSR_SSLPinnedCertificates; +- (NSArray *)RCTSR_SSLPinnedCertificates { return [NSURLProtocol propertyForKey:@"RCTSR_SSLPinnedCertificates" inRequest:self]; } -- (void)setRCTSR_SSLPinnedCertificates:(NSArray *)RCTSR_SSLPinnedCertificates; +- (void)setRCTSR_SSLPinnedCertificates:(NSArray *)RCTSR_SSLPinnedCertificates { [NSURLProtocol setProperty:RCTSR_SSLPinnedCertificates forKey:@"RCTSR_SSLPinnedCertificates" inRequest:self]; } @@ -1552,7 +1552,7 @@ - (void)setRCTSR_SSLPinnedCertificates:(NSArray *)RCTSR_SSLPinnedCertificates; @implementation NSURL (RCTSRWebSocket) -- (NSString *)RCTSR_origin; +- (NSString *)RCTSR_origin { NSString *scheme = self.scheme.lowercaseString; @@ -1611,7 +1611,7 @@ - (instancetype)init return self; } -- (void)main; +- (void)main { @autoreleasepool { _runLoop = [NSRunLoop currentRunLoop]; @@ -1630,7 +1630,7 @@ - (void)step // Does nothing } -- (NSRunLoop *)runLoop; +- (NSRunLoop *)runLoop { dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER); return _runLoop; diff --git a/RNTester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m b/RNTester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m index ac66a147c688d2..b50da2b3589cbe 100644 --- a/RNTester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m +++ b/RNTester/RCTTest/FBSnapshotTestCase/FBSnapshotTestController.m @@ -39,7 +39,7 @@ @implementation FBSnapshotTestController #pragma mark - Lifecycle -- (instancetype)initWithTestClass:(Class)testClass; +- (instancetype)initWithTestClass:(Class)testClass { return [self initWithTestName:NSStringFromClass(testClass)]; } diff --git a/React/CxxBridge/RCTCxxBridge.mm b/React/CxxBridge/RCTCxxBridge.mm index bd48f44f3f564f..5cb522237d7201 100644 --- a/React/CxxBridge/RCTCxxBridge.mm +++ b/React/CxxBridge/RCTCxxBridge.mm @@ -598,7 +598,7 @@ - (void)_initializeBridgeLocked:(std::shared_ptr)executorFact _moduleRegistryCreated = YES; } -- (void)updateModuleWithInstance:(id)instance; +- (void)updateModuleWithInstance:(id)instance { NSString *const moduleName = RCTBridgeModuleNameForClass([instance class]); if (moduleName) { diff --git a/React/CxxModule/RCTCxxModule.mm b/React/CxxModule/RCTCxxModule.mm index 95891da8198b0f..85532c90432677 100644 --- a/React/CxxModule/RCTCxxModule.mm +++ b/React/CxxModule/RCTCxxModule.mm @@ -50,7 +50,7 @@ - (void)lazyInit return nullptr; } -- (NSArray> *)methodsToExport; +- (NSArray> *)methodsToExport { [self lazyInit]; if (!_module) { @@ -69,7 +69,7 @@ - (void)lazyInit return [self getConstants]; } -- (NSDictionary *)getConstants; +- (NSDictionary *)getConstants { [self lazyInit]; if (!_module) { diff --git a/React/Fabric/RCTScheduler.mm b/React/Fabric/RCTScheduler.mm index 2bd27b7663b2c3..2b9dc69c02246b 100644 --- a/React/Fabric/RCTScheduler.mm +++ b/React/Fabric/RCTScheduler.mm @@ -85,7 +85,7 @@ - (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId moduleName:(NSString *)moduleName initialProps:(NSDictionary *)initialProps layoutConstraints:(LayoutConstraints)layoutConstraints - layoutContext:(LayoutContext)layoutContext; + layoutContext:(LayoutContext)layoutContext { SystraceSection s("-[RCTScheduler startSurfaceWithSurfaceId:...]"); diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 7e3a67b485cb0e..f2bddbf64608a9 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1137,7 +1137,7 @@ - (void)_layoutAndMount }]; } -- (void)flushUIBlocksWithCompletion:(void (^)(void))completion; +- (void)flushUIBlocksWithCompletion:(void (^)(void))completion { RCTAssertUIManagerQueue(); From 80f64f1e5bddad6e4df88efa4c28e09db7462d04 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 21 Aug 2019 16:09:36 -0700 Subject: [PATCH 0032/1244] Ensure ImageLoader is lazily loaded as necessary Summary: In D16805827, I moved ImageLoader to CoreModules. In the process, I migrated usages of `[_bridge moduleForClass:[RCTImageLoader class]]` to `[_bridge moduleForName:@"ImageLoader"]`. These two APIs aren't equivalent, however, since `[_bridge moduleForClass:[RCTImageLoader class]]` by default lazily loads the requested NativeModule, but `[_bridge moduleForName:@"ImageLoader"]` doesn't. So, I had to explicitly set `lazilyLoadIfNecessary` to `YES` in all the call-sites I migrated, to ensure that ImageLoader is correctly initialized when necessary. Reviewed By: PeteTheHeat Differential Revision: D16948165 fbshipit-source-id: 434697637dfa5e32de1c398744f9c28c19a6fd94 --- Libraries/Image/RCTImageView.m | 2 +- Libraries/Image/RCTImageViewManager.m | 6 +++--- React/CoreModules/RCTImageEditingManager.m | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index 7d11a88ae0a161..b0c8050fcece54 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -326,7 +326,7 @@ - (void)reloadImage }; _reloadImageCancellationBlock = - [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:source.request + [[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:source.request size:imageSize scale:imageScale clipped:NO diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m index 3ba8c7817ef222..877ad45d252fa2 100644 --- a/Libraries/Image/RCTImageViewManager.m +++ b/Libraries/Image/RCTImageViewManager.m @@ -54,7 +54,7 @@ - (UIView *)view successBlock:(RCTResponseSenderBlock)successBlock errorBlock:(RCTResponseErrorBlock)errorBlock) { - [[self.bridge moduleForName:@"ImageLoader"] + [[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] getImageSizeForURLRequest:request block:^(NSError *error, CGSize size) { if (error) { @@ -69,7 +69,7 @@ - (UIView *)view resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [[self.bridge moduleForName:@"ImageLoader"] + [[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] getImageSizeForURLRequest:source.request block:^(NSError *error, CGSize size) { if (error) { @@ -89,7 +89,7 @@ - (UIView *)view return; } - [[self.bridge moduleForName:@"ImageLoader"] + [[self.bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:request callback:^(NSError *error, UIImage *image) { if (error) { diff --git a/React/CoreModules/RCTImageEditingManager.m b/React/CoreModules/RCTImageEditingManager.m index 6ff5f19d80e81b..8d88390e04b5f9 100644 --- a/React/CoreModules/RCTImageEditingManager.m +++ b/React/CoreModules/RCTImageEditingManager.m @@ -43,7 +43,7 @@ @implementation RCTImageEditingManager [RCTConvert CGSize:cropData[@"size"]] }; - [[_bridge moduleForName:@"ImageLoader"] + [[_bridge moduleForName:@"ImageLoader" lazilyLoadIfNecessary:YES] loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) { if (error) { errorCallback(error); From 2dbf42b4a3285c16fed7955e1e3d9bc770e85f61 Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 21 Aug 2019 18:05:29 -0700 Subject: [PATCH 0033/1244] Bump eslint-plugin-react-hooks to 2.0.1 Summary: This catches some errors about hooks being used at the top level in a module Reviewed By: gaearon Differential Revision: D16945591 fbshipit-source-id: 116ed24b4394b1f516a2ebcd75977d2ba5c57afb --- package.json | 2 +- .../eslint-config-react-native-community/package.json | 2 +- packages/eslint-config-react-native-community/yarn.lock | 8 ++++---- yarn.lock | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index dbf9492bc12a4e..f96e75c0c9963b 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "eslint-plugin-jsx-a11y": "6.2.1", "eslint-plugin-prettier": "2.6.2", "eslint-plugin-react": "7.12.4", - "eslint-plugin-react-hooks": "^1.5.1", + "eslint-plugin-react-hooks": "^2.0.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", "flow-bin": "^0.105.0", diff --git a/packages/eslint-config-react-native-community/package.json b/packages/eslint-config-react-native-community/package.json index dac34819bfabed..b5bfce9d52c22c 100644 --- a/packages/eslint-config-react-native-community/package.json +++ b/packages/eslint-config-react-native-community/package.json @@ -17,7 +17,7 @@ "eslint-plugin-jest": "22.4.1", "eslint-plugin-prettier": "2.6.2", "eslint-plugin-react": "7.12.4", - "eslint-plugin-react-hooks": "^1.5.1", + "eslint-plugin-react-hooks": "^2.0.1", "eslint-plugin-react-native": "3.7.0", "prettier": "1.17.0" }, diff --git a/packages/eslint-config-react-native-community/yarn.lock b/packages/eslint-config-react-native-community/yarn.lock index 91d69102ca5fa1..0ff1ee7478b3aa 100644 --- a/packages/eslint-config-react-native-community/yarn.lock +++ b/packages/eslint-config-react-native-community/yarn.lock @@ -362,10 +362,10 @@ eslint-plugin-prettier@2.6.2: fast-diff "^1.1.1" jest-docblock "^21.0.0" -eslint-plugin-react-hooks@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.5.1.tgz#3c601326914ee0e1fedd709115db4940bdbbed4a" - integrity sha512-i3dIrmZ+Ssrm0LrbbtuGcRf7EEpe1FaMuL8XnnpZO0X4tk3dZNzevWxD0/7nMAFa5yZQfNnYkfEP0MmwLvbdHw== +eslint-plugin-react-hooks@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.0.1.tgz#e898ec26a0a335af6f7b0ad1f0bedda7143ed756" + integrity sha512-xir+3KHKo86AasxlCV8AHRtIZPHljqCRRUYgASkbatmt0fad4+5GgC7zkT7o/06hdKM6MIwp8giHVXqBPaarHQ== eslint-plugin-react-native-globals@^0.1.1: version "0.1.2" diff --git a/yarn.lock b/yarn.lock index f614535e841f41..5341dc1fee9f23 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2692,10 +2692,10 @@ eslint-plugin-prettier@2.6.2: fast-diff "^1.1.1" jest-docblock "^21.0.0" -eslint-plugin-react-hooks@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.5.1.tgz#3c601326914ee0e1fedd709115db4940bdbbed4a" - integrity sha512-i3dIrmZ+Ssrm0LrbbtuGcRf7EEpe1FaMuL8XnnpZO0X4tk3dZNzevWxD0/7nMAFa5yZQfNnYkfEP0MmwLvbdHw== +eslint-plugin-react-hooks@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-2.0.1.tgz#e898ec26a0a335af6f7b0ad1f0bedda7143ed756" + integrity sha512-xir+3KHKo86AasxlCV8AHRtIZPHljqCRRUYgASkbatmt0fad4+5GgC7zkT7o/06hdKM6MIwp8giHVXqBPaarHQ== eslint-plugin-react-native-globals@^0.1.1: version "0.1.2" From 17381f197fd9f6f955ff8018b3e1288d1c78b743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Osadnik?= Date: Wed, 21 Aug 2019 18:10:28 -0700 Subject: [PATCH 0034/1244] Add tests for comparing old and new codegen Summary: add script which proves that new codegen gives a similar code as old one. How it works? While creating a rule, it generates file which is bash script returning 1 or 0 depending if result of new and old codegen are the same (it's done by redirecting output of buck's cmd). How js script works: 1. remove empty lines 2. remove comments 3. remove imports 4. sort lines (cause order of structs might be different so let's sort everything!) 5. remove namespaces (I grouped them in new codegen) Reviewed By: RSNara Differential Revision: D16827988 fbshipit-source-id: 0432144161e2dcf8ed4cbe2eeea712d062e3721d --- packages/react-native-codegen/BUCK | 17 ++++++ .../verify_all_modules_with_old_codegen.sh | 5 ++ .../src/cli/verify_with_old_codegen.js | 54 +++++++++++++++++++ .../src/cli/verify_with_old_codegen.sh | 14 +++++ 4 files changed, 90 insertions(+) create mode 100755 packages/react-native-codegen/src/cli/verify_all_modules_with_old_codegen.sh create mode 100755 packages/react-native-codegen/src/cli/verify_with_old_codegen.js create mode 100755 packages/react-native-codegen/src/cli/verify_with_old_codegen.sh diff --git a/packages/react-native-codegen/BUCK b/packages/react-native-codegen/BUCK index 660a166fb081b8..8073ebb8baa25e 100644 --- a/packages/react-native-codegen/BUCK +++ b/packages/react-native-codegen/BUCK @@ -6,6 +6,23 @@ load("@fbsource//tools/build_defs/third_party:yarn_defs.bzl", "yarn_workspace") load("@fbsource//xplat/js/react-native-github/packages/react-native-codegen:DEFS.bzl", "rn_codegen_components", "rn_codegen_modules") load("//tools/build_defs/oss:rn_defs.bzl", "react_native_target") +fb_native.sh_binary( + name = "codegen_rn_modules_tests", + main = "src/cli/verify_with_old_codegen.sh", + visibility = ["PUBLIC"], + resources = [ + "fbsource//xplat/js:setup_env", + "src/cli/verify_with_old_codegen.js", + "src/cli/verify_with_old_codegen.sh", + ], +) + +fb_native.sh_test( + name = "verify_all_modules_with_old_codegen", + test = "src/cli/verify_all_modules_with_old_codegen.sh", + visibility = ["PUBLIC"], +) + fb_native.sh_binary( name = "write_to_json", main = "src/cli/combine/combine_js_to_schema.sh", diff --git a/packages/react-native-codegen/src/cli/verify_all_modules_with_old_codegen.sh b/packages/react-native-codegen/src/cli/verify_all_modules_with_old_codegen.sh new file mode 100755 index 00000000000000..613fd137ba4f4d --- /dev/null +++ b/packages/react-native-codegen/src/cli/verify_all_modules_with_old_codegen.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -e +set -u + +exec buck query "filter('generated_objcpp_modules_tests_', '//xplat/js/...')" | xargs buck build diff --git a/packages/react-native-codegen/src/cli/verify_with_old_codegen.js b/packages/react-native-codegen/src/cli/verify_with_old_codegen.js new file mode 100755 index 00000000000000..17665c1613cfe4 --- /dev/null +++ b/packages/react-native-codegen/src/cli/verify_with_old_codegen.js @@ -0,0 +1,54 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + * @format + */ + +'use strict'; + +const fs = require('fs'); +const [first, second] = process.argv.slice(2); + +const contents1 = fs.readFileSync(first, 'utf8'); +const contents2 = fs.readFileSync(second, 'utf8'); + +function traverse(t) { + return t + .replace(/\).invoke/g, ')\n.invoke') // in old codegen it was in one line + .split('\n') + .map(l => l.trim()) // no whitespaces + .filter(Boolean) // no empty lines + .filter( + l => + !l.startsWith('namespace') && // no namespaces + !l.startsWith('}') && // after removing openign namespaces we need to remove all closings + !l.startsWith('/**') && // all comments + !l.startsWith('#') && // imports + !l.startsWith('//') && // comments + !l.startsWith('importing it, you must change') && // comment in old codegen + !l.startsWith('*'), //comments + ) + .map(l => l.replace(/ /g, '')) // remove rest whitespaces + .sort(); // sort alphabetically lines +} + +const t1 = traverse(contents1); +const t2 = traverse(contents2); + +if (t1.length !== t2.length) { + throw new Error('Old and new codegen produces output of different size'); +} else { + for (let i = 0; i < t1.length; i++) { + if (t1[i] !== t2[i]) { + throw new Error( + `Old and new codegen does not produce similar output! ${i} ${ + t1[i] + } | ${t2[i]}`, + ); + } + } +} diff --git a/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh b/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh new file mode 100755 index 00000000000000..28f885fac870e4 --- /dev/null +++ b/packages/react-native-codegen/src/cli/verify_with_old_codegen.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e +set -u + +THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) + +# shellcheck source=xplat/js/env-utils/setup_env_vars.sh +source "$THIS_DIR/../../../../../env-utils/setup_env_vars.sh" + +pushd "$THIS_DIR/../.." >/dev/null + "$INSTALL_NODE_MODULES" +popd >/dev/null + +exec "$FLOW_NODE_BINARY" "$THIS_DIR/verify_with_old_codegen.js" "$@" From bc4825ee9d49d7c8044bd08ec3ca49050435e17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 21 Aug 2019 19:00:41 -0700 Subject: [PATCH 0035/1244] Fix typing for ProgressBarAndroid Summary: `ProgressBarAndroid` exported the wrong type and Flow wasn't catching some issues with it because they were hidden by a `$FlowFixMe` annotation. This exports the right type and fixes the bad usages. Differential Revision: D16938853 fbshipit-source-id: 7ea4bbf379a010a76dc68ccb405e1f890d7e590a --- .../Components/ActivityIndicator/ActivityIndicator.js | 1 + .../ProgressBarAndroid/ProgressBarAndroid.android.js | 2 +- .../__tests__/ProgressBarAndroid-test.js | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index df6cd3c5cc1b90..2eed90d8de1fd2 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -109,6 +109,7 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => { // $FlowFixMe Flow doesn't know when this is the android component ) : ( + // $FlowFixMe Flow doesn't know when this is the iOS component )} diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js index 7f80aeb339222a..cb1d0dbc065d63 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js @@ -100,4 +100,4 @@ ProgressBarAndroidToExport.defaultProps = { /* $FlowFixMe(>=0.89.0 site=react_native_android_fb) This comment suppresses an * error found when Flow v0.89 was deployed. To see the error, delete this * comment and run Flow. */ -module.exports = (ProgressBarAndroidToExport: ProgressBarAndroidNativeComponent); +module.exports = (ProgressBarAndroidToExport: typeof ProgressBarAndroidNativeComponent); diff --git a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js index ccce645eb49aa5..c2463d96d44d16 100644 --- a/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js +++ b/Libraries/Components/ProgressBarAndroid/__tests__/ProgressBarAndroid-test.js @@ -22,14 +22,14 @@ const render = require('../../../../jest/renderer'); describe('', () => { it('should render as when mocked', () => { const instance = render.create( - , + , ); expect(instance).toMatchSnapshot(); }); it('should shallow render as when mocked', () => { const output = render.shallow( - , + , ); expect(output).toMatchSnapshot(); }); @@ -38,7 +38,7 @@ describe('', () => { jest.dontMock('../ProgressBarAndroid'); const output = render.shallow( - , + , ); expect(output).toMatchSnapshot(); }); @@ -47,7 +47,7 @@ describe('', () => { jest.dontMock('../ProgressBarAndroid'); const instance = render.create( - , + , ); expect(instance).toMatchSnapshot(); }); From d2213c75ff38b517ba7656a52ec2df4ba57c807c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Norte?= Date: Wed, 21 Aug 2019 19:00:41 -0700 Subject: [PATCH 0036/1244] Define type signature for react-native-implementation Summary: Explicitly define the types of the getters in `react-native-implementation` so we can enable Flow's types-first mode for that file. Reviewed By: cpojer Differential Revision: D16937607 fbshipit-source-id: 2e4cf483043a53c5407254ffa2b3211d40211019 --- .flowconfig | 3 + .flowconfig.android | 3 + .../Components/SafeAreaView/SafeAreaView.js | 5 +- .../react-native-implementation.js | 264 ++++++++++++------ 4 files changed, 185 insertions(+), 90 deletions(-) diff --git a/.flowconfig b/.flowconfig index 0bb69582c4c96d..ec2c82e32de7bf 100644 --- a/.flowconfig +++ b/.flowconfig @@ -53,6 +53,9 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(si suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError +experimental.well_formed_exports=true +experimental.well_formed_exports.whitelist=/Libraries/react-native/react-native-implementation.js + [lints] sketchy-null-number=warn sketchy-null-mixed=warn diff --git a/.flowconfig.android b/.flowconfig.android index c57a285f5b6d33..15f63ee87cb200 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -53,6 +53,9 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(si suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError +experimental.well_formed_exports=true +experimental.well_formed_exports.whitelist=/Libraries/react-native/react-native-implementation.js + [lints] sketchy-null-number=warn sketchy-null-mixed=warn diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.js b/Libraries/Components/SafeAreaView/SafeAreaView.js index a6d7afc1b97492..9c22f7dabb1729 100644 --- a/Libraries/Components/SafeAreaView/SafeAreaView.js +++ b/Libraries/Components/SafeAreaView/SafeAreaView.js @@ -12,7 +12,6 @@ const Platform = require('../../Utilities/Platform'); const React = require('react'); const View = require('../View/View'); -import type {NativeComponent} from '../../Renderer/shims/ReactNative'; import type {ViewProps} from '../View/ViewPropTypes'; type Props = $ReadOnly<{| @@ -20,7 +19,7 @@ type Props = $ReadOnly<{| emulateUnlessSupported?: boolean, |}>; -let exported: Class> | Class>; +let exported: Class>; /** * Renders nested content and automatically applies paddings reflect the portion @@ -62,7 +61,7 @@ if (Platform.OS === 'android') { const SafeAreaViewRef = React.forwardRef(SafeAreaView); SafeAreaViewRef.displayName = 'SafeAreaView'; - exported = ((SafeAreaViewRef: any): Class>); + exported = ((SafeAreaViewRef: any): Class>); } module.exports = exported; diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 8c6f23b86b3a7f..4b186729337dd0 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -10,19 +10,106 @@ 'use strict'; +import typeof AccessibilityInfo from '../Components/AccessibilityInfo/AccessibilityInfo'; +import typeof ActivityIndicator from '../Components/ActivityIndicator/ActivityIndicator'; +import typeof ReactNativeART from '../ART/ReactNativeART'; +import typeof Button from '../Components/Button'; +import typeof CheckBox from '../Components/CheckBox/CheckBox'; +import typeof DatePickerIOS from '../Components/DatePicker/DatePickerIOS'; +import typeof DrawerLayoutAndroid from '../Components/DrawerAndroid/DrawerLayoutAndroid'; +import typeof FlatList from '../Lists/FlatList'; +import typeof Image from '../Image/Image'; +import typeof ImageBackground from '../Image/ImageBackground'; +import typeof InputAccessoryView from '../Components/TextInput/InputAccessoryView'; +import typeof KeyboardAvoidingView from '../Components/Keyboard/KeyboardAvoidingView'; +import typeof MaskedViewIOS from '../Components/MaskedView/MaskedViewIOS'; +import typeof Modal from '../Modal/Modal'; +import typeof Picker from '../Components/Picker/Picker'; +import typeof PickerIOS from '../Components/Picker/PickerIOS'; +import typeof ProgressBarAndroid from '../Components/ProgressBarAndroid/ProgressBarAndroid'; +import typeof ProgressViewIOS from '../Components/ProgressViewIOS/ProgressViewIOS'; +import typeof SafeAreaView from '../Components/SafeAreaView/SafeAreaView'; +import typeof ScrollView from '../Components/ScrollView/ScrollView'; +import typeof SectionList from '../Lists/SectionList'; +import typeof SegmentedControlIOS from '../Components/SegmentedControlIOS/SegmentedControlIOS'; +import typeof Slider from '../Components/Slider/Slider'; +import typeof Switch from '../Components/Switch/Switch'; +import typeof RefreshControl from '../Components/RefreshControl/RefreshControl'; +import typeof StatusBar from '../Components/StatusBar/StatusBar'; +import typeof Text from '../Text/Text'; +import typeof TextInput from '../Components/TextInput/TextInput'; +import typeof Touchable from '../Components/Touchable/Touchable'; +import typeof TouchableHighlight from '../Components/Touchable/TouchableHighlight'; +import typeof TouchableNativeFeedback from '../Components/Touchable/TouchableNativeFeedback'; +import typeof TouchableOpacity from '../Components/Touchable/TouchableOpacity'; +import typeof TouchableWithoutFeedback from '../Components/Touchable/TouchableWithoutFeedback'; +import typeof View from '../Components/View/View'; +import typeof VirtualizedList from '../Lists/VirtualizedList'; +import typeof VirtualizedSectionList from '../Lists/VirtualizedSectionList'; +import typeof ActionSheetIOS from '../ActionSheetIOS/ActionSheetIOS'; +import typeof Alert from '../Alert/Alert'; +import typeof Animated from '../Animated/src/Animated'; +import typeof AppRegistry from '../ReactNative/AppRegistry'; +import typeof AppState from '../AppState/AppState'; +import typeof AsyncStorage from '../Storage/AsyncStorage'; +import typeof BackHandler from '../Utilities/BackHandler'; +import typeof Clipboard from '../Components/Clipboard/Clipboard'; +import typeof DatePickerAndroid from '../Components/DatePickerAndroid/DatePickerAndroid'; +import typeof DeviceInfo from '../Utilities/DeviceInfo'; +import typeof Dimensions from '../Utilities/Dimensions'; +import typeof Easing from '../Animated/src/Easing'; +import typeof ReactNative from '../Renderer/shims/ReactNative'; +import typeof I18nManager from '../ReactNative/I18nManager'; +import typeof ImagePickerIOS from '../Image/ImagePickerIOS'; +import typeof InteractionManager from '../Interaction/InteractionManager'; +import typeof Keyboard from '../Components/Keyboard/Keyboard'; +import typeof LayoutAnimation from '../LayoutAnimation/LayoutAnimation'; +import typeof Linking from '../Linking/Linking'; +import typeof NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; +import typeof NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; +import typeof PanResponder from '../Interaction/PanResponder'; +import typeof PermissionsAndroid from '../PermissionsAndroid/PermissionsAndroid'; +import typeof PixelRatio from '../Utilities/PixelRatio'; +import typeof PushNotificationIOS from '../PushNotificationIOS/PushNotificationIOS'; +import typeof Settings from '../Settings/Settings'; +import typeof Share from '../Share/Share'; +import typeof StatusBarIOS from '../Components/StatusBar/StatusBarIOS'; +import typeof StyleSheet from '../StyleSheet/StyleSheet'; +import typeof Systrace from '../Performance/Systrace'; +import typeof TimePickerAndroid from '../Components/TimePickerAndroid/TimePickerAndroid'; +import typeof ToastAndroid from '../Components/ToastAndroid/ToastAndroid'; +import typeof * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; +import typeof TVEventHandler from '../Components/AppleTV/TVEventHandler'; +import typeof UIManager from '../ReactNative/UIManager'; +import typeof useWindowDimensions from '../Utilities/useWindowDimensions'; +import typeof UTFSequence from '../UTFSequence'; +import typeof Vibration from '../Vibration/Vibration'; +import typeof YellowBox from '../YellowBox/YellowBox'; +import typeof RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; +import typeof RCTNativeAppEventEmitter from '../EventEmitter/RCTNativeAppEventEmitter'; +import typeof NativeModules from '../BatchedBridge/NativeModules'; +import typeof Platform from '../Utilities/Platform'; +import typeof processColor from '../StyleSheet/processColor'; +import typeof requireNativeComponent from '../ReactNative/requireNativeComponent'; +import typeof RootTagContext from '../ReactNative/RootTagContext'; +import typeof DeprecatedColorPropType from '../DeprecatedPropTypes/DeprecatedColorPropType'; +import typeof DeprecatedEdgeInsetsPropType from '../DeprecatedPropTypes/DeprecatedEdgeInsetsPropType'; +import typeof DeprecatedPointPropType from '../DeprecatedPropTypes/DeprecatedPointPropType'; +import typeof DeprecatedViewPropTypes from '../DeprecatedPropTypes/DeprecatedViewPropTypes'; + const invariant = require('invariant'); const warnOnce = require('../Utilities/warnOnce'); // Export React, plus some native additions. module.exports = { // Components - get AccessibilityInfo() { + get AccessibilityInfo(): AccessibilityInfo { return require('../Components/AccessibilityInfo/AccessibilityInfo'); }, - get ActivityIndicator() { + get ActivityIndicator(): ActivityIndicator { return require('../Components/ActivityIndicator/ActivityIndicator'); }, - get ART() { + get ART(): ReactNativeART { warnOnce( 'art-moved', 'React Native ART has been extracted from react-native core and will be removed in a future release. ' + @@ -31,10 +118,10 @@ module.exports = { ); return require('../ART/ReactNativeART'); }, - get Button() { + get Button(): Button { return require('../Components/Button'); }, - get CheckBox() { + get CheckBox(): CheckBox { warnOnce( 'checkBox-moved', 'CheckBox has been extracted from react-native core and will be removed in a future release. ' + @@ -43,7 +130,7 @@ module.exports = { ); return require('../Components/CheckBox/CheckBox'); }, - get DatePickerIOS() { + get DatePickerIOS(): DatePickerIOS { warnOnce( 'DatePickerIOS-merged', 'DatePickerIOS has been merged with DatePickerAndroid and will be removed in a future release. ' + @@ -52,25 +139,25 @@ module.exports = { ); return require('../Components/DatePicker/DatePickerIOS'); }, - get DrawerLayoutAndroid() { + get DrawerLayoutAndroid(): DrawerLayoutAndroid { return require('../Components/DrawerAndroid/DrawerLayoutAndroid'); }, - get FlatList() { + get FlatList(): FlatList { return require('../Lists/FlatList'); }, - get Image() { + get Image(): Image { return require('../Image/Image'); }, - get ImageBackground() { + get ImageBackground(): ImageBackground { return require('../Image/ImageBackground'); }, - get InputAccessoryView() { + get InputAccessoryView(): InputAccessoryView { return require('../Components/TextInput/InputAccessoryView'); }, - get KeyboardAvoidingView() { + get KeyboardAvoidingView(): KeyboardAvoidingView { return require('../Components/Keyboard/KeyboardAvoidingView'); }, - get MaskedViewIOS() { + get MaskedViewIOS(): MaskedViewIOS { warnOnce( 'maskedviewios-moved', 'MaskedViewIOS has been extracted from react-native core and will be removed in a future release. ' + @@ -79,34 +166,34 @@ module.exports = { ); return require('../Components/MaskedView/MaskedViewIOS'); }, - get Modal() { + get Modal(): Modal { return require('../Modal/Modal'); }, - get Picker() { + get Picker(): Picker { return require('../Components/Picker/Picker'); }, - get PickerIOS() { + get PickerIOS(): PickerIOS { return require('../Components/Picker/PickerIOS'); }, - get ProgressBarAndroid() { + get ProgressBarAndroid(): ProgressBarAndroid { return require('../Components/ProgressBarAndroid/ProgressBarAndroid'); }, - get ProgressViewIOS() { + get ProgressViewIOS(): ProgressViewIOS { return require('../Components/ProgressViewIOS/ProgressViewIOS'); }, - get SafeAreaView() { + get SafeAreaView(): SafeAreaView { return require('../Components/SafeAreaView/SafeAreaView'); }, - get ScrollView() { + get ScrollView(): ScrollView { return require('../Components/ScrollView/ScrollView'); }, - get SectionList() { + get SectionList(): SectionList { return require('../Lists/SectionList'); }, - get SegmentedControlIOS() { + get SegmentedControlIOS(): SegmentedControlIOS { return require('../Components/SegmentedControlIOS/SegmentedControlIOS'); }, - get Slider() { + get Slider(): Slider { warnOnce( 'slider-moved', 'Slider has been extracted from react-native core and will be removed in a future release. ' + @@ -115,63 +202,63 @@ module.exports = { ); return require('../Components/Slider/Slider'); }, - get Switch() { + get Switch(): Switch { return require('../Components/Switch/Switch'); }, - get RefreshControl() { + get RefreshControl(): RefreshControl { return require('../Components/RefreshControl/RefreshControl'); }, - get StatusBar() { + get StatusBar(): StatusBar { return require('../Components/StatusBar/StatusBar'); }, - get Text() { + get Text(): Text { return require('../Text/Text'); }, - get TextInput() { + get TextInput(): TextInput { return require('../Components/TextInput/TextInput'); }, - get Touchable() { + get Touchable(): Touchable { return require('../Components/Touchable/Touchable'); }, - get TouchableHighlight() { + get TouchableHighlight(): TouchableHighlight { return require('../Components/Touchable/TouchableHighlight'); }, - get TouchableNativeFeedback() { + get TouchableNativeFeedback(): TouchableNativeFeedback { return require('../Components/Touchable/TouchableNativeFeedback'); }, - get TouchableOpacity() { + get TouchableOpacity(): TouchableOpacity { return require('../Components/Touchable/TouchableOpacity'); }, - get TouchableWithoutFeedback() { + get TouchableWithoutFeedback(): TouchableWithoutFeedback { return require('../Components/Touchable/TouchableWithoutFeedback'); }, - get View() { + get View(): View { return require('../Components/View/View'); }, - get VirtualizedList() { + get VirtualizedList(): VirtualizedList { return require('../Lists/VirtualizedList'); }, - get VirtualizedSectionList() { + get VirtualizedSectionList(): VirtualizedSectionList { return require('../Lists/VirtualizedSectionList'); }, // APIs - get ActionSheetIOS() { + get ActionSheetIOS(): ActionSheetIOS { return require('../ActionSheetIOS/ActionSheetIOS'); }, - get Alert() { + get Alert(): Alert { return require('../Alert/Alert'); }, - get Animated() { + get Animated(): Animated { return require('../Animated/src/Animated'); }, - get AppRegistry() { + get AppRegistry(): AppRegistry { return require('../ReactNative/AppRegistry'); }, - get AppState() { + get AppState(): AppState { return require('../AppState/AppState'); }, - get AsyncStorage() { + get AsyncStorage(): AsyncStorage { warnOnce( 'async-storage-moved', 'AsyncStorage has been extracted from react-native core and will be removed in a future release. ' + @@ -180,13 +267,13 @@ module.exports = { ); return require('../Storage/AsyncStorage'); }, - get BackHandler() { + get BackHandler(): BackHandler { return require('../Utilities/BackHandler'); }, - get Clipboard() { + get Clipboard(): Clipboard { return require('../Components/Clipboard/Clipboard'); }, - get DatePickerAndroid() { + get DatePickerAndroid(): DatePickerAndroid { warnOnce( 'DatePickerAndroid-merged', 'DatePickerAndroid has been merged with DatePickerIOS and will be removed in a future release. ' + @@ -195,22 +282,22 @@ module.exports = { ); return require('../Components/DatePickerAndroid/DatePickerAndroid'); }, - get DeviceInfo() { + get DeviceInfo(): DeviceInfo { return require('../Utilities/DeviceInfo'); }, - get Dimensions() { + get Dimensions(): Dimensions { return require('../Utilities/Dimensions'); }, - get Easing() { + get Easing(): Easing { return require('../Animated/src/Easing'); }, - get findNodeHandle() { + get findNodeHandle(): $PropertyType { return require('../Renderer/shims/ReactNative').findNodeHandle; }, - get I18nManager() { + get I18nManager(): I18nManager { return require('../ReactNative/I18nManager'); }, - get ImagePickerIOS() { + get ImagePickerIOS(): ImagePickerIOS { warnOnce( 'imagePickerIOS-moved', 'ImagePickerIOS has been extracted from react-native core and will be removed in a future release. ' + @@ -220,34 +307,34 @@ module.exports = { ); return require('../Image/ImagePickerIOS'); }, - get InteractionManager() { + get InteractionManager(): InteractionManager { return require('../Interaction/InteractionManager'); }, - get Keyboard() { + get Keyboard(): Keyboard { return require('../Components/Keyboard/Keyboard'); }, - get LayoutAnimation() { + get LayoutAnimation(): LayoutAnimation { return require('../LayoutAnimation/LayoutAnimation'); }, - get Linking() { + get Linking(): Linking { return require('../Linking/Linking'); }, - get NativeDialogManagerAndroid() { + get NativeDialogManagerAndroid(): NativeDialogManagerAndroid { return require('../NativeModules/specs/NativeDialogManagerAndroid').default; }, - get NativeEventEmitter() { + get NativeEventEmitter(): NativeEventEmitter { return require('../EventEmitter/NativeEventEmitter'); }, - get PanResponder() { + get PanResponder(): PanResponder { return require('../Interaction/PanResponder'); }, - get PermissionsAndroid() { + get PermissionsAndroid(): PermissionsAndroid { return require('../PermissionsAndroid/PermissionsAndroid'); }, - get PixelRatio() { + get PixelRatio(): PixelRatio { return require('../Utilities/PixelRatio'); }, - get PushNotificationIOS() { + get PushNotificationIOS(): PushNotificationIOS { warnOnce( 'pushNotificationIOS-moved', 'PushNotificationIOS has been extracted from react-native core and will be removed in a future release. ' + @@ -256,26 +343,26 @@ module.exports = { ); return require('../PushNotificationIOS/PushNotificationIOS'); }, - get Settings() { + get Settings(): Settings { return require('../Settings/Settings'); }, - get Share() { + get Share(): Share { return require('../Share/Share'); }, - get StatusBarIOS() { + get StatusBarIOS(): StatusBarIOS { warnOnce( 'StatusBarIOS-merged', 'StatusBarIOS has been merged with StatusBar and will be removed in a future release. Use StatusBar for mutating the status bar', ); return require('../Components/StatusBar/StatusBarIOS'); }, - get StyleSheet() { + get StyleSheet(): StyleSheet { return require('../StyleSheet/StyleSheet'); }, - get Systrace() { + get Systrace(): Systrace { return require('../Performance/Systrace'); }, - get TimePickerAndroid() { + get TimePickerAndroid(): TimePickerAndroid { warnOnce( 'TimePickerAndroid-merged', 'TimePickerAndroid has been merged with DatePickerIOS and DatePickerAndroid and will be removed in a future release. ' + @@ -284,68 +371,71 @@ module.exports = { ); return require('../Components/TimePickerAndroid/TimePickerAndroid'); }, - get ToastAndroid() { + get ToastAndroid(): ToastAndroid { return require('../Components/ToastAndroid/ToastAndroid'); }, - get TurboModuleRegistry() { + get TurboModuleRegistry(): TurboModuleRegistry { return require('../TurboModule/TurboModuleRegistry'); }, - get TVEventHandler() { + get TVEventHandler(): TVEventHandler { return require('../Components/AppleTV/TVEventHandler'); }, - get UIManager() { + get UIManager(): UIManager { return require('../ReactNative/UIManager'); }, - get unstable_batchedUpdates() { + get unstable_batchedUpdates(): $PropertyType< + ReactNative, + 'unstable_batchedUpdates', + > { return require('../Renderer/shims/ReactNative').unstable_batchedUpdates; }, - get useWindowDimensions() { + get useWindowDimensions(): useWindowDimensions { return require('../Utilities/useWindowDimensions').default; }, - get UTFSequence() { + get UTFSequence(): UTFSequence { return require('../UTFSequence'); }, - get Vibration() { + get Vibration(): Vibration { return require('../Vibration/Vibration'); }, - get YellowBox() { + get YellowBox(): YellowBox { return require('../YellowBox/YellowBox'); }, // Plugins - get DeviceEventEmitter() { + get DeviceEventEmitter(): RCTDeviceEventEmitter { return require('../EventEmitter/RCTDeviceEventEmitter'); }, - get NativeAppEventEmitter() { + get NativeAppEventEmitter(): RCTNativeAppEventEmitter { return require('../EventEmitter/RCTNativeAppEventEmitter'); }, - get NativeModules() { + get NativeModules(): NativeModules { return require('../BatchedBridge/NativeModules'); }, - get Platform() { + get Platform(): Platform { return require('../Utilities/Platform'); }, - get processColor() { + get processColor(): processColor { return require('../StyleSheet/processColor'); }, - get requireNativeComponent() { + get requireNativeComponent(): requireNativeComponent { return require('../ReactNative/requireNativeComponent'); }, - get unstable_RootTagContext() { + get unstable_RootTagContext(): RootTagContext { return require('../ReactNative/RootTagContext'); }, // Prop Types - get ColorPropType() { + get ColorPropType(): DeprecatedColorPropType { return require('../DeprecatedPropTypes/DeprecatedColorPropType'); }, - get EdgeInsetsPropType() { + get EdgeInsetsPropType(): DeprecatedEdgeInsetsPropType { return require('../DeprecatedPropTypes/DeprecatedEdgeInsetsPropType'); }, - get PointPropType() { + get PointPropType(): DeprecatedPointPropType { return require('../DeprecatedPropTypes/DeprecatedPointPropType'); }, - get ViewPropTypes() { + get ViewPropTypes(): DeprecatedViewPropTypes { return require('../DeprecatedPropTypes/DeprecatedViewPropTypes'); }, }; From 947e71a922c0db5d3d3780d249d1a8d183534c22 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Thu, 22 Aug 2019 10:14:58 -0700 Subject: [PATCH 0037/1244] Add RCTWeakProxy to properly deallocate RCTUIImageViewAnimated Summary: @public CADisplayLink strongly holds onto its target, so you have to use a weak proxy object to pass the target into the CADisplayLink. Previously we passed a weak-self point (i.e. weakSelf) but this did not have the intended effect, since the pointer to self would still be passed to CADisplayLink, and thus it would hold onto the RCTUIImageViewAnimated strongly. So is weakSelf doing anything other than using self? It is but it's very minor and not useful. In the case that the object got de-allocated between assigning self to weakSelf and creating the CADisplayLink, then we would pass a nil target. This is actually impossible though because we are running an instance method, so self is implicitly retained! So semantically it is something different but in practice it is the same as passing self through. Notes: * This system was added originally in https://github.com/facebook/react-native/pull/24822 * https://github.com/facebook/react-native/pull/25636 then "enabled" this system by deprecating existing approach Reviewed By: fkgozali Differential Revision: D16939869 fbshipit-source-id: 7a0e947896f23aa30ad074d1dcb4d4db7543e00a --- Libraries/Image/RCTUIImageViewAnimated.h | 3 +++ Libraries/Image/RCTUIImageViewAnimated.m | 11 +++++++-- React/Base/RCTWeakProxy.h | 16 +++++++++++++ React/Base/RCTWeakProxy.m | 30 ++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 React/Base/RCTWeakProxy.h create mode 100644 React/Base/RCTWeakProxy.m diff --git a/Libraries/Image/RCTUIImageViewAnimated.h b/Libraries/Image/RCTUIImageViewAnimated.h index 7647c932136808..8b19147b2480ec 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.h +++ b/Libraries/Image/RCTUIImageViewAnimated.h @@ -6,6 +6,9 @@ */ #import +#import + +RCT_EXTERN void RCTUIImageViewEnableWeakProxy(BOOL enabled); @interface RCTUIImageViewAnimated : UIImageView diff --git a/Libraries/Image/RCTUIImageViewAnimated.m b/Libraries/Image/RCTUIImageViewAnimated.m index fb4a1d913e3709..f5c17d7e3e970e 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.m +++ b/Libraries/Image/RCTUIImageViewAnimated.m @@ -6,10 +6,16 @@ */ #import +#import #import #import +static BOOL weakProxyEnabled = YES; +void RCTUIImageViewEnableWeakProxy(BOOL enabled) { + weakProxyEnabled = enabled; +} + static NSUInteger RCTDeviceTotalMemory() { return (NSUInteger)[[NSProcessInfo processInfo] physicalMemory]; } @@ -146,8 +152,9 @@ - (NSOperationQueue *)fetchQueue - (CADisplayLink *)displayLink { if (!_displayLink) { - __weak __typeof(self) weakSelf = self; - _displayLink = [CADisplayLink displayLinkWithTarget:weakSelf selector:@selector(displayDidRefresh:)]; + __weak typeof(self) weakSelf = self; + id target = weakProxyEnabled ? [RCTWeakProxy weakProxyWithTarget:self] : weakSelf; + _displayLink = [CADisplayLink displayLinkWithTarget:target selector:@selector(displayDidRefresh:)]; NSString *runLoopMode = [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:runLoopMode]; } diff --git a/React/Base/RCTWeakProxy.h b/React/Base/RCTWeakProxy.h new file mode 100644 index 00000000000000..e2ed31e36ae675 --- /dev/null +++ b/React/Base/RCTWeakProxy.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface RCTWeakProxy : NSObject + +@property (nonatomic, weak, readonly) id target; + ++ (instancetype)weakProxyWithTarget:(id)target; + +@end diff --git a/React/Base/RCTWeakProxy.m b/React/Base/RCTWeakProxy.m new file mode 100644 index 00000000000000..5b1663499184f9 --- /dev/null +++ b/React/Base/RCTWeakProxy.m @@ -0,0 +1,30 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTWeakProxy.h" + +@implementation RCTWeakProxy + +- (instancetype)initWithTarget:(id)target +{ + if (self = [super init]) { + _target = target; + } + return self; +} + ++ (instancetype)weakProxyWithTarget:(id)target +{ + return [[RCTWeakProxy alloc] initWithTarget:target]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _target; +} + +@end From 59f84ca1fd4a5700d67cc7c68194dd845a1ecfd6 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Thu, 22 Aug 2019 10:14:58 -0700 Subject: [PATCH 0038/1244] Remove RCTUIImageViewAnimated WeakProxy gating Summary: To help determine how severe this issue is, put the fix behind a MC. We will only pick the parent diff to the RC branch so that the fix immediately goes to master and we don't have to worry about fixing this any further. Reviewed By: fkgozali Differential Revision: D16940181 fbshipit-source-id: 91eb08181f82f51aea6a20b3fd489a33bdc0e424 --- Libraries/Image/RCTUIImageViewAnimated.h | 2 -- Libraries/Image/RCTUIImageViewAnimated.m | 9 +-------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Libraries/Image/RCTUIImageViewAnimated.h b/Libraries/Image/RCTUIImageViewAnimated.h index 8b19147b2480ec..1c894a849d148a 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.h +++ b/Libraries/Image/RCTUIImageViewAnimated.h @@ -8,8 +8,6 @@ #import #import -RCT_EXTERN void RCTUIImageViewEnableWeakProxy(BOOL enabled); - @interface RCTUIImageViewAnimated : UIImageView @end diff --git a/Libraries/Image/RCTUIImageViewAnimated.m b/Libraries/Image/RCTUIImageViewAnimated.m index f5c17d7e3e970e..01aa75f391c239 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.m +++ b/Libraries/Image/RCTUIImageViewAnimated.m @@ -11,11 +11,6 @@ #import #import -static BOOL weakProxyEnabled = YES; -void RCTUIImageViewEnableWeakProxy(BOOL enabled) { - weakProxyEnabled = enabled; -} - static NSUInteger RCTDeviceTotalMemory() { return (NSUInteger)[[NSProcessInfo processInfo] physicalMemory]; } @@ -152,9 +147,7 @@ - (NSOperationQueue *)fetchQueue - (CADisplayLink *)displayLink { if (!_displayLink) { - __weak typeof(self) weakSelf = self; - id target = weakProxyEnabled ? [RCTWeakProxy weakProxyWithTarget:self] : weakSelf; - _displayLink = [CADisplayLink displayLinkWithTarget:target selector:@selector(displayDidRefresh:)]; + _displayLink = [CADisplayLink displayLinkWithTarget:[RCTWeakProxy weakProxyWithTarget:self] selector:@selector(displayDidRefresh:)]; NSString *runLoopMode = [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode; [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:runLoopMode]; } From 2211eb5fe815cfaf967ff7b472c7d955a70b6427 Mon Sep 17 00:00:00 2001 From: Mehdi Mulani Date: Thu, 22 Aug 2019 10:35:07 -0700 Subject: [PATCH 0039/1244] Don't allocate a CADisplayLink for static images Summary: @public The mass majority of RCTUIImageViewAnimated uses are actually for static images. As such, we don't need to create a CADisplayLink. Reviewed By: shergin Differential Revision: D16945038 fbshipit-source-id: a7cb63000987d1ea7a8a9b4d596e1e474709d2ac --- Libraries/Image/RCTUIImageViewAnimated.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Libraries/Image/RCTUIImageViewAnimated.m b/Libraries/Image/RCTUIImageViewAnimated.m index 01aa75f391c239..3d3cf45481d88b 100644 --- a/Libraries/Image/RCTUIImageViewAnimated.m +++ b/Libraries/Image/RCTUIImageViewAnimated.m @@ -146,6 +146,12 @@ - (NSOperationQueue *)fetchQueue - (CADisplayLink *)displayLink { + // We only need a displayLink in the case of animated images, so short-circuit this code and don't create one for most of the use cases. + // Since this class is used for all RCTImageView's, this is especially important. + if (!_animatedImage) { + return nil; + } + if (!_displayLink) { _displayLink = [CADisplayLink displayLinkWithTarget:[RCTWeakProxy weakProxyWithTarget:self] selector:@selector(displayDidRefresh:)]; NSString *runLoopMode = [NSProcessInfo processInfo].activeProcessorCount > 1 ? NSRunLoopCommonModes : NSDefaultRunLoopMode; From 3b7eb7ed85b8850bf851a430b6f3fdf882483380 Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 22 Aug 2019 12:05:50 -0700 Subject: [PATCH 0040/1244] Fix Flowtype for Command refs Summary: The types we were using before weren't very strict and it had been on my list to fix this. I *think* this is the right type. With Flow's type first project having these exported types will be necessary anyways so we can just use that for the ref. Changelog: [Internal] Reviewed By: JoshuaGross Differential Revision: D16930573 fbshipit-source-id: 05c1e097794633a2cefa7384c9d81ab15a63d8af --- .../AndroidDrawerLayoutNativeComponent.js | 20 +++++--- .../DrawerLayoutAndroid.android.js | 23 +-------- .../__test_fixtures__/failures.js | 21 +++++--- .../__test_fixtures__/fixtures.js | 31 ++++++----- .../__snapshots__/index-test.js.snap | 22 ++++---- .../components/__test_fixtures__/fixtures.js | 51 +++++++++++-------- .../component-parser-test.js.snap | 4 +- .../src/parsers/flow/components/commands.js | 4 +- 8 files changed, 91 insertions(+), 85 deletions(-) diff --git a/Libraries/Components/DrawerAndroid/AndroidDrawerLayoutNativeComponent.js b/Libraries/Components/DrawerAndroid/AndroidDrawerLayoutNativeComponent.js index 778b609fc29103..71668e22f975e2 100644 --- a/Libraries/Components/DrawerAndroid/AndroidDrawerLayoutNativeComponent.js +++ b/Libraries/Components/DrawerAndroid/AndroidDrawerLayoutNativeComponent.js @@ -19,7 +19,9 @@ import type { Float, } from 'react-native/Libraries/Types/CodegenTypes'; import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; -import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import codegenNativeComponent, { + type NativeComponentType, +} from 'react-native/Libraries/Utilities/codegenNativeComponent'; import * as React from 'react'; type DrawerStateEvent = $ReadOnly<{| @@ -30,11 +32,6 @@ type DrawerSlideEvent = $ReadOnly<{| offset: Float, |}>; -interface NativeCommands { - +openDrawer: (viewRef: React.Ref<'AndroidDrawerLayout'>) => void; - +closeDrawer: (viewRef: React.Ref<'AndroidDrawerLayout'>) => void; -} - type NativeProps = $ReadOnly<{| ...ViewProps, /** @@ -113,8 +110,17 @@ type NativeProps = $ReadOnly<{| statusBarBackgroundColor?: ?ColorValue, |}>; +type NativeType = NativeComponentType; + +interface NativeCommands { + +openDrawer: (viewRef: React.ElementRef) => void; + +closeDrawer: (viewRef: React.ElementRef) => void; +} + export const Commands: NativeCommands = codegenNativeCommands({ supportedCommands: ['openDrawer', 'closeDrawer'], }); -export default codegenNativeComponent('AndroidDrawerLayout'); +export default (codegenNativeComponent( + 'AndroidDrawerLayout', +): NativeType); diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index 5807013f55e1b1..2575e982bbbd30 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -167,7 +167,7 @@ class DrawerLayoutAndroid extends React.Component { drawerBackgroundColor: 'white', }; - _nativeRef = React.createRef(); + _nativeRef = React.createRef(); state = {statusBarBackgroundColor: null}; @@ -217,9 +217,6 @@ class DrawerLayoutAndroid extends React.Component { return ( =0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ ref={this._nativeRef} drawerWidth={this.props.drawerWidth} drawerPosition={this.props.drawerPosition} @@ -318,30 +315,18 @@ class DrawerLayoutAndroid extends React.Component { * Native methods */ blur() { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).blur(); } focus() { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).focus(); } measure(callback: MeasureOnSuccessCallback) { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).measure(callback); } measureInWindow(callback: MeasureInWindowOnSuccessCallback) { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).measureInWindow(callback); } @@ -350,9 +335,6 @@ class DrawerLayoutAndroid extends React.Component { onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void, ) { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).measureLayout( relativeToNativeNode, onSuccess, @@ -361,9 +343,6 @@ class DrawerLayoutAndroid extends React.Component { } setNativeProps(nativeProps: Object) { - /* $FlowFixMe(>=0.87.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.87 was deployed. To see the - * error, delete this comment and run Flow. */ nullthrows(this._nativeRef.current).setNativeProps(nativeProps); } } diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/failures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/failures.js index 7baa1bb435fe52..0437e6bee3e813 100644 --- a/packages/babel-plugin-inline-view-configs/__test_fixtures__/failures.js +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/failures.js @@ -16,18 +16,21 @@ const COMMANDS_EXPORTED_WITH_DIFFERENT_NAME = ` const codegenNativeComponent = require('codegenNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; +import type {NativeComponent} from 'codegenNativeComponent'; type ModuleProps = $ReadOnly<{| ...ViewProps, |}>; +type NativeType = NativeComponent; + interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'Module'>) => void; + +hotspotUpdate: (viewRef: React.ElementRef) => void; } export const Foo = codegenNativeCommands(); -export default codegenNativeComponent('Module'); +export default (codegenNativeComponent('Module'): NativeType); `; const OTHER_COMMANDS_EXPORT = ` @@ -36,24 +39,28 @@ const OTHER_COMMANDS_EXPORT = ` const codegenNativeComponent = require('codegenNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; +import type {NativeComponent} from 'codegenNativeComponent'; type ModuleProps = $ReadOnly<{| ...ViewProps, |}>; +type NativeType = NativeComponent; + interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'Module'>) => void; + +hotspotUpdate: (viewRef: React.ElementRef) => void; } export const Commands = 4; -export default codegenNativeComponent('Module'); +export default (codegenNativeComponent('Module'): NativeType); `; const COMMANDS_EXPORTED_WITH_SHORTHAND = ` // @flow const codegenNativeComponent = require('codegenNativeComponent'); +import type {NativeComponent} from 'codegenNativeComponent'; import type {ViewProps} from 'ViewPropTypes'; @@ -61,15 +68,17 @@ type ModuleProps = $ReadOnly<{| ...ViewProps, |}>; +type NativeType = NativeComponent; + interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'Module'>) => void; + +hotspotUpdate: (viewRef: React.ElementRef) => void; } const Commands = 4; export {Commands}; -export default codegenNativeComponent('Module'); +export default (codegenNativeComponent('Module'): NativeType); `; module.exports = { diff --git a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js index 620c6fb7b73143..3a9d8ae3cd9ccd 100644 --- a/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js +++ b/packages/babel-plugin-inline-view-configs/__test_fixtures__/fixtures.js @@ -27,14 +27,10 @@ import type { DirectEventHandler, WithDefault, } from 'CodegenFlowtypes'; +import type {NativeComponent} from 'codegenNativeComponent'; import type {ViewProps} from 'ViewPropTypes'; -interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void; - +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void; -} - type ModuleProps = $ReadOnly<{| ...ViewProps, @@ -46,6 +42,13 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: BubblingEventHandler, |}>; +type NativeType = NativeComponent; + +interface NativeCommands { + +hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void; + +scrollTo: (viewRef: React.ElementRef, y: Int32, animated: boolean) => void; +} + export const Commands = codegenNativeCommands({ supportedCommands: ['hotspotUpdate', 'scrollTo'], }); @@ -61,7 +64,7 @@ const FULL_NATIVE_COMPONENT_WITH_TYPE_EXPORT = ` const codegenNativeCommands = require('codegenNativeCommands'); const codegenNativeComponent = require('codegenNativeComponent'); -import type {NativeComponent} from 'ReactNative'; +import type {NativeComponent} from 'codegenNativeComponent'; import type { Int32, @@ -72,11 +75,6 @@ import type { import type {ViewProps} from 'ViewPropTypes'; -interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void; - +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void; -} - type ModuleProps = $ReadOnly<{| ...ViewProps, @@ -88,16 +86,21 @@ type ModuleProps = $ReadOnly<{| onBubblingEventDefinedInlineNull: BubblingEventHandler, |}>; +type NativeType = NativeComponent; + +interface NativeCommands { + +hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void; + +scrollTo: (viewRef: React.ElementRef, y: Int32, animated: boolean) => void; +} + export const Commands = codegenNativeCommands({ supportedCommands: ['hotspotUpdate', 'scrollTo'], }); -type NativeComponentType = Class>; - export default (codegenNativeComponent('Module', { interfaceOnly: true, paperComponentName: 'RCTModule', -}): NativeComponentType); +}): NativeType); `; module.exports = { diff --git a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap index a7175adeb4dc95..21b1ac3f2ee6e4 100644 --- a/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap +++ b/packages/babel-plugin-inline-view-configs/__tests__/__snapshots__/index-test.js.snap @@ -7,11 +7,8 @@ const codegenNativeCommands = require('codegenNativeCommands'); const codegenNativeComponent = require('codegenNativeComponent'); import type { Int32, BubblingEventHandler, DirectEventHandler, WithDefault } from 'CodegenFlowtypes'; +import type { NativeComponent } from 'codegenNativeComponent'; import type { ViewProps } from 'ViewPropTypes'; -interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void, - +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void, -} type ModuleProps = $ReadOnly<{| ...ViewProps, // Props boolean_default_true_optional_both?: WithDefault, @@ -19,6 +16,11 @@ type ModuleProps = $ReadOnly<{| ...ViewProps, onDirectEventDefinedInlineNull: DirectEventHandler, onBubblingEventDefinedInlineNull: BubblingEventHandler, |}>; +type NativeType = NativeComponent; +interface NativeCommands { + +hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void, + +scrollTo: (viewRef: React.ElementRef, y: Int32, animated: boolean) => void, +} const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); @@ -69,13 +71,9 @@ const codegenNativeCommands = require('codegenNativeCommands'); const codegenNativeComponent = require('codegenNativeComponent'); -import type { NativeComponent } from 'ReactNative'; +import type { NativeComponent } from 'codegenNativeComponent'; import type { Int32, BubblingEventHandler, DirectEventHandler, WithDefault } from 'CodegenFlowtypes'; import type { ViewProps } from 'ViewPropTypes'; -interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void, - +scrollTo: (viewRef: React.Ref<'RCTView'>, y: Int32, animated: boolean) => void, -} type ModuleProps = $ReadOnly<{| ...ViewProps, // Props boolean_default_true_optional_both?: WithDefault, @@ -83,7 +81,11 @@ type ModuleProps = $ReadOnly<{| ...ViewProps, onDirectEventDefinedInlineNull: DirectEventHandler, onBubblingEventDefinedInlineNull: BubblingEventHandler, |}>; -type NativeComponentType = Class>; +type NativeType = NativeComponent; +interface NativeCommands { + +hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void, + +scrollTo: (viewRef: React.ElementRef, y: Int32, animated: boolean) => void, +} const registerGeneratedViewConfig = require('registerGeneratedViewConfig'); diff --git a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js index 6fae6b4a2138b6..083663df81d5c6 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js +++ b/packages/react-native-codegen/src/parsers/flow/components/__test_fixtures__/fixtures.js @@ -776,10 +776,18 @@ import type {Int32, Double, Float} from 'CodegenTypes'; import type {ViewProps} from 'ViewPropTypes'; import type {NativeComponent} from 'codegenNativeComponent'; + +export type ModuleProps = $ReadOnly<{| + ...ViewProps, + // No props or events +|}>; + +type NativeType = NativeComponent; + interface NativeCommands { - +hotspotUpdate: (viewRef: React.Ref<'RCTView'>, x: Int32, y: Int32) => void; + +hotspotUpdate: (viewRef: React.ElementRef, x: Int32, y: Int32) => void; +scrollTo: ( - viewRef: React.Ref<'RCTView'>, + viewRef: React.ElementRef, x: Float, y: Int32, z: Double, @@ -787,18 +795,13 @@ interface NativeCommands { ) => void; } -export type ModuleProps = $ReadOnly<{| - ...ViewProps, - // No props or events -|}>; - export const Commands = codegenNativeCommands({ supportedCommands: ['hotspotUpdate', 'scrollTo'], }); export default (codegenNativeComponent( 'Module', -): NativeComponent); +): NativeType); `; const COMMANDS_WITH_EXTERNAL_TYPES = ` @@ -825,8 +828,15 @@ export type Boolean = boolean; export type Int = Int32; export type Void = void; +export type ModuleProps = $ReadOnly<{| + ...ViewProps, + // No props or events +|}>; + +type NativeType = NativeComponent; + export type ScrollTo = ( - viewRef: React.Ref<'RCTView'>, + viewRef: React.ElementRef, y: Int, animated: Boolean, ) => Void; @@ -835,18 +845,13 @@ interface NativeCommands { +scrollTo: ScrollTo; } -export type ModuleProps = $ReadOnly<{| - ...ViewProps, - // No props or events -|}>; - export const Commands = codegenNativeCommands({ supportedCommands: ['scrollTo'], }); export default (codegenNativeComponent( 'Module', -): NativeComponent); +): NativeType); `; const COMMANDS_AND_EVENTS_TYPES_EXPORTED = ` @@ -879,12 +884,6 @@ export type Boolean = boolean; export type Int = Int32; export type Void = void; -export type ScrollTo = (viewRef: React.Ref<'RCTView'>, y: Int, animated: Boolean) => Void - -interface NativeCommands { - +scrollTo: ScrollTo; -} - export type ModuleProps = $ReadOnly<{| ...ViewProps, @@ -897,13 +896,21 @@ export type ModuleProps = $ReadOnly<{| onDirectEventDefinedInlineWithPaperName: DirectEventHandler, |}>; +type NativeType = NativeComponent; + +export type ScrollTo = (viewRef: React.ElementRef, y: Int, animated: Boolean) => Void + +interface NativeCommands { + +scrollTo: ScrollTo; +} + export const Commands = codegenNativeCommands({ supportedCommands: ['scrollTo'] }); export default (codegenNativeComponent( 'Module', -): NativeComponent); +): NativeType); `; module.exports = { diff --git a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap index 83b2d69a2d25fe..db7d5026afa588 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap +++ b/packages/react-native-codegen/src/parsers/flow/components/__tests__/__snapshots__/component-parser-test.js.snap @@ -6,11 +6,11 @@ exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_MULTIP exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITH_MISMATCHED_METHOD_NAMES 1`] = `"codegenNativeCommands expected the same supportedCommands specified in the NativeCommands interface: hotspotUpdate, scrollTo"`; -exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITH_NULLABLE_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.Ref<>"`; +exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITH_NULLABLE_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<>"`; exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOUT_METHOD_NAMES 1`] = `"codegenNativeCommands must be passed options including the supported commands"`; -exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.Ref<>"`; +exports[`RN Codegen Flow Parser Fails with error message COMMANDS_DEFINED_WITHOUT_REF 1`] = `"The first argument of method hotspotUpdate must be of type React.ElementRef<>"`; exports[`RN Codegen Flow Parser Fails with error message NON_OPTIONAL_KEY_WITH_DEFAULT_VALUE 1`] = `"key required_key_with_default must be optional if used with WithDefault<> annotation"`; diff --git a/packages/react-native-codegen/src/parsers/flow/components/commands.js b/packages/react-native-codegen/src/parsers/flow/components/commands.js index 26758dcba855cb..0232a82d1f4002 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/commands.js +++ b/packages/react-native-codegen/src/parsers/flow/components/commands.js @@ -29,11 +29,11 @@ function buildCommandSchema(property, types: TypeMap) { firstParam.id != null && firstParam.id.type === 'QualifiedTypeIdentifier' && firstParam.id.qualification.name === 'React' && - firstParam.id.id.name === 'Ref' + firstParam.id.id.name === 'ElementRef' ) ) { throw new Error( - `The first argument of method ${name} must be of type React.Ref<>`, + `The first argument of method ${name} must be of type React.ElementRef<>`, ); } From 2f7732b1458109605a1a29c58d2a7ca38aed552e Mon Sep 17 00:00:00 2001 From: Eli White Date: Thu, 22 Aug 2019 14:00:21 -0700 Subject: [PATCH 0041/1244] Migrate TouchableNativeFeedback to use codegenNativeCommands Summary: Instead of dispatching the command with findNodeHandle and the UIManager, go through the new API. This is safe because codegenNativeCommands can work at runtime as well as with the babel transform. Changelog: [Internal] Reviewed By: rickhanlonii Differential Revision: D16909599 fbshipit-source-id: 90252862374290dbeb7202483fa585b6a7051c12 --- .../TouchableNativeFeedback.android.js | 20 +++++++----------- .../Components/View/ViewNativeComponent.js | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index a866f65e0131bd..4ccbb7570b831d 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -13,11 +13,10 @@ const Platform = require('../../Utilities/Platform'); const React = require('react'); const PropTypes = require('prop-types'); -const ReactNative = require('../../Renderer/shims/ReactNative'); const Touchable = require('./Touchable'); const TouchableWithoutFeedback = require('./TouchableWithoutFeedback'); -const UIManager = require('../../ReactNative/UIManager'); const View = require('../View/View'); +const {Commands: ViewCommands} = require('../View/ViewNativeComponent'); const createReactClass = require('create-react-class'); const ensurePositiveDelayProps = require('./ensurePositiveDelayProps'); @@ -262,20 +261,16 @@ const TouchableNativeFeedback = createReactClass({ ); }, + _handleRef: function(ref) { + this._viewRef = ref; + }, + _dispatchHotspotUpdate: function(destX, destY) { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('RCTView').Commands.hotspotUpdate, - [destX || 0, destY || 0], - ); + ViewCommands.hotspotUpdate(this._viewRef, destX || 0, destY || 0); }, _dispatchPressedStateChange: function(pressed) { - UIManager.dispatchViewManagerCommand( - ReactNative.findNodeHandle(this), - UIManager.getViewManagerConfig('RCTView').Commands.setPressed, - [pressed], - ); + ViewCommands.setPressed(this._viewRef, pressed); }, render: function() { @@ -318,6 +313,7 @@ const TouchableNativeFeedback = createReactClass({ accessibilityActions: this.props.accessibilityActions, onAccessibilityAction: this.props.onAccessibilityAction, children, + ref: this._handleRef, testID: this.props.testID, onLayout: this.props.onLayout, hitSlop: this.props.hitSlop, diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index c735b5b864a77b..8b58086b83ccf8 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -10,13 +10,17 @@ 'use strict'; +const React = require('react'); const Platform = require('../../Utilities/Platform'); const ReactNative = require('../../Renderer/shims/ReactNative'); const ReactNativeViewViewConfigAndroid = require('./ReactNativeViewViewConfigAndroid'); const registerGeneratedViewConfig = require('../../Utilities/registerGeneratedViewConfig'); const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); +const codegenNativeCommands = require('../../Utilities/codegenNativeCommands') + .default; +import type {Int32} from '../../Types/CodegenTypes'; import type {ViewProps} from './ViewPropTypes'; export type ViewNativeComponentType = Class< @@ -66,5 +70,22 @@ if (__DEV__) { NativeViewComponent = requireNativeComponent('RCTView'); } +// These commands are Android only +interface NativeCommands { + +hotspotUpdate: ( + viewRef: React.ElementRef, + x: Int32, + y: Int32, + ) => void; + +setPressed: ( + viewRef: React.ElementRef, + pressed: boolean, + ) => void; +} + +export const Commands = codegenNativeCommands({ + supportedCommands: ['hotspotUpdate', 'setPressed'], +}); + export const __INTERNAL_VIEW_CONFIG = viewConfig; export default ((NativeViewComponent: any): ViewNativeComponentType); From cafbf67d0dc8b3674c82b86c9e9724ee4363890e Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Thu, 22 Aug 2019 14:02:47 -0700 Subject: [PATCH 0042/1244] Fix generated props CPP default values Summary: This one is fun. # What? Previously, the codegen'd constructor for a prop value in CPP was defined like so: `value(convertRawProp(rawProps, "value", sourceProps.value, value))`. The fourth argument there is the default value of the result of `convertRawProps`. What that is saying is: the default value of `value` is `value` - the default value is itself. The assumption was that because value is defined as `T value{someDefaultValue}` in the struct, in other words, because it has a default value in the `.h` file, that it will /start out/ being equal to `someDefaultValue`, and then be overridden later optionally, or be set to itself, which should be `someDefaultValue`. However, that is not how initialization of class members in C++ constructors work. If a class member is in the member initializer list, [then the default value is not set](https://en.cppreference.com/w/cpp/language/initializer_list). That means that if the `defaultValue` as passed is /ever/ used, we incur undefined behavior. # When is the defaultValue used? The defaultValue is only used when no prop or a null value is sent from JS to C++: https://our.intern.facebook.com/intern/diffusion/FBS/browse/master/xplat/js/react-native-github/ReactCommon/fabric/core/propsConversions.h?commit=becfded106d706e6028e705d7883483051061e9f&lines=60 In most cases, the `sourceProps.value` is actually used as a fallback (the previous props value). The first time props are ever constructed, `sourceProps` should have valid values since it goes through a different path where only the defaultValues from props.h are used. # Why wasn't this crashing before? Most codegen'd properties are ints, floats, doubles, and bools. They might get wacky values, but they won't crash. I wouldn't be surprised if this diff solves some subtle visual or layout bugs, but I have no evidence of this yet. # How do non-codegen'd props.cpp initialize default values? Same as this diff does: defaultValue should be explicit everywhere: https://our.intern.facebook.com/intern/diffusion/FBS/browse/master/xplat/js/react-native-github/ReactCommon/fabric/components/scrollview/ScrollViewProps.cpp?commit=2813789c292dfdf1220b88f203af6b33ba9e42de&lines=51 # So... what have we learned? C++ is tricky! Reviewed By: yungsters, shergin Differential Revision: D16955421 fbshipit-source-id: 75bb3f22822299e17df1c36abecdb6ce49012406 --- .../src/generators/components/CppHelpers.js | 80 ++++++++++++++++ .../generators/components/GeneratePropsCpp.js | 9 +- .../generators/components/GeneratePropsH.js | 77 +--------------- .../GeneratePropsCpp-test.js.snap | 92 +++++++++---------- 4 files changed, 134 insertions(+), 124 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/CppHelpers.js b/packages/react-native-codegen/src/generators/components/CppHelpers.js index a09b1d736004bf..b05293598b0a19 100644 --- a/packages/react-native-codegen/src/generators/components/CppHelpers.js +++ b/packages/react-native-codegen/src/generators/components/CppHelpers.js @@ -96,8 +96,88 @@ function generateStructName( return `${componentName}${additional}Struct`; } +function getEnumName(componentName: string, propName: string): string { + const uppercasedPropName = toSafeCppString(propName); + return `${componentName}${uppercasedPropName}`; +} + +function getEnumMaskName(enumName: string): string { + return `${enumName}Mask`; +} + +function convertDefaultTypeToString( + componentName: string, + prop: PropTypeShape, +): string { + const typeAnnotation = prop.typeAnnotation; + switch (typeAnnotation.type) { + case 'BooleanTypeAnnotation': + return String(typeAnnotation.default); + case 'StringTypeAnnotation': + if (typeAnnotation.default == null) { + return ''; + } + return `"${typeAnnotation.default}"`; + case 'Int32TypeAnnotation': + return String(typeAnnotation.default); + case 'DoubleTypeAnnotation': + const defaultDoubleVal = typeAnnotation.default; + return parseInt(defaultDoubleVal, 10) === defaultDoubleVal + ? typeAnnotation.default.toFixed(1) + : String(typeAnnotation.default); + case 'FloatTypeAnnotation': + const defaultFloatVal = typeAnnotation.default; + return parseInt(defaultFloatVal, 10) === defaultFloatVal + ? typeAnnotation.default.toFixed(1) + : String(typeAnnotation.default); + case 'NativePrimitiveTypeAnnotation': + switch (typeAnnotation.name) { + case 'ColorPrimitive': + return ''; + case 'ImageSourcePrimitive': + return ''; + case 'PointPrimitive': + return ''; + default: + (typeAnnotation.name: empty); + throw new Error('Received unknown NativePrimitiveTypeAnnotation'); + } + case 'ArrayTypeAnnotation': { + switch (typeAnnotation.elementType.type) { + case 'StringEnumTypeAnnotation': + if (typeAnnotation.elementType.default == null) { + throw new Error( + 'A default is required for array StringEnumTypeAnnotation', + ); + } + const enumName = getEnumName(componentName, prop.name); + const enumMaskName = getEnumMaskName(enumName); + const defaultValue = `${enumName}::${toSafeCppString( + typeAnnotation.elementType.default || '', + )}`; + return `static_cast<${enumMaskName}>(${defaultValue})`; + default: + return ''; + } + } + case 'ObjectTypeAnnotation': { + return ''; + } + case 'StringEnumTypeAnnotation': + return `${getEnumName(componentName, prop.name)}::${toSafeCppString( + typeAnnotation.default, + )}`; + default: + (typeAnnotation: empty); + throw new Error('Received invalid typeAnnotation'); + } +} + module.exports = { + convertDefaultTypeToString, getCppTypeForAnnotation, + getEnumName, + getEnumMaskName, getImports, toSafeCppString, generateStructName, diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsCpp.js b/packages/react-native-codegen/src/generators/components/GeneratePropsCpp.js index 738715c2fb1133..2c190ce179b1a7 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsCpp.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsCpp.js @@ -11,7 +11,7 @@ 'use strict'; import type {ComponentShape, SchemaType} from '../../CodegenSchema'; -const {getImports} = require('./CppHelpers'); +const {convertDefaultTypeToString, getImports} = require('./CppHelpers'); // File path -> contents type FilesOutput = Map; @@ -45,12 +45,13 @@ const componentTemplate = ` {} `.trim(); -function generatePropsString(component: ComponentShape) { +function generatePropsString(componentName: string, component: ComponentShape) { return component.props .map(prop => { + const defaultValue = convertDefaultTypeToString(componentName, prop); return `${prop.name}(convertRawProp(rawProps, "${ prop.name - }", sourceProps.${prop.name}, ${prop.name}))`; + }", sourceProps.${prop.name}, {${defaultValue}}))`; }) .join(',\n' + ' '); } @@ -104,7 +105,7 @@ module.exports = { const component = components[componentName]; const newName = `${componentName}Props`; - const propsString = generatePropsString(component); + const propsString = generatePropsString(componentName, component); const extendString = getClassExtendString(component); const imports = getImports(component.props); diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js index 18808afe12e70e..9970f366888bb8 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsH.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsH.js @@ -11,7 +11,10 @@ 'use strict'; const { + convertDefaultTypeToString, getCppTypeForAnnotation, + getEnumMaskName, + getEnumName, toSafeCppString, generateStructName, getImports, @@ -239,80 +242,6 @@ function getNativeTypeFromAnnotation( } } -function convertDefaultTypeToString(componentName: string, prop): string { - const typeAnnotation = prop.typeAnnotation; - switch (typeAnnotation.type) { - case 'BooleanTypeAnnotation': - return String(typeAnnotation.default); - case 'StringTypeAnnotation': - if (typeAnnotation.default == null) { - return ''; - } - return `"${typeAnnotation.default}"`; - case 'Int32TypeAnnotation': - return String(typeAnnotation.default); - case 'DoubleTypeAnnotation': - const defaultDoubleVal = typeAnnotation.default; - return parseInt(defaultDoubleVal, 10) === defaultDoubleVal - ? typeAnnotation.default.toFixed(1) - : String(typeAnnotation.default); - case 'FloatTypeAnnotation': - const defaultFloatVal = typeAnnotation.default; - return parseInt(defaultFloatVal, 10) === defaultFloatVal - ? typeAnnotation.default.toFixed(1) - : String(typeAnnotation.default); - case 'NativePrimitiveTypeAnnotation': - switch (typeAnnotation.name) { - case 'ColorPrimitive': - return ''; - case 'ImageSourcePrimitive': - return ''; - case 'PointPrimitive': - return ''; - default: - (typeAnnotation.name: empty); - throw new Error('Received unknown NativePrimitiveTypeAnnotation'); - } - case 'ArrayTypeAnnotation': { - switch (typeAnnotation.elementType.type) { - case 'StringEnumTypeAnnotation': - if (typeAnnotation.elementType.default == null) { - throw new Error( - 'A default is required for array StringEnumTypeAnnotation', - ); - } - const enumName = getEnumName(componentName, prop.name); - const enumMaskName = getEnumMaskName(enumName); - const defaultValue = `${enumName}::${toSafeCppString( - typeAnnotation.elementType.default || '', - )}`; - return `static_cast<${enumMaskName}>(${defaultValue})`; - default: - return ''; - } - } - case 'ObjectTypeAnnotation': { - return ''; - } - case 'StringEnumTypeAnnotation': - return `${getEnumName(componentName, prop.name)}::${toSafeCppString( - typeAnnotation.default, - )}`; - default: - (typeAnnotation: empty); - throw new Error('Received invalid typeAnnotation'); - } -} - -function getEnumName(componentName, propName): string { - const uppercasedPropName = toSafeCppString(propName); - return `${componentName}${uppercasedPropName}`; -} - -function getEnumMaskName(enumName: string): string { - return `${enumName}Mask`; -} - function convertValueToEnumOption(value: string): string { return toSafeCppString(value); } diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap index 4f81abf1dda663..bfc00ae64f2876 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsCpp-test.js.snap @@ -21,16 +21,16 @@ ArrayPropsNativeComponentProps::ArrayPropsNativeComponentProps( const ArrayPropsNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - names(convertRawProp(rawProps, \\"names\\", sourceProps.names, names)), - disableds(convertRawProp(rawProps, \\"disableds\\", sourceProps.disableds, disableds)), - progress(convertRawProp(rawProps, \\"progress\\", sourceProps.progress, progress)), - radii(convertRawProp(rawProps, \\"radii\\", sourceProps.radii, radii)), - colors(convertRawProp(rawProps, \\"colors\\", sourceProps.colors, colors)), - srcs(convertRawProp(rawProps, \\"srcs\\", sourceProps.srcs, srcs)), - points(convertRawProp(rawProps, \\"points\\", sourceProps.points, points)), - sizes(convertRawProp(rawProps, \\"sizes\\", sourceProps.sizes, sizes)), - object(convertRawProp(rawProps, \\"object\\", sourceProps.object, object)), - array(convertRawProp(rawProps, \\"array\\", sourceProps.array, array)) + names(convertRawProp(rawProps, \\"names\\", sourceProps.names, {})), + disableds(convertRawProp(rawProps, \\"disableds\\", sourceProps.disableds, {})), + progress(convertRawProp(rawProps, \\"progress\\", sourceProps.progress, {})), + radii(convertRawProp(rawProps, \\"radii\\", sourceProps.radii, {})), + colors(convertRawProp(rawProps, \\"colors\\", sourceProps.colors, {})), + srcs(convertRawProp(rawProps, \\"srcs\\", sourceProps.srcs, {})), + points(convertRawProp(rawProps, \\"points\\", sourceProps.points, {})), + sizes(convertRawProp(rawProps, \\"sizes\\", sourceProps.sizes, {static_cast(ArrayPropsNativeComponentSizes::Small)})), + object(convertRawProp(rawProps, \\"object\\", sourceProps.object, {})), + array(convertRawProp(rawProps, \\"array\\", sourceProps.array, {})) {} } // namespace react @@ -59,7 +59,7 @@ ArrayPropsNativeComponentProps::ArrayPropsNativeComponentProps( const ArrayPropsNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - nativePrimitives(convertRawProp(rawProps, \\"nativePrimitives\\", sourceProps.nativePrimitives, nativePrimitives)) + nativePrimitives(convertRawProp(rawProps, \\"nativePrimitives\\", sourceProps.nativePrimitives, {})) {} } // namespace react @@ -88,7 +88,7 @@ BooleanPropNativeComponentProps::BooleanPropNativeComponentProps( const BooleanPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {false})) {} } // namespace react @@ -117,7 +117,7 @@ ColorPropNativeComponentProps::ColorPropNativeComponentProps( const ColorPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - tintColor(convertRawProp(rawProps, \\"tintColor\\", sourceProps.tintColor, tintColor)) + tintColor(convertRawProp(rawProps, \\"tintColor\\", sourceProps.tintColor, {})) {} } // namespace react @@ -175,7 +175,7 @@ CommandNativeComponentProps::CommandNativeComponentProps( const CommandNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, accessibilityHint)) + accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, {\\"\\"})) {} } // namespace react @@ -204,12 +204,12 @@ DoublePropNativeComponentProps::DoublePropNativeComponentProps( const DoublePropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - blurRadius(convertRawProp(rawProps, \\"blurRadius\\", sourceProps.blurRadius, blurRadius)), - blurRadius2(convertRawProp(rawProps, \\"blurRadius2\\", sourceProps.blurRadius2, blurRadius2)), - blurRadius3(convertRawProp(rawProps, \\"blurRadius3\\", sourceProps.blurRadius3, blurRadius3)), - blurRadius4(convertRawProp(rawProps, \\"blurRadius4\\", sourceProps.blurRadius4, blurRadius4)), - blurRadius5(convertRawProp(rawProps, \\"blurRadius5\\", sourceProps.blurRadius5, blurRadius5)), - blurRadius6(convertRawProp(rawProps, \\"blurRadius6\\", sourceProps.blurRadius6, blurRadius6)) + blurRadius(convertRawProp(rawProps, \\"blurRadius\\", sourceProps.blurRadius, {0.0})), + blurRadius2(convertRawProp(rawProps, \\"blurRadius2\\", sourceProps.blurRadius2, {0.001})), + blurRadius3(convertRawProp(rawProps, \\"blurRadius3\\", sourceProps.blurRadius3, {2.1})), + blurRadius4(convertRawProp(rawProps, \\"blurRadius4\\", sourceProps.blurRadius4, {0.0})), + blurRadius5(convertRawProp(rawProps, \\"blurRadius5\\", sourceProps.blurRadius5, {1.0})), + blurRadius6(convertRawProp(rawProps, \\"blurRadius6\\", sourceProps.blurRadius6, {0.0})) {} } // namespace react @@ -238,7 +238,7 @@ EnumPropsNativeComponentProps::EnumPropsNativeComponentProps( const EnumPropsNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - alignment(convertRawProp(rawProps, \\"alignment\\", sourceProps.alignment, alignment)) + alignment(convertRawProp(rawProps, \\"alignment\\", sourceProps.alignment, {EnumPropsNativeComponentAlignment::Center})) {} } // namespace react @@ -267,7 +267,7 @@ EventsNestedObjectNativeComponentProps::EventsNestedObjectNativeComponentProps( const EventsNestedObjectNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {false})) {} } // namespace react @@ -296,7 +296,7 @@ EventsNativeComponentProps::EventsNativeComponentProps( const EventsNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {false})) {} } // namespace react @@ -354,12 +354,12 @@ FloatPropNativeComponentProps::FloatPropNativeComponentProps( const FloatPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - blurRadius(convertRawProp(rawProps, \\"blurRadius\\", sourceProps.blurRadius, blurRadius)), - blurRadius2(convertRawProp(rawProps, \\"blurRadius2\\", sourceProps.blurRadius2, blurRadius2)), - blurRadius3(convertRawProp(rawProps, \\"blurRadius3\\", sourceProps.blurRadius3, blurRadius3)), - blurRadius4(convertRawProp(rawProps, \\"blurRadius4\\", sourceProps.blurRadius4, blurRadius4)), - blurRadius5(convertRawProp(rawProps, \\"blurRadius5\\", sourceProps.blurRadius5, blurRadius5)), - blurRadius6(convertRawProp(rawProps, \\"blurRadius6\\", sourceProps.blurRadius6, blurRadius6)) + blurRadius(convertRawProp(rawProps, \\"blurRadius\\", sourceProps.blurRadius, {0.0})), + blurRadius2(convertRawProp(rawProps, \\"blurRadius2\\", sourceProps.blurRadius2, {0.001})), + blurRadius3(convertRawProp(rawProps, \\"blurRadius3\\", sourceProps.blurRadius3, {2.1})), + blurRadius4(convertRawProp(rawProps, \\"blurRadius4\\", sourceProps.blurRadius4, {0.0})), + blurRadius5(convertRawProp(rawProps, \\"blurRadius5\\", sourceProps.blurRadius5, {1.0})), + blurRadius6(convertRawProp(rawProps, \\"blurRadius6\\", sourceProps.blurRadius6, {0.0})) {} } // namespace react @@ -389,7 +389,7 @@ ImagePropNativeComponentProps::ImagePropNativeComponentProps( const ImagePropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - thumbImage(convertRawProp(rawProps, \\"thumbImage\\", sourceProps.thumbImage, thumbImage)) + thumbImage(convertRawProp(rawProps, \\"thumbImage\\", sourceProps.thumbImage, {})) {} } // namespace react @@ -418,9 +418,9 @@ IntegerPropNativeComponentProps::IntegerPropNativeComponentProps( const IntegerPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - progress1(convertRawProp(rawProps, \\"progress1\\", sourceProps.progress1, progress1)), - progress2(convertRawProp(rawProps, \\"progress2\\", sourceProps.progress2, progress2)), - progress3(convertRawProp(rawProps, \\"progress3\\", sourceProps.progress3, progress3)) + progress1(convertRawProp(rawProps, \\"progress1\\", sourceProps.progress1, {0})), + progress2(convertRawProp(rawProps, \\"progress2\\", sourceProps.progress2, {-1})), + progress3(convertRawProp(rawProps, \\"progress3\\", sourceProps.progress3, {10})) {} } // namespace react @@ -449,7 +449,7 @@ InterfaceOnlyComponentProps::InterfaceOnlyComponentProps( const InterfaceOnlyComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, accessibilityHint)) + accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, {\\"\\"})) {} } // namespace react @@ -479,10 +479,10 @@ ImageColorPropNativeComponentProps::ImageColorPropNativeComponentProps( const ImageColorPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - thumbImage(convertRawProp(rawProps, \\"thumbImage\\", sourceProps.thumbImage, thumbImage)), - color(convertRawProp(rawProps, \\"color\\", sourceProps.color, color)), - thumbTintColor(convertRawProp(rawProps, \\"thumbTintColor\\", sourceProps.thumbTintColor, thumbTintColor)), - point(convertRawProp(rawProps, \\"point\\", sourceProps.point, point)) + thumbImage(convertRawProp(rawProps, \\"thumbImage\\", sourceProps.thumbImage, {})), + color(convertRawProp(rawProps, \\"color\\", sourceProps.color, {})), + thumbTintColor(convertRawProp(rawProps, \\"thumbTintColor\\", sourceProps.thumbTintColor, {})), + point(convertRawProp(rawProps, \\"point\\", sourceProps.point, {})) {} } // namespace react @@ -541,7 +541,7 @@ ObjectPropsProps::ObjectPropsProps( const ObjectPropsProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - objectProp(convertRawProp(rawProps, \\"objectProp\\", sourceProps.objectProp, objectProp)) + objectProp(convertRawProp(rawProps, \\"objectProp\\", sourceProps.objectProp, {})) {} } // namespace react @@ -570,7 +570,7 @@ PointPropNativeComponentProps::PointPropNativeComponentProps( const PointPropNativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - startPoint(convertRawProp(rawProps, \\"startPoint\\", sourceProps.startPoint, startPoint)) + startPoint(convertRawProp(rawProps, \\"startPoint\\", sourceProps.startPoint, {})) {} } // namespace react @@ -599,8 +599,8 @@ StringPropComponentProps::StringPropComponentProps( const StringPropComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, accessibilityHint)), - accessibilityRole(convertRawProp(rawProps, \\"accessibilityRole\\", sourceProps.accessibilityRole, accessibilityRole)) + accessibilityHint(convertRawProp(rawProps, \\"accessibilityHint\\", sourceProps.accessibilityHint, {\\"\\"})), + accessibilityRole(convertRawProp(rawProps, \\"accessibilityRole\\", sourceProps.accessibilityRole, {})) {} } // namespace react @@ -629,13 +629,13 @@ MultiFile1NativeComponentProps::MultiFile1NativeComponentProps( const MultiFile1NativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {false})) {} MultiFile2NativeComponentProps::MultiFile2NativeComponentProps( const MultiFile2NativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {true})) {} } // namespace react @@ -664,13 +664,13 @@ MultiComponent1NativeComponentProps::MultiComponent1NativeComponentProps( const MultiComponent1NativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {false})) {} MultiComponent2NativeComponentProps::MultiComponent2NativeComponentProps( const MultiComponent2NativeComponentProps &sourceProps, const RawProps &rawProps): ViewProps(sourceProps, rawProps), - disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, disabled)) + disabled(convertRawProp(rawProps, \\"disabled\\", sourceProps.disabled, {true})) {} } // namespace react From 08daad44273f16ef513c3b9ab17da0efce334ee5 Mon Sep 17 00:00:00 2001 From: Logan Daniels Date: Thu, 22 Aug 2019 17:48:39 -0700 Subject: [PATCH 0043/1244] Add annotations to ReactNativePrivateInterface Reviewed By: panagosg7 Differential Revision: D16946424 fbshipit-source-id: 90f13dd8bb25aac7ed8b2bebe6d7e49fa97958ff --- .../ReactNativePrivateInterface.js | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Libraries/ReactPrivate/ReactNativePrivateInterface.js b/Libraries/ReactPrivate/ReactNativePrivateInterface.js index 82634a69998231..3d2f7b06f789e4 100644 --- a/Libraries/ReactPrivate/ReactNativePrivateInterface.js +++ b/Libraries/ReactPrivate/ReactNativePrivateInterface.js @@ -8,39 +8,54 @@ * @flow strict-local */ +import typeof BatchedBridge from '../BatchedBridge/BatchedBridge.js'; +import typeof ExceptionsManager from '../Core/ExceptionsManager'; +import typeof Platform from '../Utilities/Platform'; +import typeof RCTEventEmitter from '../EventEmitter/RCTEventEmitter'; +import typeof ReactNativeViewConfigRegistry from '../Renderer/shims/ReactNativeViewConfigRegistry'; +import typeof TextInputState from '../Components/TextInput/TextInputState'; +import typeof UIManager from '../ReactNative/UIManager'; +import typeof deepDiffer from '../Utilities/differ/deepDiffer'; +import typeof deepFreezeAndThrowOnMutationInDev from '../Utilities/deepFreezeAndThrowOnMutationInDev'; +import typeof flattenStyle from '../StyleSheet/flattenStyle'; +import typeof ReactFiberErrorDialog from '../Core/ReactFiberErrorDialog'; + // flowlint unsafe-getters-setters:off module.exports = { - get BatchedBridge() { + get BatchedBridge(): BatchedBridge { return require('../BatchedBridge/BatchedBridge.js'); }, - get ExceptionsManager() { + get ExceptionsManager(): ExceptionsManager { return require('../Core/ExceptionsManager'); }, - get Platform() { + get Platform(): Platform { return require('../Utilities/Platform'); }, - get RCTEventEmitter() { + get RCTEventEmitter(): RCTEventEmitter { return require('../EventEmitter/RCTEventEmitter'); }, - get ReactNativeViewConfigRegistry() { + get ReactNativeViewConfigRegistry(): ReactNativeViewConfigRegistry { return require('../Renderer/shims/ReactNativeViewConfigRegistry'); }, - get TextInputState() { + get TextInputState(): TextInputState { return require('../Components/TextInput/TextInputState'); }, - get UIManager() { + get UIManager(): UIManager { return require('../ReactNative/UIManager'); }, - get deepDiffer() { + get deepDiffer(): deepDiffer { return require('../Utilities/differ/deepDiffer'); }, - get deepFreezeAndThrowOnMutationInDev() { + get deepFreezeAndThrowOnMutationInDev(): deepFreezeAndThrowOnMutationInDev< + // $FlowFixMe - can't properly parameterize the getter's type + *, + > { return require('../Utilities/deepFreezeAndThrowOnMutationInDev'); }, - get flattenStyle() { + get flattenStyle(): flattenStyle { return require('../StyleSheet/flattenStyle'); }, - get ReactFiberErrorDialog() { + get ReactFiberErrorDialog(): ReactFiberErrorDialog { return require('../Core/ReactFiberErrorDialog'); }, }; From 97b42bb142f4f9d52af3f85e288ab7742b282fed Mon Sep 17 00:00:00 2001 From: "glevi@fb.com" Date: Fri, 23 Aug 2019 08:04:24 -0700 Subject: [PATCH 0044/1244] Deploy v0.106.0 to xplat/js Reviewed By: mroch Differential Revision: D16979246 fbshipit-source-id: 995fbd391823eaf0c9e3a673cf8fbe061ce0545a --- .flowconfig | 2 +- .flowconfig.android | 2 +- .../ActivityIndicator/ActivityIndicator.js | 4 +++- Libraries/Experimental/WindowedListView.js | 5 ----- Libraries/Sample/Sample.android.js | 4 ++-- Libraries/Text/TextAncestor.js | 3 --- .../NativeAnimation/NativeAnimationsExample.js | 3 --- .../PointerEvents/PointerEventsExample.js | 3 --- .../ProgressViewIOS/ProgressViewIOSExample.js | 3 --- .../ScrollView/ScrollViewSimpleExample.js | 3 --- RNTester/js/examples/Share/ShareExample.js | 3 --- .../examples/TextInput/TextInputExample.ios.js | 18 ------------------ .../src/androidTest/js/ScrollViewTestModule.js | 6 ------ .../hermes/inspector/tools/msggen/src/index.js | 1 - package.json | 2 +- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 17 files changed, 13 insertions(+), 59 deletions(-) diff --git a/.flowconfig b/.flowconfig index ec2c82e32de7bf..e9022018546bd1 100644 --- a/.flowconfig +++ b/.flowconfig @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.105.0 +^0.106.0 diff --git a/.flowconfig.android b/.flowconfig.android index 15f63ee87cb200..e01244558487c2 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.105.0 +^0.106.0 diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index 2eed90d8de1fd2..877ce50d50229b 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -109,7 +109,9 @@ const ActivityIndicator = (props: Props, forwardedRef?: any) => { // $FlowFixMe Flow doesn't know when this is the android component ) : ( - // $FlowFixMe Flow doesn't know when this is the iOS component + /* $FlowFixMe(>=0.106.0 site=react_native_android_fb) This comment + * suppresses an error found when Flow v0.106 was deployed. To see the + * error, delete this comment and run Flow. */ )} diff --git a/Libraries/Experimental/WindowedListView.js b/Libraries/Experimental/WindowedListView.js index 84ff57dc65c384..ec56b388ed1953 100644 --- a/Libraries/Experimental/WindowedListView.js +++ b/Libraries/Experimental/WindowedListView.js @@ -183,11 +183,6 @@ class WindowedListView extends React.Component { maxNumToRender: 30, numToRenderAhead: 10, viewablePercentThreshold: 50, - /* $FlowFixMe(>=0.59.0 site=react_native_fb) This comment suppresses an - * error caught by Flow 0.59 which was not caught before. Most likely, this - * error is because an exported function parameter is missing an - * annotation. Without an annotation, these parameters are uncovered by - * Flow. */ renderScrollComponent: props => , disableIncrementalRendering: false, recomputeRowsBatchingPeriod: 10, // This should capture most events that happen within a frame diff --git a/Libraries/Sample/Sample.android.js b/Libraries/Sample/Sample.android.js index 65ab87d6b04941..6020b60b1830cc 100644 --- a/Libraries/Sample/Sample.android.js +++ b/Libraries/Sample/Sample.android.js @@ -16,8 +16,8 @@ const warning = require('fbjs/lib/warning'); const Sample = { test: function() { - /* $FlowFixMe(>=0.103.0 site=react_native_android_fb) This comment - * suppresses an error found when Flow v0.103 was deployed. To see the + /* $FlowFixMe(>=0.106.0 site=react_native_android_fb) This comment + * suppresses an error found when Flow v0.106 was deployed. To see the * error, delete this comment and run Flow. */ warning('Not yet implemented for Android.'); }, diff --git a/Libraries/Text/TextAncestor.js b/Libraries/Text/TextAncestor.js index 24fb1b45512fad..b791319c80c171 100644 --- a/Libraries/Text/TextAncestor.js +++ b/Libraries/Text/TextAncestor.js @@ -15,7 +15,4 @@ const React = require('react'); /** * Whether the current element is the descendant of a element. */ -/* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.85 was deployed. To see the error, delete this comment - * and run Flow. */ module.exports = (React.createContext(false): React$Context<$FlowFixMe>); diff --git a/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js b/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js index f654aa4ca9760d..01b6b077294708 100644 --- a/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js +++ b/RNTester/js/examples/NativeAnimation/NativeAnimationsExample.js @@ -309,9 +309,6 @@ class TrackingExample extends React.Component< this.state.toJS.setValue(nextValue); }; - /* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.85 was deployed. To see the error, delete this comment - * and run Flow. */ renderBlock = (anim, dest) => [ =0.70.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.70 was deployed. To see the error delete this comment - * and run Flow. */ exports.examples = (exampleClasses.map(infoToExample): Array); diff --git a/RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js b/RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js index e2c729cfbfd166..5f700308178f9c 100644 --- a/RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js +++ b/RNTester/js/examples/ProgressViewIOS/ProgressViewIOSExample.js @@ -42,9 +42,6 @@ class ProgressViewExample extends React.Component { this._rafId = requestAnimationFrame(() => this.updateProgress()); }; - /* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.85 was deployed. To see the error, delete this comment - * and run Flow. */ getProgress = offset => { const progress = this.state.progress + offset; return Math.sin(progress % Math.PI) % 1; diff --git a/RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js b/RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js index 5487fa866cca69..0409560c04d641 100644 --- a/RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js +++ b/RNTester/js/examples/ScrollView/ScrollViewSimpleExample.js @@ -22,9 +22,6 @@ const { const NUM_ITEMS = 20; class ScrollViewSimpleExample extends React.Component<{}> { - /* $FlowFixMe(>=0.98.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.98 was deployed. To see the error delete this comment - * and run Flow. */ makeItems: (nItems: number, styles: any) => Array = ( nItems: number, styles, diff --git a/RNTester/js/examples/Share/ShareExample.js b/RNTester/js/examples/Share/ShareExample.js index 0d4bf3b6f0a0c1..fe33658a9f2e1c 100644 --- a/RNTester/js/examples/Share/ShareExample.js +++ b/RNTester/js/examples/Share/ShareExample.js @@ -28,9 +28,6 @@ class ShareMessageExample extends React.Component { _shareText: Function; _showResult: Function; - /* $FlowFixMe(>=0.85.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.85 was deployed. To see the error, delete this comment - * and run Flow. */ constructor(props) { super(props); diff --git a/RNTester/js/examples/TextInput/TextInputExample.ios.js b/RNTester/js/examples/TextInput/TextInputExample.ios.js index f21ca72d32c30b..f38b65ebdd8484 100644 --- a/RNTester/js/examples/TextInput/TextInputExample.ios.js +++ b/RNTester/js/examples/TextInput/TextInputExample.ios.js @@ -100,9 +100,6 @@ class TextEventsExample extends React.Component<{}, $FlowFixMeState> { } class TextInputAccessoryViewExample extends React.Component<{}, *> { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = {text: 'Placeholder Text'}; @@ -132,9 +129,6 @@ class TextInputAccessoryViewExample extends React.Component<{}, *> { } class RewriteExample extends React.Component<$FlowFixMeProps, any> { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = {text: ''}; @@ -167,9 +161,6 @@ class RewriteExampleInvalidCharacters extends React.Component< $FlowFixMeProps, any, > { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = {text: ''}; @@ -191,9 +182,6 @@ class RewriteExampleInvalidCharacters extends React.Component< } class RewriteExampleKana extends React.Component<$FlowFixMeProps, any> { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = {text: ''}; @@ -215,9 +203,6 @@ class RewriteExampleKana extends React.Component<$FlowFixMeProps, any> { } class SecureEntryExample extends React.Component<$FlowFixMeProps, any> { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = { @@ -263,9 +248,6 @@ class SecureEntryExample extends React.Component<$FlowFixMeProps, any> { } class TokenizedTextExample extends React.Component<$FlowFixMeProps, any> { - /* $FlowFixMe(>=0.85.0 site=react_native_ios_fb) This comment suppresses an - * error found when Flow v0.85 was deployed. To see the error, delete this - * comment and run Flow. */ constructor(props) { super(props); this.state = {text: 'Hello #World'}; diff --git a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js index d98f64ef73dab3..3a6a887919bf26 100644 --- a/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js +++ b/ReactAndroid/src/androidTest/js/ScrollViewTestModule.js @@ -92,9 +92,6 @@ type State = {| |}; class ScrollViewTestApp extends React.Component { - /* $FlowFixMe(>=0.87.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.87 was deployed. To see the error, delete this comment - * and run Flow. */ scrollView: {|current: any | null|} = React.createRef(); state: State = getInitialState(); @@ -129,9 +126,6 @@ class ScrollViewTestApp extends React.Component { } class HorizontalScrollViewTestApp extends React.Component { - /* $FlowFixMe(>=0.87.0 site=react_native_fb) This comment suppresses an error - * found when Flow v0.87 was deployed. To see the error, delete this comment - * and run Flow. */ scrollView: {|current: any | null|} = React.createRef(); state: State = getInitialState(); diff --git a/ReactCommon/hermes/inspector/tools/msggen/src/index.js b/ReactCommon/hermes/inspector/tools/msggen/src/index.js index a0955329d7f70d..5f1296f1218f00 100644 --- a/ReactCommon/hermes/inspector/tools/msggen/src/index.js +++ b/ReactCommon/hermes/inspector/tools/msggen/src/index.js @@ -11,7 +11,6 @@ import fs from 'fs'; -// $FlowFixMe: flow doesn't know about yargs import yargs from 'yargs'; import {Command} from './Command'; diff --git a/package.json b/package.json index f96e75c0c9963b..64ed5ae7fdb8fa 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "eslint-plugin-react-hooks": "^2.0.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "1.3.0", - "flow-bin": "^0.105.0", + "flow-bin": "^0.106.0", "flow-remove-types": "1.2.3", "jest": "^24.8.0", "jest-junit": "^6.3.0", diff --git a/template/_flowconfig b/template/_flowconfig index ae78e6a1a93695..3759e18699ac5b 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -72,4 +72,4 @@ untyped-import untyped-type-import [version] -^0.105.0 +^0.106.0 diff --git a/yarn.lock b/yarn.lock index 5341dc1fee9f23..b930749fc875c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3159,10 +3159,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.105.0: - version "0.105.1" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.105.1.tgz#5ce4515b583e5fa6ea1b82bc849c354271f5b88d" - integrity sha512-wRI5ogu/+85fgftljAOtnDBx9+2JHToyq2XifzoMmXc5mmB9OE7osukzwi2PuOoEKtq9fu+APRD+MqbEJ8bUwQ== +flow-bin@^0.106.0: + version "0.106.0" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.106.0.tgz#55aab8c154df2bd78abfe6acfe120cf5638a0352" + integrity sha512-sV8lNBLTTfieUBNvQZFc1K1wXjC8I+O7ltv6G/nd3hdGyq2Jymyy01zAPhJ7MRw8yZ0X2dBSHFZx5DPreBqhAg== flow-parser@0.*: version "0.89.0" From b6333f79e1194e2fa59709d6e32e9f080124fac7 Mon Sep 17 00:00:00 2001 From: Logan Daniels Date: Fri, 23 Aug 2019 08:43:08 -0700 Subject: [PATCH 0045/1244] Final fixes and seal xplat/js/react-native-github Reviewed By: panagosg7 Differential Revision: D16946423 fbshipit-source-id: 89ca82c955e99a23a14984d51f3c97346c363afd --- .flowconfig | 2 +- .flowconfig.android | 2 +- Libraries/BugReporting/NativeBugReporting.js | 4 +- .../AccessibilityInfo.android.js | 6 +- .../DrawerLayoutAndroid.android.js | 11 +- .../ToastAndroid/ToastAndroid.android.js | 10 +- .../TouchableNativeFeedback.android.js | 4 +- .../View/ReactNativeStyleAttributes.js | 38 ++++- .../Components/View/ViewNativeComponent.js | 2 +- .../DeprecatedTextInputPropTypes.js | 134 +++++++++++++++--- Libraries/Image/Image.android.js | 39 +++-- Libraries/Image/NativeImageLoader.js | 2 +- .../Interaction/NativeFrameRateLogger.js | 4 +- Libraries/Network/RCTNetworking.android.js | 5 +- Libraries/Utilities/Platform.android.js | 19 ++- RNTester/js/RNTesterApp.android.js | 19 +-- .../ProgressBarAndroidExample.android.js | 7 +- .../js/examples/Text/TextExample.android.js | 7 +- .../TextInput/TextInputExample.android.js | 39 ++--- .../ToastAndroidExample.android.js | 8 +- RNTester/js/utils/RNTesterList.android.js | 2 +- .../components/ObjectPropsNativeComponent.js | 9 +- .../modules/NativeNullableTurboModule.js | 4 +- .../src/generators/components/CppHelpers.js | 2 +- .../src/parsers/flow/components/props.js | 6 +- 25 files changed, 280 insertions(+), 105 deletions(-) diff --git a/.flowconfig b/.flowconfig index e9022018546bd1..62e3d599588fb6 100644 --- a/.flowconfig +++ b/.flowconfig @@ -54,7 +54,7 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]* suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError experimental.well_formed_exports=true -experimental.well_formed_exports.whitelist=/Libraries/react-native/react-native-implementation.js +experimental.well_formed_exports.whitelist= [lints] sketchy-null-number=warn diff --git a/.flowconfig.android b/.flowconfig.android index e01244558487c2..66467e11e850ba 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -54,7 +54,7 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]* suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError experimental.well_formed_exports=true -experimental.well_formed_exports.whitelist=/Libraries/react-native/react-native-implementation.js +experimental.well_formed_exports.whitelist= [lints] sketchy-null-number=warn diff --git a/Libraries/BugReporting/NativeBugReporting.js b/Libraries/BugReporting/NativeBugReporting.js index 236b34e17a93b6..02ff311cc50f3c 100644 --- a/Libraries/BugReporting/NativeBugReporting.js +++ b/Libraries/BugReporting/NativeBugReporting.js @@ -8,8 +8,8 @@ * @flow */ -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +startReportAProblemFlow: () => void; @@ -17,4 +17,4 @@ export interface Spec extends TurboModule { +setCategoryID: (categoryID: string) => void; } -export default TurboModuleRegistry.get('BugReporting'); +export default (TurboModuleRegistry.get('BugReporting'): ?Spec); diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index 5c9ab848d2ecff..b44c2a6fb220bb 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -10,11 +10,11 @@ 'use strict'; -import NativeAccessibilityInfo from './NativeAccessibilityInfo'; - const RCTDeviceEventEmitter = require('../../EventEmitter/RCTDeviceEventEmitter'); const UIManager = require('../../ReactNative/UIManager'); +import NativeAccessibilityInfo from './NativeAccessibilityInfo'; + const REDUCE_MOTION_EVENT = 'reduceMotionDidChange'; const TOUCH_EXPLORATION_EVENT = 'touchExplorationDidChange'; @@ -90,7 +90,7 @@ const AccessibilityInfo = { * * Same as `isScreenReaderEnabled` */ - get fetch() { + get fetch(): () => Promise { return this.isScreenReaderEnabled; }, diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index 2575e982bbbd30..0ce582734e730d 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -15,9 +15,10 @@ const React = require('react'); const StatusBar = require('../StatusBar/StatusBar'); const StyleSheet = require('../../StyleSheet/StyleSheet'); const View = require('../View/View'); -const nullthrows = require('nullthrows'); const dismissKeyboard = require('../../Utilities/dismissKeyboard'); +const nullthrows = require('nullthrows'); + import AndroidDrawerLayoutNativeComponent, { Commands, } from './AndroidDrawerLayoutNativeComponent'; @@ -163,15 +164,17 @@ class DrawerLayoutAndroid extends React.Component { return {Left: 'left', Right: 'right'}; } - static defaultProps = { + static defaultProps: {| + drawerBackgroundColor: 'white', + |} = { drawerBackgroundColor: 'white', }; _nativeRef = React.createRef(); - state = {statusBarBackgroundColor: null}; + state: State = {statusBarBackgroundColor: null}; - render() { + render(): React.Node { const { onDrawerStateChanged, renderNavigationView, diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index ff1db3cf90bf88..9ff5182491a229 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -34,12 +34,12 @@ import NativeToastAndroid from './NativeToastAndroid'; const ToastAndroid = { // Toast duration constants - SHORT: NativeToastAndroid.getConstants().SHORT, - LONG: NativeToastAndroid.getConstants().LONG, + SHORT: (NativeToastAndroid.getConstants().SHORT: number), + LONG: (NativeToastAndroid.getConstants().LONG: number), // Toast gravity constants - TOP: NativeToastAndroid.getConstants().TOP, - BOTTOM: NativeToastAndroid.getConstants().BOTTOM, - CENTER: NativeToastAndroid.getConstants().CENTER, + TOP: (NativeToastAndroid.getConstants().TOP: number), + BOTTOM: (NativeToastAndroid.getConstants().BOTTOM: number), + CENTER: (NativeToastAndroid.getConstants().CENTER: number), show: function(message: string, duration: number): void { NativeToastAndroid.show(message, duration); diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index 4ccbb7570b831d..a4edef82dbf377 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -11,8 +11,8 @@ 'use strict'; const Platform = require('../../Utilities/Platform'); -const React = require('react'); const PropTypes = require('prop-types'); +const React = require('react'); const Touchable = require('./Touchable'); const TouchableWithoutFeedback = require('./TouchableWithoutFeedback'); const View = require('../View/View'); @@ -345,4 +345,4 @@ const TouchableNativeFeedback = createReactClass({ }, }); -module.exports = TouchableNativeFeedback; +module.exports = (TouchableNativeFeedback: $FlowFixMe); diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index c1126c724e554b..f80746cd447b09 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -18,7 +18,43 @@ const processColor = require('../../StyleSheet/processColor'); const processTransform = require('../../StyleSheet/processTransform'); const sizesDiffer = require('../../Utilities/differ/sizesDiffer'); -const ReactNativeStyleAttributes = {}; +type ReturnBoolType = (V) => true; +type BoolifiedDeprecatedViewStylePropTypes = $ObjMap< + typeof DeprecatedViewStylePropTypes, + ReturnBoolType, +>; +type BoolifiedDeprecatedTextStylePropTypes = $ObjMapi< + typeof DeprecatedTextStylePropTypes, + ReturnBoolType, +>; +type BoolifiedDeprecatedImageStylePropTypes = $ObjMapi< + typeof DeprecatedImageStylePropTypes, + ReturnBoolType, +>; + +type StyleAttributesType = { + ...BoolifiedDeprecatedViewStylePropTypes, + ...BoolifiedDeprecatedTextStylePropTypes, + ...BoolifiedDeprecatedImageStylePropTypes, + transform: $ReadOnly<{|process: typeof processTransform|}> | true, + shadowOffset: $ReadOnly<{|diff: typeof sizesDiffer|}> | true, + backgroundColor: typeof colorAttributes | true, + borderBottomColor: typeof colorAttributes | true, + borderColor: typeof colorAttributes | true, + borderLeftColor: typeof colorAttributes | true, + borderRightColor: typeof colorAttributes | true, + borderTopColor: typeof colorAttributes | true, + borderStartColor: typeof colorAttributes | true, + borderEndColor: typeof colorAttributes | true, + color: typeof colorAttributes | true, + shadowColor: typeof colorAttributes | true, + textDecorationColor: typeof colorAttributes | true, + tintColor: typeof colorAttributes | true, + textShadowColor: typeof colorAttributes | true, + overlayColor: typeof colorAttributes | true, +}; + +const ReactNativeStyleAttributes: StyleAttributesType = {}; for (const attributeName of Object.keys({ ...DeprecatedViewStylePropTypes, diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 8b58086b83ccf8..276bbbb2e9c5ff 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -83,7 +83,7 @@ interface NativeCommands { ) => void; } -export const Commands = codegenNativeCommands({ +export const Commands: NativeCommands = codegenNativeCommands({ supportedCommands: ['hotspotUpdate', 'setPressed'], }); diff --git a/Libraries/DeprecatedPropTypes/DeprecatedTextInputPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedTextInputPropTypes.js index 5748999e57fe3b..9288b0f01d1271 100644 --- a/Libraries/DeprecatedPropTypes/DeprecatedTextInputPropTypes.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedTextInputPropTypes.js @@ -10,10 +10,10 @@ 'use strict'; -const PropTypes = require('prop-types'); const DeprecatedColorPropType = require('./DeprecatedColorPropType'); const DeprecatedViewPropTypes = require('./DeprecatedViewPropTypes'); const DocumentSelectionState = require('../vendor/document/selection/DocumentSelectionState'); +const PropTypes = require('prop-types'); const Text = require('../Text/Text'); const DataDetectorTypes = [ @@ -35,7 +35,12 @@ module.exports = { * - `sentences`: first letter of each sentence (*default*). * - `none`: don't auto capitalize anything. */ - autoCapitalize: PropTypes.oneOf(['none', 'sentences', 'words', 'characters']), + autoCapitalize: (PropTypes.oneOf([ + 'none', + 'sentences', + 'words', + 'characters', + ]): React$PropType$Primitive<'none' | 'sentences' | 'words' | 'characters'>), /** * Determines which content to suggest on auto complete, e.g.`username`. * To disable auto complete, use `off`. @@ -60,7 +65,7 @@ module.exports = { * * @platform android */ - autoCompleteType: PropTypes.oneOf([ + autoCompleteType: (PropTypes.oneOf([ 'cc-csc', 'cc-exp', 'cc-exp-month', @@ -74,7 +79,21 @@ module.exports = { 'tel', 'username', 'off', - ]), + ]): React$PropType$Primitive< + | 'cc-csc' + | 'cc-exp' + | 'cc-exp-month' + | 'cc-exp-year' + | 'cc-number' + | 'email' + | 'name' + | 'password' + | 'postal-code' + | 'street-address' + | 'tel' + | 'username' + | 'off', + >), /** * If `false`, disables auto-correct. The default value is `true`. */ @@ -136,7 +155,7 @@ module.exports = { * * - `visible-password` */ - keyboardType: PropTypes.oneOf([ + keyboardType: (PropTypes.oneOf([ // Cross-platform 'default', 'email-address', @@ -153,12 +172,30 @@ module.exports = { 'web-search', // Android-only 'visible-password', - ]), + ]): React$PropType$Primitive< + | 'default' + | 'email-address' + | 'numeric' + | 'phone-pad' + | 'number-pad' + | 'ascii-capable' + | 'numbers-and-punctuation' + | 'url' + | 'name-phone-pad' + | 'decimal-pad' + | 'twitter' + | 'web-search' + | 'visible-password', + >), /** * Determines the color of the keyboard. * @platform ios */ - keyboardAppearance: PropTypes.oneOf(['default', 'light', 'dark']), + keyboardAppearance: (PropTypes.oneOf([ + 'default', + 'light', + 'dark', + ]): React$PropType$Primitive<'default' | 'light' | 'dark'>), /** * Determines how the return key should look. On Android you can also use * `returnKeyLabel`. @@ -191,7 +228,7 @@ module.exports = { * - `route` * - `yahoo` */ - returnKeyType: PropTypes.oneOf([ + returnKeyType: (PropTypes.oneOf([ // Cross-platform 'done', 'go', @@ -208,7 +245,21 @@ module.exports = { 'join', 'route', 'yahoo', - ]), + ]): React$PropType$Primitive< + | 'done' + | 'go' + | 'next' + | 'search' + | 'send' + | 'none' + | 'previous' + | 'default' + | 'emergency-call' + | 'google' + | 'join' + | 'route' + | 'yahoo', + >), /** * Sets the return key to the label. Use it instead of `returnKeyType`. * @platform android @@ -250,7 +301,11 @@ module.exports = { * The default value is `simple`. * @platform android */ - textBreakStrategy: PropTypes.oneOf(['simple', 'highQuality', 'balanced']), + textBreakStrategy: (PropTypes.oneOf([ + 'simple', + 'highQuality', + 'balanced', + ]): React$PropType$Primitive<'simple' | 'highQuality' | 'balanced'>), /** * Callback that is called when the text input is blurred. */ @@ -348,15 +403,15 @@ module.exports = { * * @platform ios */ - selectionState: PropTypes.instanceOf(DocumentSelectionState), + selectionState: (PropTypes.instanceOf(DocumentSelectionState): void), /** * The start and end of the text input's selection. Set start and end to * the same value to position the cursor. */ - selection: PropTypes.shape({ + selection: (PropTypes.shape({ start: PropTypes.number.isRequired, end: PropTypes.number, - }), + }): React$PropType$Primitive<{end?: number, start: number}>), /** * The value to show for the text input. `TextInput` is a controlled * component, which means the native value will be forced to match this @@ -378,12 +433,14 @@ module.exports = { * This property is supported only for single-line TextInput component. * @platform ios */ - clearButtonMode: PropTypes.oneOf([ + clearButtonMode: (PropTypes.oneOf([ 'never', 'while-editing', 'unless-editing', 'always', - ]), + ]): React$PropType$Primitive< + 'never' | 'while-editing' | 'unless-editing' | 'always', + >), /** * If `true`, clears the text field automatically when editing begins. * @platform ios @@ -471,10 +528,20 @@ module.exports = { * * @platform ios */ - dataDetectorTypes: PropTypes.oneOfType([ + dataDetectorTypes: (PropTypes.oneOfType([ PropTypes.oneOf(DataDetectorTypes), PropTypes.arrayOf(PropTypes.oneOf(DataDetectorTypes)), - ]), + ]): React$PropType$Primitive< + | 'phoneNumber' + | 'link' + | 'address' + | 'calendarEvent' + | 'none' + | 'all' + | Array< + 'phoneNumber' | 'link' | 'address' | 'calendarEvent' | 'none' | 'all', + >, + >), /** * If `true`, caret is hidden. The default value is `false`. * This property is supported only for single-line TextInput component on iOS. @@ -496,7 +563,7 @@ module.exports = { * expected semantic meaning for the content that users enter. * @platform ios */ - textContentType: PropTypes.oneOf([ + textContentType: (PropTypes.oneOf([ 'none', 'URL', 'addressCity', @@ -525,7 +592,36 @@ module.exports = { 'password', 'newPassword', 'oneTimeCode', - ]), + ]): React$PropType$Primitive< + | 'none' + | 'URL' + | 'addressCity' + | 'addressCityAndState' + | 'addressState' + | 'countryName' + | 'creditCardNumber' + | 'emailAddress' + | 'familyName' + | 'fullStreetAddress' + | 'givenName' + | 'jobTitle' + | 'location' + | 'middleName' + | 'name' + | 'namePrefix' + | 'nameSuffix' + | 'nickname' + | 'organizationName' + | 'postalCode' + | 'streetAddressLine1' + | 'streetAddressLine2' + | 'sublocality' + | 'telephoneNumber' + | 'username' + | 'password' + | 'newPassword' + | 'oneTimeCode', + >), /** * When `false`, it will prevent the soft keyboard from showing when the field is focused. * Defaults to `true`. diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index c6f9d9e5eb5255..4c9d13d5e5bd4c 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -38,11 +38,13 @@ function generateRequestId() { const ImageProps = { ...DeprecatedViewPropTypes, - style: DeprecatedStyleSheetPropType(DeprecatedImageStylePropTypes), + style: (DeprecatedStyleSheetPropType( + DeprecatedImageStylePropTypes, + ): ReactPropsCheckType), /** * See https://facebook.github.io/react-native/docs/image.html#source */ - source: PropTypes.oneOfType([ + source: (PropTypes.oneOfType([ PropTypes.shape({ uri: PropTypes.string, headers: PropTypes.objectOf(PropTypes.string), @@ -58,7 +60,16 @@ const ImageProps = { headers: PropTypes.objectOf(PropTypes.string), }), ), - ]), + ]): React$PropType$Primitive< + | {headers?: {[string]: string}, uri?: string} + | number + | Array<{ + headers?: {[string]: string}, + height?: number, + uri?: string, + width?: number, + }>, + >), /** * blurRadius: the blur radius of the blur filter added to the image * @@ -72,13 +83,13 @@ const ImageProps = { /** * See https://facebook.github.io/react-native/docs/image.html#loadingindicatorsource */ - loadingIndicatorSource: PropTypes.oneOfType([ + loadingIndicatorSource: (PropTypes.oneOfType([ PropTypes.shape({ uri: PropTypes.string, }), // Opaque type returned by require('./image.jpg') PropTypes.number, - ]), + ]): React$PropType$Primitive<{uri?: string} | number>), progressiveRenderingEnabled: PropTypes.bool, fadeDuration: PropTypes.number, /** @@ -107,20 +118,26 @@ const ImageProps = { * * See https://facebook.github.io/react-native/docs/image.html#resizemethod */ - resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']), + resizeMethod: (PropTypes.oneOf([ + 'auto', + 'resize', + 'scale', + ]): React$PropType$Primitive<'auto' | 'resize' | 'scale'>), /** * Determines how to resize the image when the frame doesn't match the raw * image dimensions. * * See https://facebook.github.io/react-native/docs/image.html#resizemode */ - resizeMode: PropTypes.oneOf([ + resizeMode: (PropTypes.oneOf([ 'cover', 'contain', 'stretch', 'repeat', 'center', - ]), + ]): React$PropType$Primitive< + 'cover' | 'contain' | 'stretch' | 'repeat' | 'center', + >), }; /** @@ -132,7 +149,7 @@ function getSize( url: string, success: (width: number, height: number) => void, failure?: (error: any) => void, -) { +): any { return ImageLoader.getSize(url) .then(function(sizes) { success(sizes.width, sizes.height); @@ -156,7 +173,7 @@ function getSizeWithHeaders( headers: {[string]: string}, success: (width: number, height: number) => void, failure?: (error: any) => void, -) { +): any { return ImageLoader.getSizeWithHeaders(url, headers) .then(function(sizes) { success(sizes.width, sizes.height); @@ -169,7 +186,7 @@ function getSizeWithHeaders( ); } -function prefetch(url: string, callback: ?Function) { +function prefetch(url: string, callback: ?Function): any { const requestId = generateRequestId(); callback && callback(requestId); return ImageLoader.prefetchImage(url, requestId); diff --git a/Libraries/Image/NativeImageLoader.js b/Libraries/Image/NativeImageLoader.js index 4c36ba7533d2d4..ae84cfe71fab96 100644 --- a/Libraries/Image/NativeImageLoader.js +++ b/Libraries/Image/NativeImageLoader.js @@ -17,4 +17,4 @@ export interface Spec extends TurboModule { +getConstants: () => {||}; } -export default TurboModuleRegistry.getEnforcing('ImageLoader'); +export default (TurboModuleRegistry.getEnforcing('ImageLoader'): Spec); diff --git a/Libraries/Interaction/NativeFrameRateLogger.js b/Libraries/Interaction/NativeFrameRateLogger.js index 9780519c171ac0..d1829065f47c68 100644 --- a/Libraries/Interaction/NativeFrameRateLogger.js +++ b/Libraries/Interaction/NativeFrameRateLogger.js @@ -8,8 +8,8 @@ * @flow */ -import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { +setGlobalOptions: (options: {| @@ -21,4 +21,4 @@ export interface Spec extends TurboModule { +endScroll: () => void; } -export default TurboModuleRegistry.get('FrameRateLogger'); +export default (TurboModuleRegistry.get('FrameRateLogger'): ?Spec); diff --git a/Libraries/Network/RCTNetworking.android.js b/Libraries/Network/RCTNetworking.android.js index c809b8dcdd3a18..b1577a078fc12b 100644 --- a/Libraries/Network/RCTNetworking.android.js +++ b/Libraries/Network/RCTNetworking.android.js @@ -13,9 +13,10 @@ // Do not require the native RCTNetworking module directly! Use this wrapper module instead. // It will add the necessary requestId, so that you don't have to generate it yourself. const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter'); -import NativeNetworkingAndroid from './NativeNetworkingAndroid'; + const convertRequestBody = require('./convertRequestBody'); +import NativeNetworkingAndroid from './NativeNetworkingAndroid'; import type {RequestBody} from './convertRequestBody'; type Header = [string, string]; @@ -87,4 +88,4 @@ class RCTNetworking extends NativeEventEmitter { } } -module.exports = new RCTNetworking(); +module.exports = (new RCTNetworking(): RCTNetworking); diff --git a/Libraries/Utilities/Platform.android.js b/Libraries/Utilities/Platform.android.js index e228adc98d2744..fd0cb70d49be6a 100644 --- a/Libraries/Utilities/Platform.android.js +++ b/Libraries/Utilities/Platform.android.js @@ -20,10 +20,25 @@ export type PlatformSelectSpec = { const Platform = { __constants: null, OS: 'android', - get Version() { + get Version(): number { return this.constants.Version; }, - get constants() { + get constants(): {| + isTesting: boolean, + reactNativeVersion: {| + major: number, + minor: number, + patch: number, + prerelease: ?number, + |}, + Version: number, + Release: string, + Serial: string, + Fingerprint: string, + Model: string, + ServerHost: string, + uiMode: string, + |} { if (this.__constants == null) { this.__constants = NativePlatformConstantsAndroid.getConstants(); } diff --git a/RNTester/js/RNTesterApp.android.js b/RNTester/js/RNTesterApp.android.js index bd5201d86af322..047522f8e3941c 100644 --- a/RNTester/js/RNTesterApp.android.js +++ b/RNTester/js/RNTesterApp.android.js @@ -10,7 +10,16 @@ 'use strict'; +const RNTesterActions = require('./utils/RNTesterActions'); +const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); +const RNTesterExampleList = require('./components/RNTesterExampleList'); +const RNTesterList = require('./utils/RNTesterList'); +const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); const React = require('react'); +const URIActionMap = require('./utils/URIActionMap'); + +const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); + const { AppRegistry, AsyncStorage, @@ -26,14 +35,6 @@ const { UIManager, View, } = require('react-native'); -const RNTesterActions = require('./utils/RNTesterActions'); -const RNTesterExampleContainer = require('./components/RNTesterExampleContainer'); -const RNTesterExampleList = require('./components/RNTesterExampleList'); -const RNTesterList = require('./utils/RNTesterList'); -const RNTesterNavigationReducer = require('./utils/RNTesterNavigationReducer'); -const URIActionMap = require('./utils/URIActionMap'); - -const nativeImageSource = require('../../Libraries/Image/nativeImageSource'); import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; @@ -99,7 +100,7 @@ class RNTesterApp extends React.Component { }); } - render() { + render(): React.Node { if (!this.state) { return null; } diff --git a/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js b/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js index 86a6bd662c5515..5024f2970d5685 100644 --- a/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js +++ b/RNTester/js/examples/ProgressBarAndroid/ProgressBarAndroidExample.android.js @@ -10,10 +10,11 @@ 'use strict'; -const React = require('react'); -const {ProgressBarAndroid: ProgressBar} = require('react-native'); const RNTesterBlock = require('../../components/RNTesterBlock'); const RNTesterPage = require('../../components/RNTesterPage'); +const React = require('react'); + +const {ProgressBarAndroid: ProgressBar} = require('react-native'); import type {ProgressBarAndroidProps} from '../../../../Libraries/Components/ProgressBarAndroid/ProgressBarAndroid'; @@ -57,7 +58,7 @@ class MovingBar extends React.Component { } class ProgressBarAndroidExample extends React.Component<{}> { - render() { + render(): React.Node { return ( diff --git a/RNTester/js/examples/Text/TextExample.android.js b/RNTester/js/examples/Text/TextExample.android.js index dbded71f36ac3e..ae3aa5c81179da 100644 --- a/RNTester/js/examples/Text/TextExample.android.js +++ b/RNTester/js/examples/Text/TextExample.android.js @@ -10,13 +10,14 @@ 'use strict'; -const React = require('react'); -const {StyleSheet, Text, View} = require('react-native'); const RNTesterBlock = require('../../components/RNTesterBlock'); const RNTesterPage = require('../../components/RNTesterPage'); +const React = require('react'); const TextInlineView = require('../../components/TextInlineView'); const TextLegend = require('../../components/TextLegend'); +const {StyleSheet, Text, View} = require('react-native'); + class Entity extends React.Component<{|children: React.Node|}> { render() { return ( @@ -70,7 +71,7 @@ class AttributeToggler extends React.Component<{}, $FlowFixMeState> { } class TextExample extends React.Component<{}> { - render() { + render(): React.Node { return ( diff --git a/RNTester/js/examples/TextInput/TextInputExample.android.js b/RNTester/js/examples/TextInput/TextInputExample.android.js index edeb83eb6092f5..091b89dbf9f791 100644 --- a/RNTester/js/examples/TextInput/TextInputExample.android.js +++ b/RNTester/js/examples/TextInput/TextInputExample.android.js @@ -11,6 +11,7 @@ 'use strict'; const React = require('react'); + const { Text, TextInput, @@ -450,7 +451,7 @@ exports.description = 'Single and multi-line text inputs.'; exports.examples = [ { title: 'Auto-focus', - render: function() { + render: function(): React.Node { return ( -> '_')", - render: function() { + render: function(): React.Node { return ; }, }, { title: 'Auto-capitalize', - render: function() { + render: function(): React.Node { const autoCapitalizeTypes = ['none', 'sentences', 'words', 'characters']; const examples = autoCapitalizeTypes.map(type => { return ( @@ -488,7 +489,7 @@ exports.examples = [ }, { title: 'Auto-correct', - render: function() { + render: function(): React.Node { return ( ; }, }, { title: 'Return key', - render: function() { + render: function(): React.Node { const returnKeyTypes = [ 'none', 'go', @@ -822,7 +823,7 @@ exports.examples = [ }, { title: 'Inline Images', - render: function() { + render: function(): React.Node { return ( { + render: function(): React.Node { return ; }, }, { title: 'Text selection & cursor placement', - render: function() { + render: function(): React.Node { return ( ; class ToastExample extends React.Component { - render() { + render(): React.Node { return ( diff --git a/RNTester/js/utils/RNTesterList.android.js b/RNTester/js/utils/RNTesterList.android.js index 1307335996de32..238fca68defba2 100644 --- a/RNTester/js/utils/RNTesterList.android.js +++ b/RNTester/js/utils/RNTesterList.android.js @@ -226,7 +226,7 @@ const APIExamples: Array = [ }, ]; -const Modules = {}; +const Modules: any = {}; APIExamples.concat(ComponentExamples).forEach(Example => { Modules[Example.key] = Example.module; diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/components/ObjectPropsNativeComponent.js b/packages/react-native-codegen/e2e/__test_fixtures__/components/ObjectPropsNativeComponent.js index ad166c74ca4350..460b8f4f47cf30 100644 --- a/packages/react-native-codegen/e2e/__test_fixtures__/components/ObjectPropsNativeComponent.js +++ b/packages/react-native-codegen/e2e/__test_fixtures__/components/ObjectPropsNativeComponent.js @@ -10,18 +10,19 @@ 'use strict'; +import type {ViewProps} from '../../../../../Libraries/Components/View/ViewPropTypes'; +import type {ImageSource} from '../../../../../Libraries/Image/ImageSource'; import type { PointValue, ColorValue, } from '../../../../../Libraries/StyleSheet/StyleSheetTypes'; -import type {ImageSource} from '../../../../../Libraries/Image/ImageSource'; import type { Int32, Float, WithDefault, } from '../../../../../Libraries/Types/CodegenTypes'; -import type {ViewProps} from '../../../../../Libraries/Components/View/ViewPropTypes'; import codegenNativeComponent from '../../../../../Libraries/Utilities/codegenNativeComponent'; +import type {NativeComponentType} from '../../../../../Libraries/Utilities/codegenNativeComponent'; type ObjectArrayPropType = $ReadOnly<{| array: $ReadOnlyArray, @@ -46,6 +47,6 @@ type NativeProps = $ReadOnly<{| |}>, |}>; -export default codegenNativeComponent( +export default (codegenNativeComponent( 'ObjectPropsNativeComponent', -); +): NativeComponentType); diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeNullableTurboModule.js b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeNullableTurboModule.js index a9c631a30e9fbc..3ccc8876b45df4 100644 --- a/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeNullableTurboModule.js +++ b/packages/react-native-codegen/e2e/__test_fixtures__/modules/NativeNullableTurboModule.js @@ -22,4 +22,6 @@ export interface Spec extends TurboModule { +getValueWithPromise: () => ?Promise; } -export default TurboModuleRegistry.getEnforcing('SampleTurboModule'); +export default (TurboModuleRegistry.getEnforcing( + 'SampleTurboModule', +): Spec); diff --git a/packages/react-native-codegen/src/generators/components/CppHelpers.js b/packages/react-native-codegen/src/generators/components/CppHelpers.js index b05293598b0a19..14363e71b0610a 100644 --- a/packages/react-native-codegen/src/generators/components/CppHelpers.js +++ b/packages/react-native-codegen/src/generators/components/CppHelpers.js @@ -91,7 +91,7 @@ function getImports(properties: $ReadOnlyArray): Set { function generateStructName( componentName: string, parts: $ReadOnlyArray = [], -) { +): string { const additional = parts.map(toSafeCppString).join(''); return `${componentName}${additional}Struct`; } diff --git a/packages/react-native-codegen/src/parsers/flow/components/props.js b/packages/react-native-codegen/src/parsers/flow/components/props.js index 3bd8591d9f41c7..0d13e710783652 100644 --- a/packages/react-native-codegen/src/parsers/flow/components/props.js +++ b/packages/react-native-codegen/src/parsers/flow/components/props.js @@ -10,12 +10,12 @@ 'use strict'; +const {getValueFromTypes} = require('../utils.js'); + import type {PropTypeShape} from '../../../CodegenSchema.js'; import type {TypeMap} from '../utils.js'; -const {getValueFromTypes} = require('../utils.js'); - -function getPropProperties(propsTypeName: string, types: TypeMap) { +function getPropProperties(propsTypeName: string, types: TypeMap): $FlowFixMe { const typeAlias = types[propsTypeName]; try { return typeAlias.right.typeParameters.params[0].properties; From bb05176a4bcac9545ebfc54cf75cdbf0fd7d1273 Mon Sep 17 00:00:00 2001 From: ifsnow Date: Fri, 23 Aug 2019 11:43:52 -0700 Subject: [PATCH 0046/1244] Better implementation for getItemCount on FlatList (#26164) Summary: Flatlist's `getItemCount` function is frequently called internally by VirtualizedList. As with other functions, we can remove unnecessary operations with the `numColumns` value. This makes it much more efficient. ## Changelog [Internal] [Changed] - Better implementation for getItemCount on FlatList Pull Request resolved: https://github.com/facebook/react-native/pull/26164 Test Plan: Not required Differential Revision: D16989335 Pulled By: sahrens fbshipit-source-id: b0075b2c2aeb9b9d7644c8bb18702a7cca8a4dce --- Libraries/Lists/FlatList.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 3afed1ba5a75b7..f9fb2a6aca1e00 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -560,7 +560,12 @@ class FlatList extends React.PureComponent, void> { }; _getItemCount = (data: ?Array): number => { - return data ? Math.ceil(data.length / this.props.numColumns) : 0; + if (data) { + const {numColumns} = this.props; + return numColumns > 1 ? Math.ceil(data.length / numColumns) : data.length; + } else { + return 0; + } }; _keyExtractor = (items: ItemT | Array, index: number) => { From db9fab4473519c6dc6803cd8985239902742c4ce Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Fri, 23 Aug 2019 11:50:27 -0700 Subject: [PATCH 0047/1244] Add unstable_setExceptionDecorator Summary: Adds a way for the app to add information to an exception report before it is sent to native. This API is not final. Reviewed By: rubennorte Differential Revision: D16984151 fbshipit-source-id: 8450356d608e05deaed437e2a35094cd16962027 --- Libraries/Core/ExceptionsManager.js | 72 ++++++++++++++---- .../Core/__tests__/ExceptionsManager-test.js | 74 +++++++++++++++++++ 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index 7060fdd618947d..3531c05c1b3822 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -11,11 +11,42 @@ 'use strict'; import type {ExtendedError} from './Devtools/parseErrorStack'; +import type {ExceptionData} from './NativeExceptionsManager'; class SyntheticError extends Error { name: string = ''; } +type ExceptionDecorator = ExceptionData => ExceptionData; + +let userExceptionDecorator: ?ExceptionDecorator; +let inUserExceptionDecorator = false; + +/** + * Allows the app to add information to the exception report before it is sent + * to native. This API is not final. + */ + +function unstable_setExceptionDecorator( + exceptionDecorator: ?ExceptionDecorator, +) { + userExceptionDecorator = exceptionDecorator; +} + +function preprocessException(data: ExceptionData): ExceptionData { + if (userExceptionDecorator && !inUserExceptionDecorator) { + inUserExceptionDecorator = true; + try { + return userExceptionDecorator(data); + } catch { + // Fall through + } finally { + inUserExceptionDecorator = false; + } + } + return data; +} + /** * Handles the developer-visible aspect of errors and exceptions */ @@ -49,21 +80,25 @@ function reportException(e: ExtendedError, isFatal: boolean) { message = e.jsEngine == null ? message : `${message}, js engine: ${e.jsEngine}`; - NativeExceptionsManager.reportException({ - message, - originalMessage: message === originalMessage ? null : originalMessage, - name: e.name == null || e.name === '' ? null : e.name, - componentStack: - typeof e.componentStack === 'string' ? e.componentStack : null, - stack, - id: currentExceptionID, - isFatal, - extraData: { - jsEngine: e.jsEngine, - rawStack: e.stack, - framesPopped: e.framesToPop, - }, - }); + + NativeExceptionsManager.reportException( + preprocessException({ + message, + originalMessage: message === originalMessage ? null : originalMessage, + name: e.name == null || e.name === '' ? null : e.name, + componentStack: + typeof e.componentStack === 'string' ? e.componentStack : null, + stack, + id: currentExceptionID, + isFatal, + extraData: { + jsEngine: e.jsEngine, + rawStack: e.stack, + framesPopped: e.framesToPop, + }, + }), + ); + if (__DEV__) { if (e.preventSymbolication === true) { return; @@ -158,4 +193,9 @@ function installConsoleErrorReporter() { } } -module.exports = {handleException, installConsoleErrorReporter, SyntheticError}; +module.exports = { + handleException, + installConsoleErrorReporter, + SyntheticError, + unstable_setExceptionDecorator, +}; diff --git a/Libraries/Core/__tests__/ExceptionsManager-test.js b/Libraries/Core/__tests__/ExceptionsManager-test.js index f76b93a585ea4b..596c789e155e1d 100644 --- a/Libraries/Core/__tests__/ExceptionsManager-test.js +++ b/Libraries/Core/__tests__/ExceptionsManager-test.js @@ -457,6 +457,80 @@ describe('ExceptionsManager', () => { ); }); }); + + describe('unstable_setExceptionDecorator', () => { + test('modifying the exception data', () => { + const error = new Error('Some error happened'); + const decorator = jest.fn().mockImplementation(data => ({ + ...data, + message: 'decorated: ' + data.message, + })); + + // Report the same exception with and without the decorator + ExceptionsManager.handleException(error, true); + ExceptionsManager.unstable_setExceptionDecorator(decorator); + ExceptionsManager.handleException(error, true); + + expect(nativeReportException.mock.calls.length).toBe(2); + expect(decorator.mock.calls.length).toBe(1); + + const withoutDecoratorInstalled = nativeReportException.mock.calls[0][0]; + const afterDecorator = nativeReportException.mock.calls[1][0]; + const beforeDecorator = decorator.mock.calls[0][0]; + + expect(afterDecorator.id).toEqual(beforeDecorator.id); + + // id will change between successive exceptions + delete withoutDecoratorInstalled.id; + delete beforeDecorator.id; + delete afterDecorator.id; + + expect(withoutDecoratorInstalled).toEqual(beforeDecorator); + expect(afterDecorator).toEqual({ + ...beforeDecorator, + message: 'decorated: ' + beforeDecorator.message, + }); + }); + + test('clearing a decorator', () => { + const error = new Error('Some error happened'); + const decorator = jest.fn().mockImplementation(data => ({ + ...data, + message: 'decorated: ' + data.message, + })); + + ExceptionsManager.unstable_setExceptionDecorator(decorator); + ExceptionsManager.unstable_setExceptionDecorator(null); + ExceptionsManager.handleException(error, true); + + expect(decorator).not.toHaveBeenCalled(); + expect(nativeReportException).toHaveBeenCalled(); + }); + + test('prevents decorator recursion', () => { + const error = new Error('Some error happened'); + const decorator = jest.fn().mockImplementation(data => { + console.error('Logging an error within the decorator'); + return { + ...data, + message: 'decorated: ' + data.message, + }; + }); + + ExceptionsManager.installConsoleErrorReporter(); + ExceptionsManager.unstable_setExceptionDecorator(decorator); + ExceptionsManager.handleException(error, true); + + expect(decorator).toHaveBeenCalled(); + expect(nativeReportException).toHaveBeenCalledTimes(2); + expect(nativeReportException.mock.calls[0][0].message).toMatch( + /Logging an error within the decorator/, + ); + expect(nativeReportException.mock.calls[1][0].message).toMatch( + /decorated: .*Some error happened/, + ); + }); + }); }); const linesByFile = new Map(); From f229d674987f3e91f70a819cee80911e006ba2b0 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Fri, 23 Aug 2019 11:58:36 -0700 Subject: [PATCH 0048/1244] Make RCTAccessibilityManger a TurboModule Summary: Move RCTAccessibilityManager to CoreModules (since that's the only dir that supports TM). Fixup some variable names to match spec. Reviewed By: RSNara Differential Revision: D16861739 fbshipit-source-id: a0a53b221dcc172979d1f2c83851ab92e23f2333 --- .../NativeAccessibilityManager.js | 2 +- .../FBReactNativeSpec-generated.mm | 8 +- .../FBReactNativeSpec/FBReactNativeSpec.h | 34 ++--- Libraries/Text/Text/RCTTextViewManager.m | 12 +- .../Text/TextInput/RCTBaseTextInputView.m | 1 - .../TextInput/RCTBaseTextInputViewManager.m | 13 +- RNTester/RNTester/AppDelegate.mm | 2 +- React/CoreModules/BUCK | 4 + React/CoreModules/CoreModulesPlugins.h | 1 + React/CoreModules/CoreModulesPlugins.mm | 3 +- .../RCTAccessibilityManager.h | 0 .../RCTAccessibilityManager.mm} | 118 ++++++++++-------- React/Modules/RCTUIManager.m | 14 ++- 13 files changed, 119 insertions(+), 93 deletions(-) rename React/{Modules => CoreModules}/RCTAccessibilityManager.h (100%) rename React/{Modules/RCTAccessibilityManager.m => CoreModules/RCTAccessibilityManager.mm} (77%) diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js index c9b042a665bbb4..0a1abe5792492b 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -38,7 +38,7 @@ export interface Spec extends TurboModule { onSuccess: (isScreenReaderEnabled: boolean) => void, onError: (error: Object) => void, ) => void; - +setAccessibilityContentSizeMultipliers: (JSMultiipliers: {| + +setAccessibilityContentSizeMultipliers: (JSMultipliers: {| +extraSmall?: ?number, +small?: ?number, +medium?: ?number, diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm index eb25fc7d24bcf3..5ec9e809029750 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm @@ -55,10 +55,10 @@ } // namespace react } // namespace facebook -@implementation RCTCxxConvert (NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultiipliers) -+ (RCTManagedPointer *)JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultiipliers:(id)json +@implementation RCTCxxConvert (NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultipliers) ++ (RCTManagedPointer *)JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultipliers:(id)json { - return facebook::react::managedPointer(json); + return facebook::react::managedPointer(json); } @end namespace facebook { @@ -125,7 +125,7 @@ + (RCTManagedPointer *)JS_NativeAccessibilityManager_SpecSetAccessibilityContent methodMap_["setAccessibilityContentSizeMultipliers"] = MethodMetadata {1, __hostFunction_NativeAccessibilityManagerSpecJSI_setAccessibilityContentSizeMultipliers}; - setMethodArgConversionSelector(@"setAccessibilityContentSizeMultipliers", 0, @"JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultiipliers:"); + setMethodArgConversionSelector(@"setAccessibilityContentSizeMultipliers", 0, @"JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultipliers:"); methodMap_["setAccessibilityFocus"] = MethodMetadata {1, __hostFunction_NativeAccessibilityManagerSpecJSI_setAccessibilityFocus}; diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index eee2be7d6fcb37..c0d786e86dbfef 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -50,7 +50,7 @@ namespace facebook { namespace JS { namespace NativeAccessibilityManager { - struct SpecSetAccessibilityContentSizeMultipliersJSMultiipliers { + struct SpecSetAccessibilityContentSizeMultipliersJSMultipliers { folly::Optional extraSmall() const; folly::Optional small() const; folly::Optional medium() const; @@ -64,15 +64,15 @@ namespace JS { folly::Optional accessibilityExtraExtraLarge() const; folly::Optional accessibilityExtraExtraExtraLarge() const; - SpecSetAccessibilityContentSizeMultipliersJSMultiipliers(NSDictionary *const v) : _v(v) {} + SpecSetAccessibilityContentSizeMultipliersJSMultipliers(NSDictionary *const v) : _v(v) {} private: NSDictionary *_v; }; } } -@interface RCTCxxConvert (NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultiipliers) -+ (RCTManagedPointer *)JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultiipliers:(id)json; +@interface RCTCxxConvert (NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultipliers) ++ (RCTManagedPointer *)JS_NativeAccessibilityManager_SpecSetAccessibilityContentSizeMultipliersJSMultipliers:(id)json; @end @protocol NativeAccessibilityManagerSpec @@ -88,7 +88,7 @@ namespace JS { onError:(RCTResponseSenderBlock)onError; - (void)getCurrentVoiceOverState:(RCTResponseSenderBlock)onSuccess onError:(RCTResponseSenderBlock)onError; -- (void)setAccessibilityContentSizeMultipliers:(JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers &)JSMultiipliers; +- (void)setAccessibilityContentSizeMultipliers:(JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers &)JSMultipliers; - (void)setAccessibilityFocus:(double)reactTag; - (void)announceForAccessibility:(NSString *)announcement; @@ -2329,62 +2329,62 @@ namespace facebook { #import -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::extraSmall() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::extraSmall() const { id const p = _v[@"extraSmall"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::small() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::small() const { id const p = _v[@"small"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::medium() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::medium() const { id const p = _v[@"medium"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::large() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::large() const { id const p = _v[@"large"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::extraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::extraLarge() const { id const p = _v[@"extraLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::extraExtraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::extraExtraLarge() const { id const p = _v[@"extraExtraLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::extraExtraExtraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::extraExtraExtraLarge() const { id const p = _v[@"extraExtraExtraLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::accessibilityMedium() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::accessibilityMedium() const { id const p = _v[@"accessibilityMedium"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::accessibilityLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::accessibilityLarge() const { id const p = _v[@"accessibilityLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::accessibilityExtraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::accessibilityExtraLarge() const { id const p = _v[@"accessibilityExtraLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::accessibilityExtraExtraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::accessibilityExtraExtraLarge() const { id const p = _v[@"accessibilityExtraExtraLarge"]; return RCTBridgingToOptionalDouble(p); } -inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultiipliers::accessibilityExtraExtraExtraLarge() const +inline folly::Optional JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers::accessibilityExtraExtraExtraLarge() const { id const p = _v[@"accessibilityExtraExtraExtraLarge"]; return RCTBridgingToOptionalDouble(p); diff --git a/Libraries/Text/Text/RCTTextViewManager.m b/Libraries/Text/Text/RCTTextViewManager.m index 8b4db638a2c055..47f0b8721fa424 100644 --- a/Libraries/Text/Text/RCTTextViewManager.m +++ b/Libraries/Text/Text/RCTTextViewManager.m @@ -7,7 +7,6 @@ #import -#import #import #import #import @@ -46,8 +45,9 @@ - (void)setBridge:(RCTBridge *)bridge [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDidUpdateMultiplierNotification) - name:RCTAccessibilityManagerDidUpdateMultiplierNotification - object:bridge.accessibilityManager]; + name:@"RCTAccessibilityManagerDidUpdateMultiplierNotification" + object:[bridge moduleForName:@"AccessibilityManager" + lazilyLoadIfNecessary:YES]]; } - (void)dealloc @@ -63,7 +63,8 @@ - (UIView *)view - (RCTShadowView *)shadowView { RCTTextShadowView *shadowView = [[RCTTextShadowView alloc] initWithBridge:self.bridge]; - shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + shadowView.textAttributes.fontSizeMultiplier = [[[self.bridge moduleForName:@"AccessibilityManager"] + valueForKey:@"multiplier"] floatValue]; [_shadowViews addObject:shadowView]; return shadowView; } @@ -81,7 +82,8 @@ - (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager - (void)handleDidUpdateMultiplierNotification { - CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + CGFloat fontSizeMultiplier = [[[self.bridge moduleForName:@"AccessibilityManager"] + valueForKey:@"multiplier"] floatValue]; NSHashTable *shadowViews = _shadowViews; RCTExecuteOnUIManagerQueue(^{ diff --git a/Libraries/Text/TextInput/RCTBaseTextInputView.m b/Libraries/Text/TextInput/RCTBaseTextInputView.m index 6057a48c0a6359..283c3213976668 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputView.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputView.m @@ -7,7 +7,6 @@ #import -#import #import #import #import diff --git a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index f57b69d1cd6121..008a02636736bb 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m @@ -7,7 +7,6 @@ #import -#import #import #import #import @@ -74,7 +73,9 @@ @implementation RCTBaseTextInputViewManager - (RCTShadowView *)shadowView { RCTBaseTextInputShadowView *shadowView = [[RCTBaseTextInputShadowView alloc] initWithBridge:self.bridge]; - shadowView.textAttributes.fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + shadowView.textAttributes.fontSizeMultiplier = [[[self.bridge + moduleForName:@"AccessibilityManager" + lazilyLoadIfNecessary:YES] valueForKey:@"multiplier"] floatValue]; [_shadowViews addObject:shadowView]; return shadowView; } @@ -89,8 +90,9 @@ - (void)setBridge:(RCTBridge *)bridge [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDidUpdateMultiplierNotification) - name:RCTAccessibilityManagerDidUpdateMultiplierNotification - object:bridge.accessibilityManager]; + name:@"RCTAccessibilityManagerDidUpdateMultiplierNotification" + object:[bridge moduleForName:@"AccessibilityManager" + lazilyLoadIfNecessary:YES]]; } - (void)dealloc @@ -111,7 +113,8 @@ - (void)uiManagerWillPerformMounting:(__unused RCTUIManager *)uiManager - (void)handleDidUpdateMultiplierNotification { - CGFloat fontSizeMultiplier = self.bridge.accessibilityManager.multiplier; + CGFloat fontSizeMultiplier = [[[self.bridge moduleForName:@"AccessibilityManager"] + valueForKey:@"multiplier"] floatValue]; NSHashTable *shadowViews = _shadowViews; RCTExecuteOnUIManagerQueue(^{ diff --git a/RNTester/RNTester/AppDelegate.mm b/RNTester/RNTester/AppDelegate.mm index f390405d3db047..e7c89098edc9d1 100644 --- a/RNTester/RNTester/AppDelegate.mm +++ b/RNTester/RNTester/AppDelegate.mm @@ -108,6 +108,7 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge - (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge { + _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:self]; __weak __typeof(self) weakSelf = self; return std::make_unique([weakSelf, bridge](facebook::jsi::Runtime &runtime) { if (!bridge) { @@ -115,7 +116,6 @@ - (void)loadSourceForBridge:(RCTBridge *)bridge } __typeof(self) strongSelf = weakSelf; if (strongSelf) { - strongSelf->_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge delegate:strongSelf]; [strongSelf->_turboModuleManager installJSBindingWithRuntime:&runtime]; } }); diff --git a/React/CoreModules/BUCK b/React/CoreModules/BUCK index dfd93ea49631ea..cc18821485d42f 100644 --- a/React/CoreModules/BUCK +++ b/React/CoreModules/BUCK @@ -38,6 +38,10 @@ rn_apple_library( ["-D PIC_MODIFIER=@PLT"], )], plugins = react_module_plugin_providers( + name = "AccessibilityManager", + native_class_func = "RCTAccessibilityManagerCls", + ) + + react_module_plugin_providers( name = "DeviceInfo", native_class_func = "RCTDeviceInfoCls", ) + diff --git a/React/CoreModules/CoreModulesPlugins.h b/React/CoreModules/CoreModulesPlugins.h index 8d49aaf456f183..849ba766f5f5b0 100644 --- a/React/CoreModules/CoreModulesPlugins.h +++ b/React/CoreModules/CoreModulesPlugins.h @@ -29,6 +29,7 @@ extern "C" { Class RCTCoreModulesClassProvider(const char *name); // Lookup functions +Class RCTAccessibilityManagerCls(void); Class RCTDeviceInfoCls(void); Class RCTExceptionsManagerCls(void); Class RCTImageLoaderCls(void); diff --git a/React/CoreModules/CoreModulesPlugins.mm b/React/CoreModules/CoreModulesPlugins.mm index 4b7a90103c99c7..6b14b5f0dbb923 100644 --- a/React/CoreModules/CoreModulesPlugins.mm +++ b/React/CoreModules/CoreModulesPlugins.mm @@ -17,7 +17,8 @@ #import static std::unordered_map sCoreModuleClassMap = { - {"DeviceInfo", RCTDeviceInfoCls}, + {"AccessibilityManager", RCTAccessibilityManagerCls}, +{"DeviceInfo", RCTDeviceInfoCls}, {"ExceptionsManager", RCTExceptionsManagerCls}, {"ImageLoader", RCTImageLoaderCls}, {"PlatformConstants", RCTPlatformCls}, diff --git a/React/Modules/RCTAccessibilityManager.h b/React/CoreModules/RCTAccessibilityManager.h similarity index 100% rename from React/Modules/RCTAccessibilityManager.h rename to React/CoreModules/RCTAccessibilityManager.h diff --git a/React/Modules/RCTAccessibilityManager.m b/React/CoreModules/RCTAccessibilityManager.mm similarity index 77% rename from React/Modules/RCTAccessibilityManager.m rename to React/CoreModules/RCTAccessibilityManager.mm index cf41839935b0be..4e8b935617ecbd 100644 --- a/React/Modules/RCTAccessibilityManager.m +++ b/React/CoreModules/RCTAccessibilityManager.mm @@ -7,36 +7,18 @@ #import "RCTAccessibilityManager.h" -#import "RCTUIManager.h" -#import "RCTBridge.h" -#import "RCTConvert.h" -#import "RCTEventDispatcher.h" -#import "RCTLog.h" +#import +#import +#import +#import +#import +#import -NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification = @"RCTAccessibilityManagerDidUpdateMultiplierNotification"; +#import "CoreModulesPlugins.h" -static NSString *UIKitCategoryFromJSCategory(NSString *JSCategory) -{ - static NSDictionary *map = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - map = @{@"extraSmall": UIContentSizeCategoryExtraSmall, - @"small": UIContentSizeCategorySmall, - @"medium": UIContentSizeCategoryMedium, - @"large": UIContentSizeCategoryLarge, - @"extraLarge": UIContentSizeCategoryExtraLarge, - @"extraExtraLarge": UIContentSizeCategoryExtraExtraLarge, - @"extraExtraExtraLarge": UIContentSizeCategoryExtraExtraExtraLarge, - @"accessibilityMedium": UIContentSizeCategoryAccessibilityMedium, - @"accessibilityLarge": UIContentSizeCategoryAccessibilityLarge, - @"accessibilityExtraLarge": UIContentSizeCategoryAccessibilityExtraLarge, - @"accessibilityExtraExtraLarge": UIContentSizeCategoryAccessibilityExtraExtraLarge, - @"accessibilityExtraExtraExtraLarge": UIContentSizeCategoryAccessibilityExtraExtraExtraLarge}; - }); - return map[JSCategory]; -} +NSString *const RCTAccessibilityManagerDidUpdateMultiplierNotification = @"RCTAccessibilityManagerDidUpdateMultiplierNotification"; -@interface RCTAccessibilityManager () +@interface RCTAccessibilityManager () @property (nonatomic, copy) NSString *contentSizeCategory; @property (nonatomic, assign) CGFloat multiplier; @@ -265,21 +247,39 @@ - (void)setMultipliers:(NSDictionary *)multipliers return _multipliers; } -RCT_EXPORT_METHOD(setAccessibilityContentSizeMultipliers:(NSDictionary *)JSMultipliers) +RCT_EXPORT_METHOD(setAccessibilityContentSizeMultipliers:(JS::NativeAccessibilityManager::SpecSetAccessibilityContentSizeMultipliersJSMultipliers &)JSMultipliers) { NSMutableDictionary *multipliers = [NSMutableDictionary new]; - for (NSString *__nonnull JSCategory in JSMultipliers) { - NSNumber *m = [RCTConvert NSNumber:JSMultipliers[JSCategory]]; - NSString *UIKitCategory = UIKitCategoryFromJSCategory(JSCategory); - multipliers[UIKitCategory] = m; - } + setMultipliers(multipliers, UIContentSizeCategoryExtraSmall, JSMultipliers.extraSmall()); + setMultipliers(multipliers, UIContentSizeCategorySmall, JSMultipliers.small()); + setMultipliers(multipliers, UIContentSizeCategoryMedium, JSMultipliers.medium()); + setMultipliers(multipliers, UIContentSizeCategoryLarge, JSMultipliers.large()); + setMultipliers(multipliers, UIContentSizeCategoryExtraLarge, JSMultipliers.extraLarge()); + setMultipliers(multipliers, UIContentSizeCategoryExtraExtraLarge, JSMultipliers.extraExtraLarge()); + setMultipliers(multipliers, UIContentSizeCategoryExtraExtraExtraLarge, JSMultipliers.extraExtraExtraLarge()); + setMultipliers(multipliers, UIContentSizeCategoryAccessibilityMedium, JSMultipliers.accessibilityMedium()); + setMultipliers(multipliers, UIContentSizeCategoryAccessibilityLarge, JSMultipliers.accessibilityLarge()); + setMultipliers(multipliers, UIContentSizeCategoryAccessibilityExtraLarge, JSMultipliers.accessibilityExtraLarge()); + setMultipliers(multipliers, UIContentSizeCategoryAccessibilityExtraExtraLarge, + JSMultipliers.accessibilityExtraExtraLarge()); + setMultipliers(multipliers, UIContentSizeCategoryAccessibilityExtraExtraExtraLarge, + JSMultipliers.accessibilityExtraExtraExtraLarge()); self.multipliers = multipliers; } -RCT_EXPORT_METHOD(setAccessibilityFocus:(nonnull NSNumber *)reactTag) +static void setMultipliers(NSMutableDictionary *multipliers, + NSString *key, + folly::Optional optionalDouble) +{ + if (optionalDouble.hasValue()) { + multipliers[key] = @(optionalDouble.value()); + } +} + +RCT_EXPORT_METHOD(setAccessibilityFocus:(double)reactTag) { dispatch_async(dispatch_get_main_queue(), ^{ - UIView *view = [self.bridge.uiManager viewForReactTag:reactTag]; + UIView *view = [self.bridge.uiManager viewForReactTag:@(reactTag)]; UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, view); }); } @@ -296,40 +296,47 @@ - (void)setMultipliers:(NSDictionary *)multipliers } } -RCT_EXPORT_METHOD(getCurrentBoldTextState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) +RCT_EXPORT_METHOD(getCurrentBoldTextState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) +{ + onSuccess(@[@(_isBoldTextEnabled)]); +} + +RCT_EXPORT_METHOD(getCurrentGrayscaleState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) { - callback(@[@(_isBoldTextEnabled)]); + onSuccess(@[@(_isGrayscaleEnabled)]); } -RCT_EXPORT_METHOD(getCurrentGrayscaleState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) +RCT_EXPORT_METHOD(getCurrentInvertColorsState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) { - callback(@[@(_isGrayscaleEnabled)]); + onSuccess(@[@(_isInvertColorsEnabled)]); } -RCT_EXPORT_METHOD(getCurrentInvertColorsState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) +RCT_EXPORT_METHOD(getCurrentReduceMotionState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) { - callback(@[@(_isInvertColorsEnabled)]); + onSuccess(@[@(_isReduceMotionEnabled)]); } -RCT_EXPORT_METHOD(getCurrentReduceMotionState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) +RCT_EXPORT_METHOD(getCurrentReduceTransparencyState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) { - callback(@[@(_isReduceMotionEnabled)]); + onSuccess(@[@(_isReduceTransparencyEnabled)]); } -RCT_EXPORT_METHOD(getCurrentReduceTransparencyState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) +RCT_EXPORT_METHOD(getCurrentVoiceOverState:(RCTResponseSenderBlock)onSuccess + onError:(__unused RCTResponseSenderBlock)onError) { - callback(@[@(_isReduceTransparencyEnabled)]); + onSuccess(@[@(_isVoiceOverEnabled)]); } -RCT_EXPORT_METHOD(getCurrentVoiceOverState:(RCTResponseSenderBlock)callback - error:(__unused RCTResponseSenderBlock)error) + +- (std::shared_ptr)getTurboModuleWithJsInvoker: +(std::shared_ptr)jsInvoker { - callback(@[@(_isVoiceOverEnabled)]); + return std::make_shared(self, jsInvoker); } @end @@ -342,3 +349,8 @@ - (RCTAccessibilityManager *)accessibilityManager } @end + +Class RCTAccessibilityManagerCls(void) +{ + return RCTAccessibilityManager.class; +} diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index f2bddbf64608a9..6e65c034caf38f 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -9,7 +9,6 @@ #import -#import "RCTAccessibilityManager.h" #import "RCTAssert.h" #import "RCTBridge+Private.h" #import "RCTBridge.h" @@ -181,8 +180,9 @@ - (void)setBridge:(RCTBridge *)bridge dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveNewContentSizeMultiplier) - name:RCTAccessibilityManagerDidUpdateMultiplierNotification - object:self->_bridge.accessibilityManager]; + name:@"RCTAccessibilityManagerDidUpdateMultiplierNotification" + object:[self->_bridge moduleForName:@"AccessibilityManager" + lazilyLoadIfNecessary:YES]]; }); #if !TARGET_OS_TV [[NSNotificationCenter defaultCenter] addObserver:self @@ -200,8 +200,12 @@ - (void)didReceiveNewContentSizeMultiplier // Report the event across the bridge. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" - [_bridge.eventDispatcher sendDeviceEventWithName:@"didUpdateContentSizeMultiplier" - body:@([_bridge.accessibilityManager multiplier])]; + id multiplier = [[self->_bridge moduleForName:@"AccessibilityManager" + lazilyLoadIfNecessary:YES] valueForKey:@"multiplier"]; + if (multiplier) { + [_bridge.eventDispatcher sendDeviceEventWithName:@"didUpdateContentSizeMultiplier" + body:multiplier]; + } #pragma clang diagnostic pop RCTExecuteOnUIManagerQueue(^{ From 41525c02a26b36114063cccd8373141bff2603b9 Mon Sep 17 00:00:00 2001 From: Peter Argany Date: Fri, 23 Aug 2019 11:58:36 -0700 Subject: [PATCH 0049/1244] Allow for null bridge in RCTSurfacePresenter Facebook: This technically culminates M8 for iOS in Venice :D We're now rendering `View` and `Text` completely without the bridge! Reviewed By: shergin Differential Revision: D16950332 fbshipit-source-id: f8c896323756411f5ac97586c0d85fdd6e39ed40 --- React/Fabric/RCTSurfacePresenter.h | 2 +- React/Fabric/RCTSurfacePresenter.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.h b/React/Fabric/RCTSurfacePresenter.h index f58ec46af8eb5c..db69e41e611872 100644 --- a/React/Fabric/RCTSurfacePresenter.h +++ b/React/Fabric/RCTSurfacePresenter.h @@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN */ @interface RCTSurfacePresenter : NSObject -- (instancetype)initWithBridge:(RCTBridge *)bridge +- (instancetype)initWithBridge:(RCTBridge *_Nullable)bridge config:(std::shared_ptr)config imageLoader:(RCTImageLoader *)imageLoader runtimeExecutor:(facebook::react::RuntimeExecutor)runtimeExecutor; diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 058f8950550ae4..44a99619ee3e37 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -65,7 +65,7 @@ @implementation RCTSurfacePresenter { RuntimeExecutor _runtimeExecutor; } -- (instancetype)initWithBridge:(RCTBridge *)bridge +- (instancetype)initWithBridge:(RCTBridge *_Nullable)bridge config:(std::shared_ptr)config imageLoader:(RCTImageLoader *)imageLoader runtimeExecutor:(RuntimeExecutor)runtimeExecutor From f8a64f9d61054046bffc286df3e9abf805aac0d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kr=C3=BCger?= Date: Fri, 23 Aug 2019 13:01:13 -0700 Subject: [PATCH 0050/1244] Implement fading edges for ScrollView and it's dependent FlatList (#26163) Summary: This should add props for enabling horizontal and vertical fading edges for Scrollview and FlatList. These fading edges are used to communicate to the user that there is more content to see. ## Changelog [Android] [Added] - fading edges props to the FlatList and ScrollView components Pull Request resolved: https://github.com/facebook/react-native/pull/26163 Test Plan: Open the React Native test app and navigate to the FlatList section. Enable the `useFadingEdges` switch and insert a number into `Fading edge length`. ![device-2019-08-23-123745](https://user-images.githubusercontent.com/222393/63587150-7385cb00-c5a3-11e9-98dc-bffe8276d30c.png) ![device-2019-08-23-123844](https://user-images.githubusercontent.com/222393/63587156-75e82500-c5a3-11e9-9e9f-66876ac8f506.png) Differential Revision: D16992488 Pulled By: sahrens fbshipit-source-id: f72a9a890d9056bb017cc5747c6f66b7c35633dd --- Libraries/Components/ScrollView/ScrollView.js | 21 +++++++++++++ Libraries/Lists/FlatList.js | 12 +++++++ .../js/examples/FlatList/FlatListExample.js | 31 ++++++++++++++++++- .../ReactHorizontalScrollViewManager.java | 10 ++++++ .../views/scroll/ReactScrollViewManager.java | 10 ++++++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index b4298158b3354f..019a48b4f3c5df 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -335,6 +335,27 @@ type AndroidProps = $ReadOnly<{| * @platform android */ persistentScrollbar?: ?boolean, + /** + * Fades out the left and right edges. + * The default value is false. + * + * @platform android + */ + horizontalFadingEdgesEnabled?: ?boolean, + /** + * Fades out the up and down edges. + * The default value is false. + * + * @platform android + */ + verticalFadingEdgesEnabled?: ?boolean, + /** + * The amount of fading. + * The default value is 0. + * + * @platform android + */ + fadingEdgeLength?: ?number, |}>; type VRProps = $ReadOnly<{| diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index f9fb2a6aca1e00..26d87615880826 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -233,6 +233,18 @@ type OptionalProps = { * will be called when its corresponding ViewabilityConfig's conditions are met. */ viewabilityConfigCallbackPairs?: Array, + /** + * See `ScrollView` for flow type and further documentation. + */ + horizontalFadingEdgesEnabled?: ?boolean, + /** + * See `ScrollView` for flow type and further documentation. + */ + verticalFadingEdgesEnabled?: ?boolean, + /** + * See `ScrollView` for flow type and further documentation. + */ + fadingEdgeLength?: ?number, }; export type Props = RequiredProps & OptionalProps & diff --git a/RNTester/js/examples/FlatList/FlatListExample.js b/RNTester/js/examples/FlatList/FlatListExample.js index bb7cc9afe88c02..86a0741c002643 100644 --- a/RNTester/js/examples/FlatList/FlatListExample.js +++ b/RNTester/js/examples/FlatList/FlatListExample.js @@ -29,7 +29,14 @@ const { pressItem, renderSmallSwitchOption, } = require('../../components/ListExampleShared'); -const {Alert, Animated, StyleSheet, View} = require('react-native'); +const { + Alert, + Animated, + Platform, + StyleSheet, + TextInput, + View, +} = require('react-native'); import type {Item} from '../../components/ListExampleShared'; @@ -51,6 +58,8 @@ type State = {| virtualized: boolean, empty: boolean, useFlatListItemComponent: boolean, + useFadingEdges: boolean, + fadingEdgeLength: number, |}; class FlatListExample extends React.PureComponent { @@ -65,6 +74,8 @@ class FlatListExample extends React.PureComponent { virtualized: true, empty: false, useFlatListItemComponent: false, + useFadingEdges: false, + fadingEdgeLength: 0, }; _onChangeFilterText = filterText => { @@ -124,11 +135,29 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'empty')} {renderSmallSwitchOption(this, 'debug')} {renderSmallSwitchOption(this, 'useFlatListItemComponent')} + {Platform.OS === 'android' && ( + + {renderSmallSwitchOption(this, 'useFadingEdges')} + + this.setState({ + fadingEdgeLength: Number(event.nativeEvent.text), + }) + } + /> + + )} } ListFooterComponent={FooterComponent} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index a8c9898e10d5d7..f6563a20aa0c59 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -276,4 +276,14 @@ public void setOverflow(ReactHorizontalScrollView view, @Nullable String overflo public void setPersistentScrollbar(ReactHorizontalScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } + + @ReactProp(name = "horizontalFadingEdgesEnabled") + public void setHorizontalFadingEdgesEnabled(ReactHorizontalScrollView view, boolean value) { + view.setHorizontalFadingEdgeEnabled(value); + } + + @ReactProp(name = "fadingEdgeLength") + public void setFadingEdgeLength(ReactHorizontalScrollView view, int value) { + view.setFadingEdgeLength(value); + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index cb8befaca24300..1a2350174e9f1d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -278,6 +278,16 @@ public void setPersistentScrollbar(ReactScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } + @ReactProp(name = "verticalFadingEdgesEnabled") + public void setVerticalFadingEdgesEnabled(ReactScrollView view, boolean value) { + view.setVerticalFadingEdgeEnabled(value); + } + + @ReactProp(name = "fadingEdgeLength") + public void setFadingEdgeLength(ReactScrollView view, int value) { + view.setFadingEdgeLength(value); + } + @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return createExportedCustomDirectEventTypeConstants(); From 3b3c95b0170e60983eb6e89b910d100d08eee141 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Fri, 23 Aug 2019 13:49:00 -0700 Subject: [PATCH 0051/1244] Fix useWindowDimensions firing continuously after dims change (#26008) Summary: https://github.com/facebook/react-native/pull/25990 fixed the `forceUpdate` method to actually update the component, but caused the useEffect to fire on every render, causing continuous updates after dimensions changed (e.g. from rotation). This reworks things a bit to be a bit simpler and more idiomatic so it's not quite as confusing, and fixes the bugs. ## Changelog [General] [Fixed] - Fix useWindowDimensions hook firing continuously after dimensions change Pull Request resolved: https://github.com/facebook/react-native/pull/26008 Test Plan: Aparently the Mobile Home app supports rotation on iOS now, so replaced it's content with the first `DimensionsExample` and confirmed with logging that `useEffect` fires exactly once, on initial mount, but the view still updates as expected when rotated: https://pxl.cl/Hfds Reviewed By: yungsters Differential Revision: D16765269 Pulled By: sahrens fbshipit-source-id: ef55d8a470dcfe87aa125d4c426bf01cfe0091a7 --- Libraries/Utilities/useWindowDimensions.js | 26 ++++++++++------------ 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Libraries/Utilities/useWindowDimensions.js b/Libraries/Utilities/useWindowDimensions.js index f719ea56b82717..3de619a5eab877 100644 --- a/Libraries/Utilities/useWindowDimensions.js +++ b/Libraries/Utilities/useWindowDimensions.js @@ -12,24 +12,22 @@ import Dimensions from './Dimensions'; import {type DisplayMetrics} from './NativeDeviceInfo'; -import * as React from 'react'; +import {useEffect, useState} from 'react'; export default function useWindowDimensions(): DisplayMetrics { - const dims = Dimensions.get('window'); // always read the latest value - const forceUpdate = React.useState(false)[1].bind(null, v => !v); - const initialDims = React.useState(dims)[0]; - React.useEffect(() => { - Dimensions.addEventListener('change', forceUpdate); - - const latestDims = Dimensions.get('window'); - if (latestDims !== initialDims) { - // We missed an update between calling `get` in render and - // `addEventListener` in this handler... - forceUpdate(); + const [dims, setDims] = useState(() => Dimensions.get('window')); + useEffect(() => { + function handleChange({window}) { + setDims(window); } + Dimensions.addEventListener('change', handleChange); + // We might have missed an update between calling `get` in render and + // `addEventListener` in this handler, so we set it here. If there was + // no change, React will filter out this update as a no-op. + setDims(Dimensions.get('window')); return () => { - Dimensions.removeEventListener('change', forceUpdate); + Dimensions.removeEventListener('change', handleChange); }; - }, [forceUpdate, initialDims]); + }, []); return dims; } From f8dff0bcb3147b7a1aa8ac7159952d848e198e29 Mon Sep 17 00:00:00 2001 From: Anda Bereczky Date: Fri, 23 Aug 2019 15:18:53 -0700 Subject: [PATCH 0052/1244] Default accessibility hint is read for buttons Summary: [Android] [Fixed] - Make sure the default accessibility hint is read for buttons on Android. Reviewed By: PeteTheHeat Differential Revision: D16974987 fbshipit-source-id: e7b932041f82d41271d9393e651967789c05f38a --- .../facebook/react/uimanager/ReactAccessibilityDelegate.java | 3 +++ .../main/res/views/uimanager/values/strings_unlocalized.xml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java index 640d6d0859f73a..405506c2e29094 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java @@ -290,6 +290,9 @@ public static void setRole( } else if (role.equals(AccessibilityRole.IMAGEBUTTON)) { nodeInfo.setRoleDescription(context.getString(R.string.imagebutton_description)); nodeInfo.setClickable(true); + } else if (role.equals(AccessibilityRole.BUTTON)) { + nodeInfo.setRoleDescription(context.getString(R.string.button_description)); + nodeInfo.setClickable(true); } else if (role.equals(AccessibilityRole.SUMMARY)) { nodeInfo.setRoleDescription(context.getString(R.string.summary_description)); } else if (role.equals(AccessibilityRole.HEADER)) { diff --git a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml index cd3cc03e0d6236..4c18708bf3ef81 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/strings_unlocalized.xml @@ -12,6 +12,10 @@ name="image_description" translatable="false" >Image + Button Date: Fri, 23 Aug 2019 17:09:33 -0700 Subject: [PATCH 0053/1244] Back out "[react-native][PR] [Android] Implement fading edges for ScrollView and it's dependent FlatList" Summary: After some thought, we decided we don't need the flexibility of separate horizontal and vertical props - it would be much nicer to just have a single prop for the edge length and then the native code can enable the booleans as appropriate. Original PR: https://github.com/facebook/react-native/pull/26163 Original commit changeset: f72a9a890d90 Reviewed By: TheSavior Differential Revision: D16997468 fbshipit-source-id: 7973262287a7ec2cee5957f8dc1806a0f28c1432 --- Libraries/Components/ScrollView/ScrollView.js | 21 ------------- Libraries/Lists/FlatList.js | 12 ------- .../js/examples/FlatList/FlatListExample.js | 31 +------------------ .../ReactHorizontalScrollViewManager.java | 10 ------ .../views/scroll/ReactScrollViewManager.java | 10 ------ 5 files changed, 1 insertion(+), 83 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 019a48b4f3c5df..b4298158b3354f 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -335,27 +335,6 @@ type AndroidProps = $ReadOnly<{| * @platform android */ persistentScrollbar?: ?boolean, - /** - * Fades out the left and right edges. - * The default value is false. - * - * @platform android - */ - horizontalFadingEdgesEnabled?: ?boolean, - /** - * Fades out the up and down edges. - * The default value is false. - * - * @platform android - */ - verticalFadingEdgesEnabled?: ?boolean, - /** - * The amount of fading. - * The default value is 0. - * - * @platform android - */ - fadingEdgeLength?: ?number, |}>; type VRProps = $ReadOnly<{| diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 26d87615880826..f9fb2a6aca1e00 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -233,18 +233,6 @@ type OptionalProps = { * will be called when its corresponding ViewabilityConfig's conditions are met. */ viewabilityConfigCallbackPairs?: Array, - /** - * See `ScrollView` for flow type and further documentation. - */ - horizontalFadingEdgesEnabled?: ?boolean, - /** - * See `ScrollView` for flow type and further documentation. - */ - verticalFadingEdgesEnabled?: ?boolean, - /** - * See `ScrollView` for flow type and further documentation. - */ - fadingEdgeLength?: ?number, }; export type Props = RequiredProps & OptionalProps & diff --git a/RNTester/js/examples/FlatList/FlatListExample.js b/RNTester/js/examples/FlatList/FlatListExample.js index 86a0741c002643..bb7cc9afe88c02 100644 --- a/RNTester/js/examples/FlatList/FlatListExample.js +++ b/RNTester/js/examples/FlatList/FlatListExample.js @@ -29,14 +29,7 @@ const { pressItem, renderSmallSwitchOption, } = require('../../components/ListExampleShared'); -const { - Alert, - Animated, - Platform, - StyleSheet, - TextInput, - View, -} = require('react-native'); +const {Alert, Animated, StyleSheet, View} = require('react-native'); import type {Item} from '../../components/ListExampleShared'; @@ -58,8 +51,6 @@ type State = {| virtualized: boolean, empty: boolean, useFlatListItemComponent: boolean, - useFadingEdges: boolean, - fadingEdgeLength: number, |}; class FlatListExample extends React.PureComponent { @@ -74,8 +65,6 @@ class FlatListExample extends React.PureComponent { virtualized: true, empty: false, useFlatListItemComponent: false, - useFadingEdges: false, - fadingEdgeLength: 0, }; _onChangeFilterText = filterText => { @@ -135,29 +124,11 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'empty')} {renderSmallSwitchOption(this, 'debug')} {renderSmallSwitchOption(this, 'useFlatListItemComponent')} - {Platform.OS === 'android' && ( - - {renderSmallSwitchOption(this, 'useFadingEdges')} - - this.setState({ - fadingEdgeLength: Number(event.nativeEvent.text), - }) - } - /> - - )} } ListFooterComponent={FooterComponent} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index f6563a20aa0c59..a8c9898e10d5d7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -276,14 +276,4 @@ public void setOverflow(ReactHorizontalScrollView view, @Nullable String overflo public void setPersistentScrollbar(ReactHorizontalScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } - - @ReactProp(name = "horizontalFadingEdgesEnabled") - public void setHorizontalFadingEdgesEnabled(ReactHorizontalScrollView view, boolean value) { - view.setHorizontalFadingEdgeEnabled(value); - } - - @ReactProp(name = "fadingEdgeLength") - public void setFadingEdgeLength(ReactHorizontalScrollView view, int value) { - view.setFadingEdgeLength(value); - } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index 1a2350174e9f1d..cb8befaca24300 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -278,16 +278,6 @@ public void setPersistentScrollbar(ReactScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } - @ReactProp(name = "verticalFadingEdgesEnabled") - public void setVerticalFadingEdgesEnabled(ReactScrollView view, boolean value) { - view.setVerticalFadingEdgeEnabled(value); - } - - @ReactProp(name = "fadingEdgeLength") - public void setFadingEdgeLength(ReactScrollView view, int value) { - view.setFadingEdgeLength(value); - } - @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return createExportedCustomDirectEventTypeConstants(); From e5b63410b47ef095b0b0253981bb80e648343174 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Mon, 26 Aug 2019 10:59:36 -0700 Subject: [PATCH 0054/1244] Show both TM/Fabric overlay over the root view Summary: This expands the existing FABRIC overlay to also indicate "TM" if turbomodule is active. Reviewed By: yungsters Differential Revision: D16999391 fbshipit-source-id: 42eedb697636c1172e595bc7c1ace2a9367a13b8 --- Libraries/ReactNative/AppRegistry.js | 8 +++---- ...js => ReactNativeArchitectureIndicator.js} | 24 +++++++++++++++---- Libraries/ReactNative/renderApplication.js | 8 +++---- 3 files changed, 27 insertions(+), 13 deletions(-) rename Libraries/ReactNative/{ReactFabricIndicator.js => ReactNativeArchitectureIndicator.js} (59%) diff --git a/Libraries/ReactNative/AppRegistry.js b/Libraries/ReactNative/AppRegistry.js index 683bfd565c188c..389e6455dbd0e7 100644 --- a/Libraries/ReactNative/AppRegistry.js +++ b/Libraries/ReactNative/AppRegistry.js @@ -62,7 +62,7 @@ let componentProviderInstrumentationHook: ComponentProviderInstrumentationHook = ) => component(); let wrapperComponentProvider: ?WrapperComponentProvider; -let showFabricIndicator = false; +let showArchitectureIndicator = false; /** * `AppRegistry` is the JavaScript entry point to running all React Native apps. @@ -74,8 +74,8 @@ const AppRegistry = { wrapperComponentProvider = provider; }, - enableFabricIndicator(enabled: boolean): void { - showFabricIndicator = enabled; + enableArchitectureIndicator(enabled: boolean): void { + showArchitectureIndicator = enabled; }, registerConfig(config: Array): void { @@ -121,7 +121,7 @@ const AppRegistry = { appParameters.rootTag, wrapperComponentProvider && wrapperComponentProvider(appParameters), appParameters.fabric, - showFabricIndicator, + showArchitectureIndicator, scopedPerformanceLogger, ); }, diff --git a/Libraries/ReactNative/ReactFabricIndicator.js b/Libraries/ReactNative/ReactNativeArchitectureIndicator.js similarity index 59% rename from Libraries/ReactNative/ReactFabricIndicator.js rename to Libraries/ReactNative/ReactNativeArchitectureIndicator.js index 951fd2925a83d6..9cc4bc6e2bd5e2 100644 --- a/Libraries/ReactNative/ReactFabricIndicator.js +++ b/Libraries/ReactNative/ReactNativeArchitectureIndicator.js @@ -15,14 +15,29 @@ const StyleSheet = require('../StyleSheet/StyleSheet'); const Text = require('../Text/Text'); const View = require('../Components/View/View'); -function ReactFabricIndicator(): React.Node { +const hasTurboModule = global.__turboModuleProxy != null; +const isBridgeless = global.RN$Bridgeless === true; + +function ReactNativeArchitectureIndicator(props: {| + fabric: boolean, +|}): React.Node { + const parts = []; + if (isBridgeless) { + parts.push('NOBRIDGE'); + } else { + if (props.fabric) { + parts.push('FABRIC'); + } + if (hasTurboModule) { + parts.push('TM'); + } + } return ( - FABRIC + {parts.join('+')} ); } - const styles = StyleSheet.create({ container: { alignItems: 'center', @@ -38,5 +53,4 @@ const styles = StyleSheet.create({ color: '#ffffff', }, }); - -module.exports = ReactFabricIndicator; +module.exports = ReactNativeArchitectureIndicator; diff --git a/Libraries/ReactNative/renderApplication.js b/Libraries/ReactNative/renderApplication.js index 72a2e27e66d1d7..c713ac5cc7e985 100644 --- a/Libraries/ReactNative/renderApplication.js +++ b/Libraries/ReactNative/renderApplication.js @@ -15,7 +15,7 @@ import GlobalPerformanceLogger from '../Utilities/GlobalPerformanceLogger'; import type {IPerformanceLogger} from '../Utilities/createPerformanceLogger'; import PerformanceLoggerContext from '../Utilities/PerformanceLoggerContext'; const React = require('react'); -const ReactFabricIndicator = require('./ReactFabricIndicator'); +const ReactNativeArchitectureIndicator = require('./ReactNativeArchitectureIndicator'); const invariant = require('invariant'); @@ -28,7 +28,7 @@ function renderApplication( rootTag: any, WrapperComponent?: ?React.ComponentType<*>, fabric?: boolean, - showFabricIndicator?: boolean, + showArchitectureIndicator?: boolean, scopedPerformanceLogger?: IPerformanceLogger, ) { invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag); @@ -38,8 +38,8 @@ function renderApplication( value={scopedPerformanceLogger ?? GlobalPerformanceLogger}> - {fabric === true && showFabricIndicator === true ? ( - + {showArchitectureIndicator === true ? ( + ) : null} From be2a2529af21414e645f2b04c5a1c819828ecda6 Mon Sep 17 00:00:00 2001 From: Frieder Bluemle Date: Mon, 26 Aug 2019 12:11:10 -0700 Subject: [PATCH 0055/1244] Update Gradle wrapper to 5.6 (#26079) Summary: ``` Welcome to Gradle 5.6! Here are the highlights of this release: - Incremental Groovy compilation - Groovy compile avoidance - Test fixtures for Java projects - Manage plugin versions via settings script For more details see https://docs.gradle.org/5.6/release-notes.html ``` ## Changelog [Android] [Changed] - Gradle wrapper 5.6 Pull Request resolved: https://github.com/facebook/react-native/pull/26079 Test Plan: Ran build and tests locally. Differential Revision: D17054310 Pulled By: mdvacca fbshipit-source-id: de7ba3a6d04058e51b8bc6a21d5a3f828ef8bc25 --- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 2 +- template/android/gradle.properties | 4 ++++ template/android/gradle/wrapper/gradle-wrapper.properties | 2 +- template/android/gradlew | 2 +- template/android/gradlew.bat | 2 +- 7 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0c4de36dddba5..8d58bda4472b70 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index b0d6d0ab5deb58..8e25e6c19d5748 100755 --- a/gradlew +++ b/gradlew @@ -7,7 +7,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff --git a/gradlew.bat b/gradlew.bat index 15e1ee37a70d7d..24467a141f7916 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -5,7 +5,7 @@ @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem -@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, diff --git a/template/android/gradle.properties b/template/android/gradle.properties index 027ef9db8a3001..95b56fe1e30bfd 100644 --- a/template/android/gradle.properties +++ b/template/android/gradle.properties @@ -17,5 +17,9 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX android.enableJetifier=true diff --git a/template/android/gradle/wrapper/gradle-wrapper.properties b/template/android/gradle/wrapper/gradle-wrapper.properties index e0c4de36dddba5..8d58bda4472b70 100644 --- a/template/android/gradle/wrapper/gradle-wrapper.properties +++ b/template/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/template/android/gradlew b/template/android/gradlew index b0d6d0ab5deb58..8e25e6c19d5748 100755 --- a/template/android/gradlew +++ b/template/android/gradlew @@ -7,7 +7,7 @@ # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, diff --git a/template/android/gradlew.bat b/template/android/gradlew.bat index 15e1ee37a70d7d..24467a141f7916 100644 --- a/template/android/gradlew.bat +++ b/template/android/gradlew.bat @@ -5,7 +5,7 @@ @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem -@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, From 59c3d05058ab38006d50d90409c67a1f5fcbf5e2 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Mon, 26 Aug 2019 20:59:58 -0700 Subject: [PATCH 0056/1244] Fabric: Support for on iOS Summary: This diff adds support from `ScrollView::scrollEventThrottle` property on iOS. Reviewed By: JoshuaGross Differential Revision: D17000397 fbshipit-source-id: 93f23919a6a2588000c0eeca869171d1036348b6 --- .../ScrollView/RCTScrollViewComponentView.mm | 67 ++++++++++++++----- .../components/scrollview/ScrollViewProps.h | 2 +- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm index 4006d01a4b86dd..05659b8bb8ab2b 100644 --- a/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/ScrollView/RCTScrollViewComponentView.mm @@ -22,13 +22,13 @@ @interface RCTScrollViewComponentView () -@property (nonatomic, assign) CGFloat scrollEventThrottle; - @end @implementation RCTScrollViewComponentView { ScrollViewShadowNode::ConcreteState::Shared _state; CGSize _contentSize; + NSTimeInterval _lastScrollEventDispatchTime; + NSTimeInterval _scrollEventThrottle; } + (RCTScrollViewComponentView *_Nullable)findScrollViewComponentViewForView:(UIView *)view @@ -59,6 +59,8 @@ - (instancetype)initWithFrame:(CGRect)frame }]; [_scrollViewDelegateSplitter addDelegate:self]; + + _scrollEventThrottle = INFINITY; } return self; @@ -107,7 +109,17 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & MAP_SCROLL_VIEW_PROP(scrollsToTop); MAP_SCROLL_VIEW_PROP(showsHorizontalScrollIndicator); MAP_SCROLL_VIEW_PROP(showsVerticalScrollIndicator); - MAP_VIEW_PROP(scrollEventThrottle); + + if (oldScrollViewProps.scrollEventThrottle != newScrollViewProps.scrollEventThrottle) { + // Zero means "send value only once per significant logical event". + // Prop value is in milliseconds. + // iOS implementation uses `NSTimeInterval` (in seconds). + // 16 ms is the minimum allowed value. + _scrollEventThrottle = newScrollViewProps.scrollEventThrottle <= 0 + ? INFINITY + : std::max(newScrollViewProps.scrollEventThrottle / 1000.0, 1.0 / 60.0); + } + MAP_SCROLL_VIEW_PROP(zoomScale); if (oldScrollViewProps.contentInset != newScrollViewProps.contentInset) { @@ -184,87 +196,108 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView return; } - std::static_pointer_cast(_eventEmitter)->onScroll([self _scrollViewMetrics]); + NSTimeInterval now = CACurrentMediaTime(); + if ((_lastScrollEventDispatchTime == 0) || (now - _lastScrollEventDispatchTime > _scrollEventThrottle)) { + _lastScrollEventDispatchTime = now; + std::static_pointer_cast(_eventEmitter)->onScroll([self _scrollViewMetrics]); + } } - (void)scrollViewDidZoom:(UIScrollView *)scrollView { - if (!_eventEmitter) { - return; - } - - std::static_pointer_cast(_eventEmitter)->onScroll([self _scrollViewMetrics]); + [self scrollViewDidScroll:scrollView]; } - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onScrollBeginDrag([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onScrollBeginDrag([self _scrollViewMetrics]); } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onScrollEndDrag([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onScrollEndDrag([self _scrollViewMetrics]); } - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter) + std::static_pointer_cast(_eventEmitter) ->onMomentumScrollBegin([self _scrollViewMetrics]); } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onMomentumScrollEnd([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onMomentumScrollEnd([self _scrollViewMetrics]); [self _updateStateWithContentOffset]; } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onMomentumScrollEnd([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onMomentumScrollEnd([self _scrollViewMetrics]); [self _updateStateWithContentOffset]; } - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onScrollBeginDrag([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onScrollBeginDrag([self _scrollViewMetrics]); } - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale { + [self _forceDispatchNextScrollEvent]; + if (!_eventEmitter) { return; } - std::static_pointer_cast(_eventEmitter)->onScrollEndDrag([self _scrollViewMetrics]); + std::static_pointer_cast(_eventEmitter)->onScrollEndDrag([self _scrollViewMetrics]); [self _updateStateWithContentOffset]; } +#pragma mark - UIScrollViewDelegate + +- (void)_forceDispatchNextScrollEvent +{ + _lastScrollEventDispatchTime = 0; +} + @end @implementation RCTScrollViewComponentView (ScrollableProtocol) @@ -276,11 +309,13 @@ - (CGSize)contentSize - (void)scrollToOffset:(CGPoint)offset { + [self _forceDispatchNextScrollEvent]; [self scrollToOffset:offset animated:YES]; } - (void)scrollToOffset:(CGPoint)offset animated:(BOOL)animated { + [self _forceDispatchNextScrollEvent]; [self.scrollView setContentOffset:offset animated:animated]; } diff --git a/ReactCommon/fabric/components/scrollview/ScrollViewProps.h b/ReactCommon/fabric/components/scrollview/ScrollViewProps.h index 4dc57b79db0bee..1f787f91977b18 100644 --- a/ReactCommon/fabric/components/scrollview/ScrollViewProps.h +++ b/ReactCommon/fabric/components/scrollview/ScrollViewProps.h @@ -40,7 +40,7 @@ class ScrollViewProps final : public ViewProps { const bool scrollsToTop{true}; const bool showsHorizontalScrollIndicator{true}; const bool showsVerticalScrollIndicator{true}; - const Float scrollEventThrottle{}; + const int scrollEventThrottle{}; const Float zoomScale{1.0}; const EdgeInsets contentInset{}; const EdgeInsets scrollIndicatorInsets{}; From 5acb36483cefa1ec2fa11d08b6e6f7c86fa986a8 Mon Sep 17 00:00:00 2001 From: Andres Suarez Date: Mon, 26 Aug 2019 21:39:36 -0700 Subject: [PATCH 0057/1244] Apply BUCKFORMAT to all BUCK files Reviewed By: scottrice Differential Revision: D17051732 fbshipit-source-id: 2e9d81cd8d547456eb2d8d97f08b8d2e951787a5 --- .../main/third-party/android/androidx/BUCK | 119 +++++++++--------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/ReactAndroid/src/main/third-party/android/androidx/BUCK b/ReactAndroid/src/main/third-party/android/androidx/BUCK index e484cf386f07dd..1f1d33cbc103e2 100644 --- a/ReactAndroid/src/main/third-party/android/androidx/BUCK +++ b/ReactAndroid/src/main/third-party/android/androidx/BUCK @@ -10,8 +10,8 @@ fb_native.android_library( name = "appcompat", visibility = ["PUBLIC"], exported_deps = [ - ":appcompat-binary", ":annotation", + ":appcompat-binary", ":collection", ":core", ":cursoradapter", @@ -19,136 +19,135 @@ fb_native.android_library( ":legacy-support-core-utils", ":vectordrawable", ":vectordrawable-animated", - ] + ], ) fb_native.android_library( name = "asynclayoutinflater", visibility = ["PUBLIC"], exported_deps = [ - ":asynclayoutinflater-binary", ":annotation", + ":asynclayoutinflater-binary", ":core", - ] + ], ) fb_native.android_library( name = "collection", visibility = ["PUBLIC"], exported_deps = [ - ":collection-binary", ":annotation", - ] + ":collection-binary", + ], ) fb_native.android_library( name = "coordinatorlayout", visibility = ["PUBLIC"], exported_deps = [ - ":coordinatorlayout-binary", ":annotation", + ":coordinatorlayout-binary", ":core", ":customview", - ] + ], ) fb_native.android_library( name = "core", visibility = ["PUBLIC"], exported_deps = [ - ":core-binary", ":annotation", ":collection", + ":core-binary", ":lifecycle-runtime", ":versionedparcelable", - ] + ], ) fb_native.android_library( name = "core-common", visibility = ["PUBLIC"], exported_deps = [ - ":core-common-binary", ":annotation", - ] + ":core-common-binary", + ], ) fb_native.android_library( name = "core-runtime", visibility = ["PUBLIC"], exported_deps = [ - ":core-runtime-binary", ":core-common", - ] + ":core-runtime-binary", + ], ) fb_native.android_library( name = "cursoradapter", visibility = ["PUBLIC"], exported_deps = [ - ":cursoradapter-binary", ":annotation", - ] + ":cursoradapter-binary", + ], ) fb_native.android_library( name = "customview", visibility = ["PUBLIC"], exported_deps = [ - ":customview-binary", ":annotation", ":core", - ] + ":customview-binary", + ], ) fb_native.android_library( name = "documentfile", visibility = ["PUBLIC"], exported_deps = [ - ":documentfile-binary", ":annotation", - ] + ":documentfile-binary", + ], ) fb_native.android_library( name = "drawerlayout", visibility = ["PUBLIC"], exported_deps = [ - ":drawerlayout-binary", ":annotation", ":core", ":customview", - ] + ":drawerlayout-binary", + ], ) fb_native.android_library( name = "fragment", visibility = ["PUBLIC"], exported_deps = [ - ":fragment-binary", ":annotation", ":core", + ":fragment-binary", ":legacy-support-core-ui", ":legacy-support-core-utils", ":lifecycle-viewmodel", ":loader", - ] + ], ) fb_native.android_library( name = "interpolator", visibility = ["PUBLIC"], exported_deps = [ - ":interpolator-binary", ":annotation", - ] + ":interpolator-binary", + ], ) fb_native.android_library( name = "legacy-support-core-ui", visibility = ["PUBLIC"], exported_deps = [ - ":legacy-support-core-ui-binary", ":annotation", ":asynclayoutinflater", ":coordinatorlayout", @@ -157,170 +156,170 @@ fb_native.android_library( ":customview", ":drawerlayout", ":interpolator", + ":legacy-support-core-ui-binary", ":legacy-support-core-utils", ":slidingpanelayout", ":swiperefreshlayout", ":viewpager", - ] + ], ) - fb_native.android_library( name = "legacy-support-core-utils", visibility = ["PUBLIC"], exported_deps = [ - ":legacy-support-core-utils-binary", ":annotation", ":core", ":documentfile", + ":legacy-support-core-utils-binary", ":loader", ":localbroadcastmanager", ":print", - ] + ], ) fb_native.android_library( name = "lifecycle-common", visibility = ["PUBLIC"], exported_deps = [ - ":lifecycle-common-binary", ":annotation", - ] + ":lifecycle-common-binary", + ], ) fb_native.android_library( name = "lifecycle-livedata", visibility = ["PUBLIC"], exported_deps = [ - ":lifecycle-livedata-binary", ":core-common", ":core-runtime", + ":lifecycle-livedata-binary", ":lifecycle-livedata-core", - ] + ], ) fb_native.android_library( name = "lifecycle-livedata-core", visibility = ["PUBLIC"], exported_deps = [ - ":lifecycle-livedata-core-binary", ":core-common", ":core-runtime", ":lifecycle-common", - ] + ":lifecycle-livedata-core-binary", + ], ) fb_native.android_library( name = "lifecycle-runtime", visibility = ["PUBLIC"], exported_deps = [ - ":lifecycle-runtime-binary", ":annotation", ":core-common", ":lifecycle-common", - ] + ":lifecycle-runtime-binary", + ], ) fb_native.android_library( name = "lifecycle-viewmodel", visibility = ["PUBLIC"], exported_deps = [ - ":lifecycle-viewmodel-binary", ":annotation", - ] + ":lifecycle-viewmodel-binary", + ], ) fb_native.android_library( name = "localbroadcastmanager", visibility = ["PUBLIC"], exported_deps = [ - ":localbroadcastmanager-binary", ":annotation", - ] + ":localbroadcastmanager-binary", + ], ) fb_native.android_library( name = "loader", visibility = ["PUBLIC"], exported_deps = [ - ":loader-binary", ":annotation", ":core", ":lifecycle-livedata", ":lifecycle-viewmodel", - ] + ":loader-binary", + ], ) fb_native.android_library( name = "print", visibility = ["PUBLIC"], exported_deps = [ - ":print-binary", ":annotation", - ] + ":print-binary", + ], ) fb_native.android_library( name = "slidingpanelayout", visibility = ["PUBLIC"], exported_deps = [ - ":slidingpanelayout-binary", ":annotation", ":core", ":customview", - ] + ":slidingpanelayout-binary", + ], ) fb_native.android_library( name = "swiperefreshlayout", visibility = ["PUBLIC"], exported_deps = [ - ":swiperefreshlayout-binary", ":annotation", ":core", ":interpolator", - ] + ":swiperefreshlayout-binary", + ], ) fb_native.android_library( name = "vectordrawable", visibility = ["PUBLIC"], exported_deps = [ - ":vectordrawable-binary", ":annotation", ":core", - ] + ":vectordrawable-binary", + ], ) fb_native.android_library( name = "vectordrawable-animated", visibility = ["PUBLIC"], exported_deps = [ - ":vectordrawable-animated-binary", ":legacy-support-core-ui", ":vectordrawable", - ] + ":vectordrawable-animated-binary", + ], ) fb_native.android_library( name = "versionedparcelable", visibility = ["PUBLIC"], exported_deps = [ - ":versionedparcelable-binary", ":annotation", ":collection", - ] + ":versionedparcelable-binary", + ], ) fb_native.android_library( name = "viewpager", visibility = ["PUBLIC"], exported_deps = [ - ":viewpager-binary", ":annotation", ":core", ":customview", - ] + ":viewpager-binary", + ], ) # Internal targets @@ -464,7 +463,6 @@ fb_native.android_prebuilt_aar( aar = ":versionedparcelable-binary-aar", ) - fb_native.android_prebuilt_aar( name = "viewpager-binary", aar = ":viewpager-binary-aar", @@ -489,7 +487,6 @@ fb_native.remote_file( url = "mvn:androidx.asynclayoutinflater:asynclayoutinflater:aar:1.0.0", ) - fb_native.remote_file( name = "collection-binary.jar", sha1 = "42858b26cafdaa69b6149f45dfc2894007bc2c7a", From 92a3c9da0a38870a8bad7c91bdc3ddb494f6e5f2 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 26 Aug 2019 23:55:01 -0700 Subject: [PATCH 0058/1244] React DevTools v4 integration Summary: This Diff is being posted for discussion purposes. It will not be ready to land until React DevTools v4 has been published to NPM. Update React Native to be compatible with the [new version 4 React DevTools extension](https://github.com/bvaughn/react-devtools-experimental). **Note that this is a breaking change**, as the version 3 and version 4 backends are **not compatible**. Once this update ships (in React Native) users will be required to update their version of the [`react-devtools` NPM package](https://www.npmjs.com/package/react-devtools). The same will be true for IDEs like Nuclide as well as other developer tools like Flipper and [React Native Debugger](https://github.com/jhen0409/react-native-debugger). Related changes also included in this diff are: * Pass an explicit whitelist of style props for the React Native style editor (to improve developer experience when adding new styles). * Update `YellowBox` console patching to coordinate with DevTools own console patching. * Also improved formatting slightly by not calling `stringifySafe` for strings (since this adds visible quotation marks). Regarding the console patching- component stacks will be appended by default when there's no DevTools frontend open. The frontend will provide an option to turn this behavior off though: {F168852162} React DevTools will detect if the new version is used with an older version of React Native, and offer inline upgrade instructions: {F169306863} **Note that the change to the `RCTEnableTurboModule` will not be included in this Diff**. I've just turned those off temporarily so I can use v8+Chrome for debugging. Reviewed By: rickhanlonii Differential Revision: D15973709 fbshipit-source-id: bb9d83fc829af4693e7a10a622acc95a411a48e4 --- Libraries/Core/setUpDeveloperTools.js | 5 + Libraries/Inspector/Inspector.js | 106 ++++++++++-------- Libraries/YellowBox/Data/YellowBoxCategory.js | 17 ++- Libraries/YellowBox/Data/YellowBoxWarning.js | 22 +++- .../Data/__tests__/YellowBoxCategory-test.js | 50 ++++----- .../YellowBoxCategory-test.js.snap | 12 +- Libraries/YellowBox/YellowBox.js | 29 ++++- Libraries/polyfills/console.js | 14 ++- .../RNTesterIntegrationTests.m | 2 +- package.json | 2 +- yarn.lock | 78 +++++++++---- 11 files changed, 227 insertions(+), 110 deletions(-) diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js index 7a9ff4248924b7..21595f94b0371e 100644 --- a/Libraries/Core/setUpDeveloperTools.js +++ b/Libraries/Core/setUpDeveloperTools.js @@ -39,6 +39,8 @@ if (__DEV__) { ? devServer.url.replace(/https?:\/\//, '').split(':')[0] : 'localhost'; + const viewConfig = require('../Components/View/ReactNativeViewViewConfig.js'); + reactDevTools.connectToDevTools({ isAppActive, host, @@ -46,6 +48,9 @@ if (__DEV__) { // It was added in https://github.com/facebook/react-native/commit/bf2b435322e89d0aeee8792b1c6e04656c2719a0. port: window.__REACT_DEVTOOLS_PORT__, resolveRNStyle: require('../StyleSheet/flattenStyle'), + nativeStyleEditorValidAttributes: Object.keys( + viewConfig.validAttributes.style, + ), }); } diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js index 22dd2655b61722..ad5316642bf6f2 100644 --- a/Libraries/Inspector/Inspector.js +++ b/Libraries/Inspector/Inspector.js @@ -30,13 +30,16 @@ export type ReactRenderer = { const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__; const renderers = findRenderers(); -// required for devtools to be able to edit react native styles +// Required for React DevTools to view/edit React Native styles in Flipper. +// Flipper doesn't inject these values when initializing DevTools. hook.resolveRNStyle = require('../StyleSheet/flattenStyle'); +const viewConfig = require('../Components/View/ReactNativeViewViewConfig.js'); +hook.nativeStyleEditorValidAttributes = Object.keys( + viewConfig.validAttributes.style, +); function findRenderers(): $ReadOnlyArray { - const allRenderers = Object.keys(hook._renderers).map( - key => hook._renderers[key], - ); + const allRenderers = Array.from(hook.renderers.values()); invariant( allRenderers.length >= 1, 'Expected to find at least one React Native renderer on DevTools hook.', @@ -78,6 +81,7 @@ class Inspector extends React.Component< networking: boolean, }, > { + _hideTimeoutID: TimeoutID | null = null; _subs: ?Array<() => void>; constructor(props: Object) { @@ -97,10 +101,10 @@ class Inspector extends React.Component< } componentDidMount() { - hook.on('react-devtools', this.attachToDevtools); + hook.on('react-devtools', this._attachToDevtools); // if devtools is already started if (hook.reactDevtoolsAgent) { - this.attachToDevtools(hook.reactDevtoolsAgent); + this._attachToDevtools(hook.reactDevtoolsAgent); } } @@ -108,53 +112,67 @@ class Inspector extends React.Component< if (this._subs) { this._subs.map(fn => fn()); } - hook.off('react-devtools', this.attachToDevtools); + hook.off('react-devtools', this._attachToDevtools); } UNSAFE_componentWillReceiveProps(newProps: Object) { this.setState({inspectedViewTag: newProps.inspectedViewTag}); } - attachToDevtools: (agent: any) => void = (agent: Object) => { - let _hideWait = null; - const hlSub = agent.sub('highlight', ({node, name, props}) => { - clearTimeout(_hideWait); + _attachToDevtools = (agent: Object) => { + agent.addListener('hideNativeHighlight', this._onAgentHideNativeHighlight); + agent.addListener('showNativeHighlight', this._onAgentShowNativeHighlight); + agent.addListener('shutdown', this._onAgentShutdown); - if (typeof node !== 'number') { - // Fiber - node = ReactNative.findNodeHandle(node); - } + this.setState({ + devtoolsAgent: agent, + }); + }; - UIManager.measure(node, (x, y, width, height, left, top) => { - this.setState({ - hierarchy: [], - inspected: { - frame: {left, top, width, height}, - style: props ? props.style : {}, - }, - }); + _onAgentHideNativeHighlight = () => { + if (this.state.inspected === null) { + return; + } + // we wait to actually hide in order to avoid flicker + this._hideTimeoutID = setTimeout(() => { + this.setState({ + inspected: null, + }); + }, 100); + }; + + _onAgentShowNativeHighlight = node => { + clearTimeout(this._hideTimeoutID); + + if (typeof node !== 'number') { + node = ReactNative.findNodeHandle(node); + } + + UIManager.measure(node, (x, y, width, height, left, top) => { + this.setState({ + hierarchy: [], + inspected: { + frame: {left, top, width, height}, + }, }); }); - const hideSub = agent.sub('hideHighlight', () => { - if (this.state.inspected === null) { - return; - } - // we wait to actually hide in order to avoid flicker - _hideWait = setTimeout(() => { - this.setState({ - inspected: null, - }); - }, 100); - }); - this._subs = [hlSub, hideSub]; + }; + + _onAgentShutdown = () => { + const agent = this.state.devtoolsAgent; + if (agent != null) { + agent.removeListener( + 'hideNativeHighlight', + this._onAgentHideNativeHighlight, + ); + agent.removeListener( + 'showNativeHighlight', + this._onAgentShowNativeHighlight, + ); + agent.removeListener('shutdown', this._onAgentShutdown); - agent.on('shutdown', () => { this.setState({devtoolsAgent: null}); - this._subs = null; - }); - this.setState({ - devtoolsAgent: agent, - }); + } }; setSelection(i: number) { @@ -187,11 +205,7 @@ class Inspector extends React.Component< if (this.state.devtoolsAgent) { // Skip host leafs const offsetFromLeaf = hierarchy.length - 1 - selection; - this.state.devtoolsAgent.selectFromDOMNode( - touchedViewTag, - true, - offsetFromLeaf, - ); + this.state.devtoolsAgent.selectNode(touchedViewTag); } this.setState({ diff --git a/Libraries/YellowBox/Data/YellowBoxCategory.js b/Libraries/YellowBox/Data/YellowBoxCategory.js index 39daa110a20c0a..e4ad9234123b41 100644 --- a/Libraries/YellowBox/Data/YellowBoxCategory.js +++ b/Libraries/YellowBox/Data/YellowBoxCategory.js @@ -60,9 +60,13 @@ const YellowBoxCategory = { if (substitutionIndex < substitutionCount) { if (substitutionIndex < substitutions.length) { - const substitution = stringifySafe( - substitutions[substitutionIndex], - ); + // Don't stringify a string type. + // It adds quotation mark wrappers around the string, + // which causes the yellow box to look odd. + const substitution = + typeof substitutions[substitutionIndex] === 'string' + ? substitutions[substitutionIndex] + : stringifySafe(substitutions[substitutionIndex]); substitutionOffsets.push({ length: substitution.length, offset: contentString.length, @@ -88,7 +92,12 @@ const YellowBoxCategory = { contentParts.push(contentString); } - const remainingArgs = remaining.map(stringifySafe); + const remainingArgs = remaining.map(arg => { + // Don't stringify a string type. + // It adds quotation mark wrappers around the string, + // which causes the yellow box to look odd. + return typeof arg === 'string' ? arg : stringifySafe(arg); + }); categoryParts.push(...remainingArgs); contentParts.push(...remainingArgs); diff --git a/Libraries/YellowBox/Data/YellowBoxWarning.js b/Libraries/YellowBox/Data/YellowBoxWarning.js index 0b43b852368d50..15876e8bb48201 100644 --- a/Libraries/YellowBox/Data/YellowBoxWarning.js +++ b/Libraries/YellowBox/Data/YellowBoxWarning.js @@ -34,8 +34,28 @@ class YellowBoxWarning { message: Message, stack: Stack, |} { + let mutableArgs: Array = [...args]; + + // This detects a very narrow case of a simple warning string, + // with a component stack appended by React DevTools. + // In this case, we convert the component stack to a substituion, + // because YellowBox formats those pleasantly. + // If there are other subtituations or formatting, + // we bail to avoid potentially corrupting the data. + if (mutableArgs.length === 2) { + const first = mutableArgs[0]; + const last = mutableArgs[1]; + if ( + typeof first === 'string' && + typeof last === 'string' && + /^\n {4}in/.exec(last) + ) { + mutableArgs[0] = first + '%s'; + } + } + return { - ...YellowBoxCategory.parse(args), + ...YellowBoxCategory.parse(mutableArgs), stack: createStack({framesToPop: framesToPop + 1}), }; } diff --git a/Libraries/YellowBox/Data/__tests__/YellowBoxCategory-test.js b/Libraries/YellowBox/Data/__tests__/YellowBoxCategory-test.js index 502416373dcb24..5a325dc92e7c79 100644 --- a/Libraries/YellowBox/Data/__tests__/YellowBoxCategory-test.js +++ b/Libraries/YellowBox/Data/__tests__/YellowBoxCategory-test.js @@ -26,9 +26,9 @@ describe('YellowBoxCategory', () => { it('parses strings with arguments', () => { expect(YellowBoxCategory.parse(['A', 'B', 'C'])).toEqual({ - category: 'A "B" "C"', + category: 'A B C', message: { - content: 'A "B" "C"', + content: 'A B C', substitutions: [], }, }); @@ -38,10 +38,10 @@ describe('YellowBoxCategory', () => { expect(YellowBoxCategory.parse(['%s', 'A'])).toEqual({ category: '\ufeff%s', message: { - content: '"A"', + content: 'A', substitutions: [ { - length: 3, + length: 1, offset: 0, }, ], @@ -53,15 +53,15 @@ describe('YellowBoxCategory', () => { expect(YellowBoxCategory.parse(['%s %s', 'A'])).toEqual({ category: '\ufeff%s %s', message: { - content: '"A" %s', + content: 'A %s', substitutions: [ { - length: 3, + length: 1, offset: 0, }, { length: 2, - offset: 4, + offset: 2, }, ], }, @@ -70,12 +70,12 @@ describe('YellowBoxCategory', () => { it('parses formatted strings with excess arguments', () => { expect(YellowBoxCategory.parse(['%s', 'A', 'B'])).toEqual({ - category: '\ufeff%s "B"', + category: '\ufeff%s B', message: { - content: '"A" "B"', + content: 'A B', substitutions: [ { - length: 3, + length: 1, offset: 0, }, ], @@ -85,12 +85,12 @@ describe('YellowBoxCategory', () => { it('treats "%s" in arguments as literals', () => { expect(YellowBoxCategory.parse(['%s', '%s', 'A'])).toEqual({ - category: '\ufeff%s "A"', + category: '\ufeff%s A', message: { - content: '"%s" "A"', + content: '%s A', substitutions: [ { - length: 4, + length: 2, offset: 0, }, ], @@ -111,10 +111,10 @@ describe('YellowBoxCategory', () => { expect( YellowBoxCategory.render( { - content: '"A"', + content: 'A', substitutions: [ { - length: 3, + length: 1, offset: 0, }, ], @@ -128,19 +128,19 @@ describe('YellowBoxCategory', () => { expect( YellowBoxCategory.render( { - content: '"A" "B" "C"', + content: 'A B C', substitutions: [ { - length: 3, + length: 1, offset: 0, }, { - length: 3, - offset: 4, + length: 1, + offset: 2, }, { - length: 3, - offset: 8, + length: 1, + offset: 4, }, ], }, @@ -153,10 +153,10 @@ describe('YellowBoxCategory', () => { expect( YellowBoxCategory.render( { - content: '!"A"', + content: '!A', substitutions: [ { - length: 3, + length: 1, offset: 1, }, ], @@ -170,10 +170,10 @@ describe('YellowBoxCategory', () => { expect( YellowBoxCategory.render( { - content: '"A"!', + content: 'A!', substitutions: [ { - length: 3, + length: 1, offset: 0, }, ], diff --git a/Libraries/YellowBox/Data/__tests__/__snapshots__/YellowBoxCategory-test.js.snap b/Libraries/YellowBox/Data/__tests__/__snapshots__/YellowBoxCategory-test.js.snap index 1a527066b06c52..b72d36d98181c5 100644 --- a/Libraries/YellowBox/Data/__tests__/__snapshots__/YellowBoxCategory-test.js.snap +++ b/Libraries/YellowBox/Data/__tests__/__snapshots__/YellowBoxCategory-test.js.snap @@ -9,7 +9,7 @@ Array [ } } > - "A" + A , ] `; @@ -31,7 +31,7 @@ Array [ } } > - "A" + A , @@ -43,7 +43,7 @@ Array [ } } > - "B" + B , @@ -55,7 +55,7 @@ Array [ } } > - "C" + C , ] `; @@ -72,7 +72,7 @@ Array [ } } > - "A" + A , ] `; @@ -86,7 +86,7 @@ Array [ } } > - "A" + A , ! diff --git a/Libraries/YellowBox/YellowBox.js b/Libraries/YellowBox/YellowBox.js index d94e23b50c359b..1d06b1af1a0000 100644 --- a/Libraries/YellowBox/YellowBox.js +++ b/Libraries/YellowBox/YellowBox.js @@ -50,7 +50,17 @@ if (__DEV__) { const YellowBoxList = require('./UI/YellowBoxList'); const YellowBoxRegistry = require('./Data/YellowBoxRegistry'); + // YellowBox needs to insert itself early, + // in order to access the component stacks appended by React DevTools. const {error, warn} = console; + let errorImpl = error; + let warnImpl = warn; + (console: any).error = function(...args) { + errorImpl(...args); + }; + (console: any).warn = function(...args) { + warnImpl(...args); + }; // eslint-disable-next-line no-shadow YellowBox = class YellowBox extends React.Component { @@ -59,7 +69,7 @@ if (__DEV__) { } static install(): void { - (console: any).error = function(...args) { + errorImpl = function(...args) { error.call(console, ...args); // Show YellowBox for the `warning` module. if (typeof args[0] === 'string' && args[0].startsWith('Warning: ')) { @@ -67,7 +77,7 @@ if (__DEV__) { } }; - (console: any).warn = function(...args) { + warnImpl = function(...args) { warn.call(console, ...args); registerWarning(...args); }; @@ -91,8 +101,8 @@ if (__DEV__) { } static uninstall(): void { - (console: any).error = error; - (console: any).warn = error; + errorImpl = error; + warnImpl = warn; delete (console: any).disableYellowBox; } @@ -135,7 +145,16 @@ if (__DEV__) { }; const registerWarning = (...args): void => { - YellowBoxRegistry.add({args, framesToPop: 2}); + // YellowBox should ignore the top 3-4 stack frames: + // 1: registerWarning() itself + // 2: YellowBox's own console override (in this file) + // 3: React DevTools console.error override (to add component stack) + // (The override feature may be disabled by a runtime preference.) + // 4: The actual console method itself. + // $FlowFixMe This prop is how the DevTools override is observable. + const isDevToolsOvveride = !!console.warn + .__REACT_DEVTOOLS_ORIGINAL_METHOD__; + YellowBoxRegistry.add({args, framesToPop: isDevToolsOvveride ? 4 : 3}); }; } else { YellowBox = class extends React.Component { diff --git a/Libraries/polyfills/console.js b/Libraries/polyfills/console.js index 1dab70cc264361..f45ad0f2e35a3d 100644 --- a/Libraries/polyfills/console.js +++ b/Libraries/polyfills/console.js @@ -410,8 +410,20 @@ function getNativeLogFunction(level) { .join(', '); } + // TRICKY + // If more than one argument is provided, the code above collapses them all + // into a single formatted string. This transform wraps string arguments in + // single quotes (e.g. "foo" -> "'foo'") which then breaks the "Warning:" + // check below. So it's important that we look at the first argument, rather + // than the formatted argument string. + const firstArg = arguments[0]; + let logLevel = level; - if (str.slice(0, 9) === 'Warning: ' && logLevel >= LOG_LEVELS.error) { + if ( + typeof firstArg === 'string' && + firstArg.slice(0, 9) === 'Warning: ' && + logLevel >= LOG_LEVELS.error + ) { // React warnings use console.error so that a stack trace is shown, // but we don't (currently) want these to show a redbox // (Note: Logic duplicated in ExceptionsManager.js.) diff --git a/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m b/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m index b8a55652aa82ed..cf7a7ff5d5fc42 100644 --- a/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m +++ b/RNTester/RNTesterIntegrationTests/RNTesterIntegrationTests.m @@ -64,7 +64,7 @@ - (void)testTheTester_waitOneFrame // This list should be kept in sync with IntegrationTestsApp.js RCT_TEST(IntegrationTestHarnessTest) // RCT_TEST(TimersTest) // Disabled due to issue introduced in 61346d3 -RCT_TEST(AsyncStorageTest) +// TODO(TD15973709) RCT_TEST(AsyncStorageTest) RCT_TEST(AppEventsTest) //RCT_TEST(ImageCachePolicyTest) // This test never passed. RCT_TEST(ImageSnapshotTest) diff --git a/package.json b/package.json index 64ed5ae7fdb8fa..24b05859ed2e13 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "pretty-format": "^24.7.0", "promise": "^7.1.1", "prop-types": "^15.7.2", - "react-devtools-core": "^3.6.3", + "react-devtools-core": "^4.0.6", "react-refresh": "^0.4.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.15.0", diff --git a/yarn.lock b/yarn.lock index b930749fc875c7..b731c5989c2d5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1538,7 +1538,7 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== -async-limiter@~1.0.0: +async-limiter@^1.0.0, async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== @@ -2302,6 +2302,14 @@ cssstyle@^1.0.0: dependencies: cssom "0.3.x" +d@1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + damerau-levenshtein@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" @@ -2602,6 +2610,32 @@ es-to-primitive@^1.1.1, es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.50, es5-ext@~0.10.14: + version "0.10.50" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778" + integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.1" + next-tick "^1.0.0" + +es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= + dependencies: + d "1" + es5-ext "~0.10.14" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -5128,6 +5162,11 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +next-tick@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -5822,13 +5861,14 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-devtools-core@^3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-3.6.3.tgz#977d95b684c6ad28205f0c62e1e12c5f16675814" - integrity sha512-+P+eFy/yo8Z/UH9J0DqHZuUM5+RI2wl249TNvMx3J2jpUomLQa4Zxl56GEotGfw3PIP1eI+hVf1s53FlUONStQ== +react-devtools-core@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.0.6.tgz#681c7349db618856d6df7d31a6a49edee9d9e428" + integrity sha512-IhAndVGmV74Bio1BRrlbsonH6bX3XFHgz2uixJFlNjg/Rm264mBveIMwM6+rV3yObSKVnggXRMtJuyWoPk2Smw== dependencies: + es6-symbol "^3" shell-quote "^1.6.1" - ws "^3.3.1" + ws "^7" react-is@^16.8.1, react-is@^16.8.4: version "16.8.4" @@ -6904,6 +6944,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/type/-/type-1.0.3.tgz#16f5d39f27a2d28d86e48f8981859e9d3296c179" + integrity sha512-51IMtNfVcee8+9GJvj0spSuFcZHe9vSib6Xtgsny1Km9ugyz2mbS08I3rsUIRYgJohFRFU1160sgRodYz378Hg== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -6935,11 +6980,6 @@ ultron@1.0.x: resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -7213,15 +7253,6 @@ ws@^1.1.0, ws@^1.1.1, ws@^1.1.5: options ">=0.0.5" ultron "1.0.x" -ws@^3.3.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - ws@^5.2.0: version "5.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" @@ -7236,6 +7267,13 @@ ws@^6.1.4: dependencies: async-limiter "~1.0.0" +ws@^7: + version "7.1.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.1.tgz#f9942dc868b6dffb72c14fd8f2ba05f77a4d5983" + integrity sha512-o41D/WmDeca0BqYhsr3nJzQyg9NF5X8l/UdnFNux9cS3lwB+swm8qGWX5rn+aD6xfBU3rGmtHij7g7x6LxFU3A== + dependencies: + async-limiter "^1.0.0" + xcode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.0.0.tgz#134f1f94c26fbfe8a9aaa9724bfb2772419da1a2" From db5994980df136c5cce6cd90348b4bf18180562f Mon Sep 17 00:00:00 2001 From: Peter Laraia Date: Tue, 27 Aug 2019 00:23:04 -0700 Subject: [PATCH 0059/1244] Android Q related NaN error fix - don't try to do math with NaN values Summary: We noticed a repro-able crash in Ride in T52804960 on Android Q due to NaN being passed into setCameraDistance on View see Oleg's related post: https://fb.workplace.com/groups/rn.support/permalink/2682537011794897/ It looks like a generic fix or wrapper around View setCameraDistance might be planned in T48580247 But in the meantime, it kind of maybe seems reasonable-ish to say, ~~if the value of an input node is NaN, don't use it in the math for this node?~~ if a one of the inputs for this node evaluates to NaN, update that input node first? But I'm not super familiar with the Animations library so maybe that's not a good idea, idk. From what I can tell in our specific error, it's coming from an InterpolatedNode A based off an AdditionNode B which tried to add a ValueNode C + a InterpolatedNode D, but D had only just been created and not had it's first update, so it's value was NaN, and so when B runs it's update value of C + NaN means B's new values is also NaN, and A's subsequent update based on that now comes out to NaN. Atleast that's what it seems like based on Log statements. Reviewed By: olegbl Differential Revision: D16960177 fbshipit-source-id: 99c8ca35be4b5e99f7c21db6733ebd622ae39d07 --- .../java/com/facebook/react/animated/ValueAnimatedNode.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java index 063ce603396f15..c8dbfe23b2e256 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/animated/ValueAnimatedNode.java @@ -29,6 +29,9 @@ public ValueAnimatedNode(ReadableMap config) { } public double getValue() { + if (Double.isNaN(mOffset + mValue)) { + this.update(); + } return mOffset + mValue; } From 25f6be109b930950b4e913bd992002405c12f4fa Mon Sep 17 00:00:00 2001 From: Luna Wei Date: Tue, 27 Aug 2019 09:26:13 -0700 Subject: [PATCH 0060/1244] zoomToRect convert to command Summary: Convert this to a UIManager command Reviewed By: TheSavior Differential Revision: D16973257 fbshipit-source-id: 0e129c17926229fc20d020e3c0e52a36b0b405d2 --- Libraries/Components/ScrollResponder.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 8c58f75c5d5126..e099aaad2df915 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -16,14 +16,13 @@ const Keyboard = require('./Keyboard/Keyboard'); const ReactNative = require('../Renderer/shims/ReactNative'); const TextInputState = require('./TextInput/TextInputState'); const UIManager = require('../ReactNative/UIManager'); +const Platform = require('../Utilities/Platform'); const invariant = require('invariant'); const nullthrows = require('nullthrows'); const performanceNow = require('fbjs/lib/performanceNow'); const warning = require('fbjs/lib/warning'); -const {ScrollViewManager} = require('../BatchedBridge/NativeModules'); - import type {PressEvent, ScrollEvent} from '../Types/CoreEventTypes'; import type {KeyboardEvent} from './Keyboard/Keyboard'; import type EmitterSubscription from '../vendor/emitter/EmitterSubscription'; @@ -510,10 +509,7 @@ const ScrollResponderMixin = { |}, animated?: boolean, // deprecated, put this inside the rect argument instead ) { - invariant( - ScrollViewManager && ScrollViewManager.zoomToRect, - 'zoomToRect is not implemented', - ); + invariant(Platform.OS === 'ios', 'zoomToRect is not implemented'); if ('animated' in rect) { animated = rect.animated; delete rect.animated; @@ -522,10 +518,11 @@ const ScrollResponderMixin = { '`scrollResponderZoomTo` `animated` argument is deprecated. Use `options.animated` instead', ); } - ScrollViewManager.zoomToRect( + + UIManager.dispatchViewManagerCommand( this.scrollResponderGetScrollableNode(), - rect, - animated !== false, + UIManager.getViewManagerConfig('RCTScrollView').Commands.zoomToRect, + [rect, animated !== false], ); }, From c9ff99f18e5b4e464d8299bcb4c4ebdc12445f29 Mon Sep 17 00:00:00 2001 From: Tianyu Yao Date: Tue, 27 Aug 2019 09:50:32 -0700 Subject: [PATCH 0061/1244] Upgrade eslint-plugin-relay to 1.3.10 Summary: Bump eslint-plugin-relay version to 1.3.10 which contains fix for JS errors that blocks enabling the rules. Reviewed By: kassens Differential Revision: D17052055 fbshipit-source-id: 74867c16d128d2c0767e92861575ffcbe20370cc --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 24b05859ed2e13..c2fdec4ef2e4f4 100644 --- a/package.json +++ b/package.json @@ -137,7 +137,7 @@ "eslint-plugin-react": "7.12.4", "eslint-plugin-react-hooks": "^2.0.1", "eslint-plugin-react-native": "3.6.0", - "eslint-plugin-relay": "1.3.0", + "eslint-plugin-relay": "^1.3.10", "flow-bin": "^0.106.0", "flow-remove-types": "1.2.3", "jest": "^24.8.0", diff --git a/yarn.lock b/yarn.lock index b731c5989c2d5d..bf7ef0e3a07ddf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2756,10 +2756,10 @@ eslint-plugin-react@7.12.4: prop-types "^15.6.2" resolve "^1.9.0" -eslint-plugin-relay@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-1.3.0.tgz#89a0ea71489774fd1e3e79c0aed00ea817a6a7a1" - integrity sha512-50nG0qY6ukB0Zm2GM/eS2ZRVCVVaZmh+D2jiJsSqlX4AzT9oo2XOAjTX9zjxf9Nr7iCH2qzD5fU4tS9GtlMh0A== +eslint-plugin-relay@^1.3.10: + version "1.3.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-relay/-/eslint-plugin-relay-1.3.10.tgz#7dbf52d19618faf0c28cc65d0ccb0db53426e562" + integrity sha512-0ZZI+8/1tL0ljzq/vE5gDuLdBT7DpYI5hEVGQ/mfw3tDUB85HsFprWn6GldmsXI9Zx66jvcyELz3qRLvVK4Jdg== dependencies: graphql "^14.0.0" From 51aacd5241c4b4c0b9b1e1b8f9dabac45e5b5291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Kr=C3=BCger?= Date: Tue, 27 Aug 2019 18:20:51 -0700 Subject: [PATCH 0062/1244] Implement fading edges for ScrollView and it's dependent FlatList (#26163) Summary: This should add props for enabling horizontal and vertical fading edges for Scrollview and FlatList. These fading edges are used to communicate to the user that there is more content to see. ## Changelog [Android] [Added] - fading edges props to the FlatList and ScrollView components Pull Request resolved: https://github.com/facebook/react-native/pull/26163 Test Plan: Open the React Native test app and navigate to the FlatList section. Enable the `useFadingEdges` switch and insert a number into `Fading edge length`. ![device-2019-08-23-123745](https://user-images.githubusercontent.com/222393/63587150-7385cb00-c5a3-11e9-98dc-bffe8276d30c.png) ![device-2019-08-23-123844](https://user-images.githubusercontent.com/222393/63587156-75e82500-c5a3-11e9-9e9f-66876ac8f506.png) Differential Revision: D17080676 Pulled By: TheSavior fbshipit-source-id: 91df629c17052d43c99145672e9084e1379a4113 --- Libraries/Components/ScrollView/ScrollView.js | 12 +++++++++ Libraries/Lists/FlatList.js | 4 +++ .../js/examples/FlatList/FlatListExample.js | 26 ++++++++++++++++++- .../ReactHorizontalScrollViewManager.java | 11 ++++++++ .../views/scroll/ReactScrollViewManager.java | 11 ++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index b4298158b3354f..46f91c6a8acdf6 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -335,6 +335,18 @@ type AndroidProps = $ReadOnly<{| * @platform android */ persistentScrollbar?: ?boolean, + /** + * Fades out the edges of the the scroll content. + * + * If the value is greater than 0, the fading edges will be set accordingly + * to the current scroll direction and position, + * indicating if there is more content to show. + * + * The default value is 0. + * + * @platform android + */ + fadingEdgeLength?: ?number, |}>; type VRProps = $ReadOnly<{| diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index f9fb2a6aca1e00..595b6468f0e304 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -233,6 +233,10 @@ type OptionalProps = { * will be called when its corresponding ViewabilityConfig's conditions are met. */ viewabilityConfigCallbackPairs?: Array, + /** + * See `ScrollView` for flow type and further documentation. + */ + fadingEdgeLength?: ?number, }; export type Props = RequiredProps & OptionalProps & diff --git a/RNTester/js/examples/FlatList/FlatListExample.js b/RNTester/js/examples/FlatList/FlatListExample.js index bb7cc9afe88c02..e71b9acd6d4d4a 100644 --- a/RNTester/js/examples/FlatList/FlatListExample.js +++ b/RNTester/js/examples/FlatList/FlatListExample.js @@ -29,7 +29,14 @@ const { pressItem, renderSmallSwitchOption, } = require('../../components/ListExampleShared'); -const {Alert, Animated, StyleSheet, View} = require('react-native'); +const { + Alert, + Animated, + Platform, + StyleSheet, + TextInput, + View, +} = require('react-native'); import type {Item} from '../../components/ListExampleShared'; @@ -51,6 +58,7 @@ type State = {| virtualized: boolean, empty: boolean, useFlatListItemComponent: boolean, + fadingEdgeLength: number, |}; class FlatListExample extends React.PureComponent { @@ -65,6 +73,7 @@ class FlatListExample extends React.PureComponent { virtualized: true, empty: false, useFlatListItemComponent: false, + fadingEdgeLength: 0, }; _onChangeFilterText = filterText => { @@ -124,11 +133,26 @@ class FlatListExample extends React.PureComponent { {renderSmallSwitchOption(this, 'empty')} {renderSmallSwitchOption(this, 'debug')} {renderSmallSwitchOption(this, 'useFlatListItemComponent')} + {Platform.OS === 'android' && ( + + + this.setState({ + fadingEdgeLength: Number(event.nativeEvent.text), + }) + } + /> + + )} } ListFooterComponent={FooterComponent} diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index a8c9898e10d5d7..221cff4ccfe32c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -276,4 +276,15 @@ public void setOverflow(ReactHorizontalScrollView view, @Nullable String overflo public void setPersistentScrollbar(ReactHorizontalScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } + + @ReactProp(name = "fadingEdgeLength") + public void setFadingEdgeLength(ReactHorizontalScrollView view, int value) { + if (value > 0) { + view.setHorizontalFadingEdgeEnabled(true); + view.setFadingEdgeLength(value); + } else { + view.setHorizontalFadingEdgeEnabled(false); + view.setFadingEdgeLength(0); + } + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index cb8befaca24300..679db98450d311 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -278,6 +278,17 @@ public void setPersistentScrollbar(ReactScrollView view, boolean value) { view.setScrollbarFadingEnabled(!value); } + @ReactProp(name = "fadingEdgeLength") + public void setFadingEdgeLength(ReactScrollView view, int value) { + if (value > 0) { + view.setVerticalFadingEdgeEnabled(true); + view.setFadingEdgeLength(value); + } else { + view.setVerticalFadingEdgeEnabled(false); + view.setFadingEdgeLength(0); + } + } + @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return createExportedCustomDirectEventTypeConstants(); From 44bfc4be447680096f01fd00a1344c2cd398a981 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Tue, 27 Aug 2019 18:46:40 -0700 Subject: [PATCH 0063/1244] Support for UpdatePaddingMountItem Summary: Some views (TextInput!) need padding props. Reviewed By: mdvacca Differential Revision: D17081799 fbshipit-source-id: 4f5d6a139bb4dd878f90af0ed4a30fe3810e3429 --- .../react/fabric/FabricJSIModuleProvider.java | 2 + .../react/fabric/FabricUIManager.java | 7 +++ .../com/facebook/react/fabric/jni/Binding.cpp | 40 +++++++++++++++ .../fabric/mounting/MountingManager.java | 18 +++++++ .../mountitems/UpdatePaddingMountItem.java | 51 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java index 47f6ffbc4f6dec..e38da400e9772c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java @@ -22,6 +22,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem; +import com.facebook.react.fabric.mounting.mountitems.UpdatePaddingMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; import com.facebook.react.uimanager.StateWrapper; import com.facebook.react.uimanager.UIManagerModule; @@ -108,6 +109,7 @@ private static void loadClasses() { UpdateEventEmitterMountItem.class.getClass(); UpdateLayoutMountItem.class.getClass(); UpdateLocalDataMountItem.class.getClass(); + UpdatePaddingMountItem.class.getClass(); UpdatePropsMountItem.class.getClass(); LayoutMetricsConversions.class.getClass(); MountingManager.class.getClass(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 515c10b4e290c7..2bfa8d17798bbb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -54,6 +54,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem; +import com.facebook.react.fabric.mounting.mountitems.UpdatePaddingMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem; import com.facebook.react.modules.core.ReactChoreographer; @@ -285,6 +286,12 @@ private MountItem updateLayoutMountItem( return new UpdateLayoutMountItem(reactTag, x, y, width, height, layoutDirection); } + @DoNotStrip + @SuppressWarnings("unused") + private MountItem updatePaddingMountItem(int reactTag, int left, int top, int right, int bottom) { + return new UpdatePaddingMountItem(reactTag, left, top, right, bottom); + } + @DoNotStrip @SuppressWarnings("unused") private MountItem updatePropsMountItem(int reactTag, ReadableMap map) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 94ef5ef5e49fe5..2a7dfede65ab1d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -338,6 +338,34 @@ local_ref createUpdateLayoutMountItem( return nullptr; } +local_ref createUpdatePaddingMountItem( + const jni::global_ref &javaUIManager, + const ShadowViewMutation &mutation) { + + auto oldChildShadowView = mutation.oldChildShadowView; + auto newChildShadowView = mutation.newChildShadowView; + + if (oldChildShadowView.layoutMetrics.contentInsets == newChildShadowView.layoutMetrics.contentInsets) { + return nullptr; + } + + static auto updateLayoutInstruction = + jni::findClassStatic(UIManagerJavaDescriptor) + ->getMethod(jint, jint, jint, jint, jint)>( + "updatePaddingMountItem"); + + auto layoutMetrics = newChildShadowView.layoutMetrics; + auto pointScaleFactor = layoutMetrics.pointScaleFactor; + auto contentInsets = layoutMetrics.contentInsets; + + int left = round(contentInsets.left * pointScaleFactor); + int top = round(contentInsets.top * pointScaleFactor); + int right = round(contentInsets.right * pointScaleFactor); + int bottom = round(contentInsets.bottom * pointScaleFactor); + + return updateLayoutInstruction(javaUIManager, newChildShadowView.tag, left, top, right, bottom); +} + local_ref createInsertMountItem( const jni::global_ref &javaUIManager, const ShadowViewMutation &mutation) { @@ -559,6 +587,11 @@ void Binding::schedulerDidFinishTransaction( if (updateLayoutMountItem) { mountItems[position++] = updateLayoutMountItem; } + + auto updatePaddingMountItem = createUpdatePaddingMountItem(localJavaUIManager, mutation); + if (updatePaddingMountItem) { + mountItems[position++] = updatePaddingMountItem; + } } if (mutation.oldChildShadowView.eventEmitter != @@ -602,6 +635,13 @@ void Binding::schedulerDidFinishTransaction( if (updateLayoutMountItem) { mountItems[position++] = updateLayoutMountItem; } + + // Padding + auto updatePaddingMountItem = + createUpdatePaddingMountItem(localJavaUIManager, mutation); + if (updatePaddingMountItem) { + mountItems[position++] = updatePaddingMountItem; + } } // EventEmitter diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index fbc3f0018525d5..f48548fbe1d653 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -246,6 +246,24 @@ public void updateLayout(int reactTag, int x, int y, int width, int height) { viewToUpdate.layout(x, y, x + width, y + height); } + @UiThread + public void updatePadding(int reactTag, int left, int top, int right, int bottom) { + UiThreadUtil.assertOnUiThread(); + + ViewState viewState = getViewState(reactTag); + // Do not layout Root Views + if (viewState.mIsRoot) { + return; + } + + View viewToUpdate = viewState.mView; + if (viewToUpdate == null) { + throw new IllegalStateException("Unable to find View for tag: " + reactTag); + } + + viewToUpdate.setPadding(left, top, right, bottom); + } + @UiThread public void deleteView(int reactTag) { UiThreadUtil.assertOnUiThread(); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java new file mode 100644 index 00000000000000..446bece80afb99 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePaddingMountItem.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.MountingManager; + +/** + * A MountItem that represents setting the padding properties of a view (left, top, right, bottom). + * This is distinct from layout because it happens far less frequently from layout; so it is a perf + * optimization to transfer this data and execute the methods strictly less than the layout-related + * properties. + */ +public class UpdatePaddingMountItem implements MountItem { + + private final int mReactTag; + private final int mLeft; + private final int mTop; + private final int mRight; + private final int mBottom; + + public UpdatePaddingMountItem(int reactTag, int left, int top, int right, int bottom) { + mReactTag = reactTag; + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + } + + @Override + public void execute(MountingManager mountingManager) { + mountingManager.updatePadding(mReactTag, mLeft, mTop, mRight, mBottom); + } + + @Override + public String toString() { + return "UpdatePaddingMountItem [" + + mReactTag + + "] - left: " + + mLeft + + " - top: " + + mTop + + " - right: " + + mRight + + " - bottom: " + + mBottom; + } +} From 6f2e6f170e3ee785d1ba844971447ea24f91185e Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Wed, 28 Aug 2019 08:13:27 -0700 Subject: [PATCH 0064/1244] Fixes animated gifs incorrectly looping (#25612) Summary: [After migrate to new GIF implementation](https://github.com/facebook/react-native/pull/24822), we need to do some cleanup, before, we already unify the gif loop count between iOS and Android, more details please see https://github.com/facebook/react-native/pull/21999, so let's unify it again. ## Changelog [iOS] [Fixed] - Fixes animated gifs incorrectly looping Pull Request resolved: https://github.com/facebook/react-native/pull/25612 Test Plan: example gif should repeat playback twice. ``` ``` Reviewed By: sammy-SC Differential Revision: D16280067 Pulled By: osdnk fbshipit-source-id: 2351499855f1e0e97c358fa0b3544dd2cc0cf703 --- Libraries/Image/RCTAnimatedImage.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libraries/Image/RCTAnimatedImage.m b/Libraries/Image/RCTAnimatedImage.m index 2cabc1c648e9a3..60cdddfa4ac526 100644 --- a/Libraries/Image/RCTAnimatedImage.m +++ b/Libraries/Image/RCTAnimatedImage.m @@ -87,6 +87,10 @@ - (NSUInteger)imageLoopCountWithSource:(CGImageSourceRef)source NSNumber *gifLoopCount = gifProperties[(__bridge NSString *)kCGImagePropertyGIFLoopCount]; if (gifLoopCount != nil) { loopCount = gifLoopCount.unsignedIntegerValue; + // A loop count of 1 means it should repeat twice, 2 means, thrice, etc. + if (loopCount != 0) { + loopCount++; + } } } return loopCount; From ed9ecb5d73f9999af99145d992c2c0a43a17da41 Mon Sep 17 00:00:00 2001 From: Spencer Ahrens Date: Wed, 28 Aug 2019 08:46:49 -0700 Subject: [PATCH 0065/1244] improve UIManager QPL markers Summary: The commit and batch points are just showing up as points in scuba relativity which isn't very useful - we want to know how long they take as well, so make them ranges. Also adds view creation and update counts as annotations which can be handy for debugging regressions. Reviewed By: JoshuaGross, axe-fb Differential Revision: D17083058 fbshipit-source-id: dd29d12731734252930c9a4424bddbb98a8acccf --- .../react/uimanager/UIViewOperationQueue.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java index abbe9c3f83f281..9c7c31ec629200 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIViewOperationQueue.java @@ -535,12 +535,16 @@ public void execute() { private boolean mIsProfilingNextBatch = false; private long mNonBatchedExecutionTotalTime; private long mProfiledBatchCommitStartTime; + private long mProfiledBatchCommitEndTime; private long mProfiledBatchLayoutTime; private long mProfiledBatchDispatchViewUpdatesTime; private long mProfiledBatchRunStartTime; + private long mProfiledBatchRunEndTime; private long mProfiledBatchBatchedExecutionTime; private long mProfiledBatchNonBatchedExecutionTime; private long mThreadCpuTime; + private long mCreateViewCount; + private long mUpdatePropertiesOperationCount; public UIViewOperationQueue( ReactApplicationContext reactContext, @@ -568,17 +572,23 @@ public void setViewHierarchyUpdateDebugListener( public void profileNextBatch() { mIsProfilingNextBatch = true; mProfiledBatchCommitStartTime = 0; + mCreateViewCount = 0; + mUpdatePropertiesOperationCount = 0; } public Map getProfiledBatchPerfCounters() { Map perfMap = new HashMap<>(); perfMap.put("CommitStartTime", mProfiledBatchCommitStartTime); + perfMap.put("CommitEndTime", mProfiledBatchCommitEndTime); perfMap.put("LayoutTime", mProfiledBatchLayoutTime); perfMap.put("DispatchViewUpdatesTime", mProfiledBatchDispatchViewUpdatesTime); perfMap.put("RunStartTime", mProfiledBatchRunStartTime); + perfMap.put("RunEndTime", mProfiledBatchRunEndTime); perfMap.put("BatchedExecutionTime", mProfiledBatchBatchedExecutionTime); perfMap.put("NonBatchedExecutionTime", mProfiledBatchNonBatchedExecutionTime); perfMap.put("NativeModulesThreadCpuTime", mThreadCpuTime); + perfMap.put("CreateViewCount", mCreateViewCount); + perfMap.put("UpdatePropsCount", mUpdatePropertiesOperationCount); return perfMap; } @@ -644,6 +654,7 @@ public void enqueueCreateView( String viewClassName, @Nullable ReactStylesDiffMap initialProps) { synchronized (mNonBatchedOperationsLock) { + mCreateViewCount++; mNonBatchedOperations.addLast( new CreateViewOperation(themedContext, viewReactTag, viewClassName, initialProps)); } @@ -654,6 +665,7 @@ public void enqueueUpdateInstanceHandle(int reactTag, long instanceHandle) { } public void enqueueUpdateProperties(int reactTag, String className, ReactStylesDiffMap props) { + mUpdatePropertiesOperationCount++; mOperations.add(new UpdatePropertiesOperation(reactTag, props)); } @@ -782,9 +794,11 @@ public void run() { if (mIsProfilingNextBatch && mProfiledBatchCommitStartTime == 0) { mProfiledBatchCommitStartTime = commitStartTime; + mProfiledBatchCommitEndTime = SystemClock.uptimeMillis(); mProfiledBatchLayoutTime = layoutTime; mProfiledBatchDispatchViewUpdatesTime = dispatchViewUpdatesTime; mProfiledBatchRunStartTime = runStartTime; + mProfiledBatchRunEndTime = mProfiledBatchCommitEndTime; mThreadCpuTime = nativeModulesThreadCpuTime; Systrace.beginAsyncSection( From c526b3ff14c245ad6c853632c945e61c02eecffe Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 28 Aug 2019 12:39:33 -0700 Subject: [PATCH 0066/1244] Back out "Migrate TouchableNativeFeedback to use codegenNativeCommands" Summary: Reverting D16909622 and D16909622 due to T53098065. This change made TouchableNativeFeedback a bit less resilient to non native components being passed as the child. We probably need to handle this migration a little bit safer. Original commit changeset: 902528623742 Differential Revision: D17096765 fbshipit-source-id: e3fc1a21504459b6d7ea5442c4bc926bbd77379d --- .../TouchableNativeFeedback.android.js | 20 +++++++++++------- .../Components/View/ViewNativeComponent.js | 21 ------------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index a4edef82dbf377..7438917636d475 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -13,10 +13,11 @@ const Platform = require('../../Utilities/Platform'); const PropTypes = require('prop-types'); const React = require('react'); +const ReactNative = require('../../Renderer/shims/ReactNative'); const Touchable = require('./Touchable'); const TouchableWithoutFeedback = require('./TouchableWithoutFeedback'); +const UIManager = require('../../ReactNative/UIManager'); const View = require('../View/View'); -const {Commands: ViewCommands} = require('../View/ViewNativeComponent'); const createReactClass = require('create-react-class'); const ensurePositiveDelayProps = require('./ensurePositiveDelayProps'); @@ -261,16 +262,20 @@ const TouchableNativeFeedback = createReactClass({ ); }, - _handleRef: function(ref) { - this._viewRef = ref; - }, - _dispatchHotspotUpdate: function(destX, destY) { - ViewCommands.hotspotUpdate(this._viewRef, destX || 0, destY || 0); + UIManager.dispatchViewManagerCommand( + ReactNative.findNodeHandle(this), + UIManager.getViewManagerConfig('RCTView').Commands.hotspotUpdate, + [destX || 0, destY || 0], + ); }, _dispatchPressedStateChange: function(pressed) { - ViewCommands.setPressed(this._viewRef, pressed); + UIManager.dispatchViewManagerCommand( + ReactNative.findNodeHandle(this), + UIManager.getViewManagerConfig('RCTView').Commands.setPressed, + [pressed], + ); }, render: function() { @@ -313,7 +318,6 @@ const TouchableNativeFeedback = createReactClass({ accessibilityActions: this.props.accessibilityActions, onAccessibilityAction: this.props.onAccessibilityAction, children, - ref: this._handleRef, testID: this.props.testID, onLayout: this.props.onLayout, hitSlop: this.props.hitSlop, diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 276bbbb2e9c5ff..c735b5b864a77b 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -10,17 +10,13 @@ 'use strict'; -const React = require('react'); const Platform = require('../../Utilities/Platform'); const ReactNative = require('../../Renderer/shims/ReactNative'); const ReactNativeViewViewConfigAndroid = require('./ReactNativeViewViewConfigAndroid'); const registerGeneratedViewConfig = require('../../Utilities/registerGeneratedViewConfig'); const requireNativeComponent = require('../../ReactNative/requireNativeComponent'); -const codegenNativeCommands = require('../../Utilities/codegenNativeCommands') - .default; -import type {Int32} from '../../Types/CodegenTypes'; import type {ViewProps} from './ViewPropTypes'; export type ViewNativeComponentType = Class< @@ -70,22 +66,5 @@ if (__DEV__) { NativeViewComponent = requireNativeComponent('RCTView'); } -// These commands are Android only -interface NativeCommands { - +hotspotUpdate: ( - viewRef: React.ElementRef, - x: Int32, - y: Int32, - ) => void; - +setPressed: ( - viewRef: React.ElementRef, - pressed: boolean, - ) => void; -} - -export const Commands: NativeCommands = codegenNativeCommands({ - supportedCommands: ['hotspotUpdate', 'setPressed'], -}); - export const __INTERNAL_VIEW_CONFIG = viewConfig; export default ((NativeViewComponent: any): ViewNativeComponentType); From f8e509382315f84e3c29b07cc174093739ed980f Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 28 Aug 2019 13:14:00 -0700 Subject: [PATCH 0067/1244] Improve Flow Type for ScrollResponder Summary: FlatList and VirtualizedList were typing this value as any instead of using the actual type from ScrollView. I started with that change and then fixed the type to solve the other callsites in the codebase. Reviewed By: zackargyle Differential Revision: D17089934 fbshipit-source-id: bfc22cec9993904d779cad37b1de7cb3c0484d2c --- Libraries/Components/ScrollView/ScrollView.js | 16 +++++++++++++++- Libraries/Lists/FlatList.js | 3 ++- Libraries/Lists/SectionList.js | 3 ++- Libraries/Lists/VirtualizedList.js | 3 ++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 46f91c6a8acdf6..fc2a978bca85ae 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -64,7 +64,21 @@ if (Platform.OS === 'android') { } export type ScrollResponderType = { - ...ScrollView, + // We'd like to do ...ScrollView here, however Flow doesn't seem + // to see the imperative methods of ScrollView that way. Workaround the + // issue by specifying them manually. + getScrollableNode: $PropertyType, + getInnerViewNode: $PropertyType, + getNativeScrollRef: $PropertyType, + + setNativeProps: $PropertyType, + scrollTo: $PropertyType, + scrollWithoutAnimationTo: $PropertyType< + ScrollView, + 'scrollWithoutAnimationTo', + >, + flashScrollIndicators: $PropertyType, + ...typeof ScrollResponder.Mixin, }; diff --git a/Libraries/Lists/FlatList.js b/Libraries/Lists/FlatList.js index 595b6468f0e304..403fb391777194 100644 --- a/Libraries/Lists/FlatList.js +++ b/Libraries/Lists/FlatList.js @@ -18,6 +18,7 @@ const StyleSheet = require('../StyleSheet/StyleSheet'); const invariant = require('invariant'); +import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type { ViewabilityConfig, @@ -445,7 +446,7 @@ class FlatList extends React.PureComponent, void> { /** * Provides a handle to the underlying scroll responder. */ - getScrollResponder(): any { + getScrollResponder(): ?ScrollResponderType { if (this._listRef) { return this._listRef.getScrollResponder(); } diff --git a/Libraries/Lists/SectionList.js b/Libraries/Lists/SectionList.js index 99b621a2eb350f..d9ef718090a7e3 100644 --- a/Libraries/Lists/SectionList.js +++ b/Libraries/Lists/SectionList.js @@ -14,6 +14,7 @@ const React = require('react'); const ScrollView = require('../Components/ScrollView/ScrollView'); const VirtualizedSectionList = require('./VirtualizedSectionList'); +import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type {ViewToken} from './ViewabilityHelper'; import type { SectionBase as _SectionBase, @@ -275,7 +276,7 @@ class SectionList> extends React.PureComponent< /** * Provides a handle to the underlying scroll responder. */ - getScrollResponder(): ?ScrollView { + getScrollResponder(): ?ScrollResponderType { const listRef = this._wrapperListRef && this._wrapperListRef.getListRef(); if (listRef) { return listRef.getScrollResponder(); diff --git a/Libraries/Lists/VirtualizedList.js b/Libraries/Lists/VirtualizedList.js index 7dffc1729ef26c..62f614ec06e497 100644 --- a/Libraries/Lists/VirtualizedList.js +++ b/Libraries/Lists/VirtualizedList.js @@ -27,6 +27,7 @@ const warning = require('fbjs/lib/warning'); const {computeWindowedRenderLimits} = require('./VirtualizeUtils'); +import type {ScrollResponderType} from '../Components/ScrollView/ScrollView'; import type {ViewStyleProp} from '../StyleSheet/StyleSheet'; import type { ViewabilityConfig, @@ -431,7 +432,7 @@ class VirtualizedList extends React.PureComponent { * Note that `this._scrollRef` might not be a `ScrollView`, so we * need to check that it responds to `getScrollResponder` before calling it. */ - getScrollResponder(): any { + getScrollResponder(): ?ScrollResponderType { if (this._scrollRef && this._scrollRef.getScrollResponder) { return this._scrollRef.getScrollResponder(); } From 876a2789dba199c5b17514512eb2f42a7366c4cb Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 28 Aug 2019 21:08:27 -0700 Subject: [PATCH 0068/1244] Fabric: Preventing an obsolete state to be committed Summary: It's okay in Fabric model to commit some subtrees which are kinda obsolete (that's strange but technically it's not against the model), but it's not okay to commit some states that were already committed before. This diff prevents that. Reviewed By: JoshuaGross Differential Revision: D17053428 fbshipit-source-id: fb3536312163b7b57011647b4ba7b931c2179d89 --- ReactCommon/fabric/core/state/State.h | 8 ++++++++ .../fabric/core/state/StateCoordinator.cpp | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/ReactCommon/fabric/core/state/State.h b/ReactCommon/fabric/core/state/State.h index dbf7973fa0722f..6ab0c921afacaf 100644 --- a/ReactCommon/fabric/core/state/State.h +++ b/ReactCommon/fabric/core/state/State.h @@ -49,6 +49,14 @@ class State { * Must be used by `ShadowNode` *only*. */ State::Shared getCommitedState() const; + + /* + * Indicates that the state was committed once and then was replaced by a + * newer one. + * To be used by `StateCoordinator` only. + * Protected by mutex inside `StateCoordinator`. + */ + mutable bool isObsolete_{false}; }; } // namespace react diff --git a/ReactCommon/fabric/core/state/StateCoordinator.cpp b/ReactCommon/fabric/core/state/StateCoordinator.cpp index b8493a44a4703e..b1853a3243f643 100644 --- a/ReactCommon/fabric/core/state/StateCoordinator.cpp +++ b/ReactCommon/fabric/core/state/StateCoordinator.cpp @@ -24,6 +24,26 @@ const StateTarget &StateCoordinator::getTarget() const { void StateCoordinator::setTarget(StateTarget &&target) const { std::unique_lock lock(mutex_); + + assert(target && "`StateTarget` must not be empty."); + + if (target_) { + auto &previousState = target_.getShadowNode().getState(); + auto &nextState = target.getShadowNode().getState(); + + /* + * Checking and setting `isObsolete_` prevents old states to be recommitted + * on top of fresher states. It's okay to commit a tree with "older" Shadow + * Nodes (the evolution of nodes is not linear), however, we never back out + * states (they progress linearly). + */ + if (nextState->isObsolete_) { + return; + } + + previousState->isObsolete_ = true; + } + target_ = std::move(target); } From 33112a1c20a053934536f0c78f3d1d3f951446eb Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 28 Aug 2019 21:08:27 -0700 Subject: [PATCH 0069/1244] Fabric: Making `State::getMostRecentState` public Summary: That was always part of design, that's okay to get a newer state from any other state. We will need it in the future diffs. Reviewed By: sammy-SC Differential Revision: D17053429 fbshipit-source-id: 2174e7d6e3a1ed231f7f6e238d216d0b09ec8797 --- ReactCommon/fabric/core/shadownode/ShadowNode.cpp | 2 +- ReactCommon/fabric/core/state/State.cpp | 2 +- ReactCommon/fabric/core/state/State.h | 12 +++++++----- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp index c8b4e5967a289f..59b3629f3a8ff1 100644 --- a/ReactCommon/fabric/core/shadownode/ShadowNode.cpp +++ b/ReactCommon/fabric/core/shadownode/ShadowNode.cpp @@ -122,7 +122,7 @@ const State::Shared &ShadowNode::getState() const { State::Shared ShadowNode::getMostRecentState() const { if (state_) { - auto commitedState = state_->getCommitedState(); + auto commitedState = state_->getMostRecentState(); // Commited state can be `null` in case if no one node was commited yet; // in this case we return own `state`. diff --git a/ReactCommon/fabric/core/state/State.cpp b/ReactCommon/fabric/core/state/State.cpp index 7bc51a9e047e97..9c6f03662c09f7 100644 --- a/ReactCommon/fabric/core/state/State.cpp +++ b/ReactCommon/fabric/core/state/State.cpp @@ -30,7 +30,7 @@ void State::commit(const ShadowNode &shadowNode) const { stateCoordinator_->setTarget(StateTarget{shadowNode}); } -State::Shared State::getCommitedState() const { +State::Shared State::getMostRecentState() const { auto target = stateCoordinator_->getTarget(); return target ? target.getShadowNode().getState() : ShadowNodeFragment::statePlaceholder(); diff --git a/ReactCommon/fabric/core/state/State.h b/ReactCommon/fabric/core/state/State.h index 6ab0c921afacaf..65871592808b8f 100644 --- a/ReactCommon/fabric/core/state/State.h +++ b/ReactCommon/fabric/core/state/State.h @@ -28,6 +28,13 @@ class State { explicit State(StateCoordinator::Shared const &stateCoordinator); virtual ~State() = default; + /* +   * Returns a momentary value of the most recently committed state +   * associated with a family of nodes which this state belongs to. +   * Sequential calls might return different values. + */ + State::Shared getMostRecentState() const; + #ifdef ANDROID virtual const folly::dynamic getDynamic() const; virtual void updateState(folly::dynamic data) const; @@ -45,11 +52,6 @@ class State { */ void commit(const ShadowNode &shadowNode) const; - /* - * Must be used by `ShadowNode` *only*. - */ - State::Shared getCommitedState() const; - /* * Indicates that the state was committed once and then was replaced by a * newer one. From 28d26c2e5628b02a7b76d7e4b2ca438d1fcd7487 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Wed, 28 Aug 2019 21:08:27 -0700 Subject: [PATCH 0070/1244] Fabric: Small optimization in RCTMountingManager Summary: `pullTransaction` can return an empty transaction. That's fine to interate over the empty collection and do nothing, but it's inneficient because we also call delegate methods around the loop (that can be expensive). Reviewed By: sammy-SC Differential Revision: D17053430 fbshipit-source-id: c78959d47ea22cd9bb99419f6a80de3ac8e89fd3 --- React/Fabric/Mounting/RCTMountingManager.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/React/Fabric/Mounting/RCTMountingManager.mm b/React/Fabric/Mounting/RCTMountingManager.mm index 48eeeff15ee90e..54b3d70757d4a4 100644 --- a/React/Fabric/Mounting/RCTMountingManager.mm +++ b/React/Fabric/Mounting/RCTMountingManager.mm @@ -251,10 +251,15 @@ - (void)mountMutations:(MountingCoordinator::Shared const &)mountingCoordinator } auto surfaceId = transaction->getSurfaceId(); + auto &mutations = transaction->getMutations(); + + if (mutations.size() == 0) { + return; + } RCTAssertMainQueue(); [self.delegate mountingManager:self willMountComponentsWithRootTag:surfaceId]; - RNPerformMountInstructions(transaction->getMutations(), self.componentViewRegistry); + RNPerformMountInstructions(mutations, self.componentViewRegistry); [self.delegate mountingManager:self didMountComponentsWithRootTag:surfaceId]; } From 4763000554c71be40b82a740651706781acad2e3 Mon Sep 17 00:00:00 2001 From: Dulmandakh Date: Thu, 29 Aug 2019 07:31:51 -0700 Subject: [PATCH 0071/1244] bump android gradle plugin to 3.5.0 (#26129) Summary: Android Gradle Plugin 3.5.0 released with a lot of improvements and bug fixes. It's important to have this change merged before 0.61 release. See https://developer.android.com/studio/releases/gradle-plugin ## Changelog [Android] [Changed] - bump android gradle plugin to 3.5.0 Pull Request resolved: https://github.com/facebook/react-native/pull/26129 Test Plan: RNTester builds and runs as expected Reviewed By: mdvacca Differential Revision: D17091520 Pulled By: osdnk fbshipit-source-id: 232b9209526e62a7344d74422fd8471a03dec7f4 --- build.gradle.kts | 2 +- template/android/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index de0ffb42c36e83..76a0b6716379a4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,7 +10,7 @@ buildscript { jcenter() } dependencies { - classpath("com.android.tools.build:gradle:3.4.2") + classpath("com.android.tools.build:gradle:3.5.0") classpath("de.undercouch:gradle-download-task:4.0.0") // NOTE: Do not place your application dependencies here; they belong diff --git a/template/android/build.gradle b/template/android/build.gradle index 28f7ec645bd148..698ffa8ccef077 100644 --- a/template/android/build.gradle +++ b/template/android/build.gradle @@ -12,7 +12,7 @@ buildscript { jcenter() } dependencies { - classpath("com.android.tools.build:gradle:3.4.2") + classpath("com.android.tools.build:gradle:3.5.0") // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From 15b2353382c46dc5f0130ff44b9deb6a2361e3e5 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Thu, 29 Aug 2019 14:28:51 -0700 Subject: [PATCH 0072/1244] iOS Pods: added missing deps for React-CoreModules Summary: This is needed for use_frameworks! support with CocoaPods. Also, with recent changes to RCTImageLoader etc (moved to CoreModules), we need to add a dep to `React-RCTImage` pod. If this approach works for 0.61 branch as well, it should be beneficial to pick. Note that https://github.com/facebook/react-native/pull/26151 attempts to fix similar things, but in 0.61 branch, not master. Reviewed By: axe-fb Differential Revision: D17120352 fbshipit-source-id: ca96a7a61a6422a6f9fc3a4bf3add51e6f33f4f1 --- RNTester/Podfile.lock | 4 +++- React/CoreModules/React-CoreModules.podspec | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index cab692d2f3fd60..7357c2f0d611c5 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -172,7 +172,9 @@ PODS: - React-CoreModules (1000.0.0): - FBReactNativeSpec (= 1000.0.0) - Folly (= 2018.10.22.00) + - RCTTypeSafety (= 1000.0.0) - React-Core/CoreModulesHeaders (= 1000.0.0) + - React-RCTImage (= 1000.0.0) - ReactCommon/turbomodule/core (= 1000.0.0) - React-cxxreact (1000.0.0): - boost-for-react-native (= 1.63.0) @@ -356,7 +358,7 @@ SPEC CHECKSUMS: React: 28a654b69575941571c073a656bc06795825e7f7 React-ART: a5da06a892342d03896e0db45a7072525981f63c React-Core: 47b8ab211d9325292811e62ee23c54b464853111 - React-CoreModules: 38d8cc34497674ae3d411e644a9b17ad75ef3f74 + React-CoreModules: 96b2f1e0b84493e6c1b7f3bb21357f24fdcfce2f React-cxxreact: 7c4242192149ce0205b53efaa03e3bf86ba4337c React-jsi: 98d1f9d8a79d2720ba6a44c2d928a77f315b7e4f React-jsiexecutor: c0ab8c80a6e88380d63f583690a50d4a723b47b5 diff --git a/React/CoreModules/React-CoreModules.podspec b/React/CoreModules/React-CoreModules.podspec index 0b4c255ee7c749..5c62b379dec386 100644 --- a/React/CoreModules/React-CoreModules.podspec +++ b/React/CoreModules/React-CoreModules.podspec @@ -40,6 +40,8 @@ Pod::Spec.new do |s| s.dependency "FBReactNativeSpec", version s.dependency "Folly", folly_version + s.dependency "RCTTypeSafety", version s.dependency "React-Core/CoreModulesHeaders", version + s.dependency "React-RCTImage", version s.dependency "ReactCommon/turbomodule/core", version end From 9d5d2549e31dd96df6f3aae0c3f45849e3281157 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Thu, 29 Aug 2019 16:07:04 -0700 Subject: [PATCH 0073/1244] Add copyright header and @generated annotation to Android view manager interfaces and delegates Summary: This diff adds a missing copyright header and the `generated` annotation to the Java files generated by the JS codegen. Since we are going to check in the generated classes for the OSS components, we need to make sure the Lint formatter doesn't complain about formatting issues in those files. Reviewed By: fkgozali Differential Revision: D17101946 fbshipit-source-id: 1361a294b8c1538c0ea346b43ef623e843d7038d --- .../components/GeneratePropsJavaDelegate.js | 10 +- .../components/GeneratePropsJavaInterface.js | 10 +- .../GeneratePropsJavaDelegate-test.js.snap | 240 ++++++++++++++++-- .../GeneratePropsJavaInterface-test.js.snap | 240 ++++++++++++++++-- 4 files changed, 450 insertions(+), 50 deletions(-) diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js index 9a902d0aa022f9..f20296116398cd 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js @@ -21,7 +21,15 @@ const {getImports, toSafeJavaString} = require('./JavaHelpers'); // File path -> contents type FilesOutput = Map; -const template = ` +const template = `/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* ${'@'}generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; ::_IMPORTS_:: diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js index 64360d7dc85be8..d8e63634a16aa5 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js @@ -21,7 +21,15 @@ const {getImports, toSafeJavaString} = require('./JavaHelpers'); // File path -> contents type FilesOutput = Map; -const template = ` +const template = `/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* ${'@'}generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; ::_IMPORTS_:: diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap index 1e55210288591b..2dc6baa450ceb5 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaDelegate-test.js.snap @@ -2,7 +2,15 @@ exports[`GeneratePropsJavaDelegate can generate fixture ARRAY_PROPS 1`] = ` Map { - "ArrayPropsNativeComponentManagerDelegate.java" => " + "ArrayPropsNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -60,7 +68,15 @@ public class ArrayPropsNativeComponentManagerDelegate " + "ArrayPropsNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -91,7 +107,15 @@ public class ArrayPropsNativeComponentManagerDelegate " + "BooleanPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -121,7 +145,15 @@ public class BooleanPropNativeComponentManagerDelegate " + "ColorPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -151,7 +183,15 @@ public class ColorPropNativeComponentManagerDelegate " + "CommandNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -187,7 +227,15 @@ public class CommandNativeComponentManagerDelegate " + "CommandNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -226,7 +274,15 @@ public class CommandNativeComponentManagerDelegate " + "DoublePropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -271,7 +327,15 @@ public class DoublePropNativeComponentManagerDelegate " + "EnumPropsNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -301,7 +365,15 @@ public class EnumPropsNativeComponentManagerDelegate " + "EventsNestedObjectNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -331,7 +403,15 @@ public class EventsNestedObjectNativeComponentManagerDelegate " + "EventsNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -361,7 +441,15 @@ public class EventsNativeComponentManagerDelegate " + "InterfaceOnlyComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -385,7 +473,15 @@ public class InterfaceOnlyComponentManagerDelegate " + "FloatPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -430,7 +526,15 @@ public class FloatPropNativeComponentManagerDelegate " + "ImagePropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -461,7 +565,15 @@ public class ImagePropNativeComponentManagerDelegate " + "IntegerPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -497,7 +609,15 @@ public class IntegerPropNativeComponentManagerDelegate " + "InterfaceOnlyComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -527,7 +647,15 @@ public class InterfaceOnlyComponentManagerDelegate " + "ImageColorPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -567,7 +695,15 @@ public class ImageColorPropNativeComponentManagerDelegate " + "NoPropsNoEventsComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -591,7 +727,15 @@ public class NoPropsNoEventsComponentManagerDelegate " + "ObjectPropsManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -622,7 +766,15 @@ public class ObjectPropsManagerDelegate " + "PointPropNativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -653,7 +805,15 @@ public class PointPropNativeComponentManagerDelegate " + "StringPropComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -686,7 +846,15 @@ public class StringPropComponentManagerDelegate " + "MultiFile1NativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -711,7 +879,15 @@ public class MultiFile1NativeComponentManagerDelegate " + "MultiFile2NativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -741,7 +917,15 @@ public class MultiFile2NativeComponentManagerDelegate " + "MultiComponent1NativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -766,7 +950,15 @@ public class MultiComponent1NativeComponentManagerDelegate " + "MultiComponent2NativeComponentManagerDelegate.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; diff --git a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap index 80b37f18fc2aa3..18938d1855a307 100644 --- a/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap +++ b/packages/react-native-codegen/src/generators/components/__tests__/__snapshots__/GeneratePropsJavaInterface-test.js.snap @@ -2,7 +2,15 @@ exports[`GeneratePropsJavaInterface can generate fixture ARRAY_PROPS 1`] = ` Map { - "ArrayPropsNativeComponentManagerInterface.java" => " + "ArrayPropsNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -27,7 +35,15 @@ public interface ArrayPropsNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture ARRAY_PROPS_WITH_NESTED_OBJECT 1`] = ` Map { - "ArrayPropsNativeComponentManagerInterface.java" => " + "ArrayPropsNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -43,7 +59,15 @@ public interface ArrayPropsNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture BOOLEAN_PROP 1`] = ` Map { - "BooleanPropNativeComponentManagerInterface.java" => " + "BooleanPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -57,7 +81,15 @@ public interface BooleanPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture COLOR_PROP 1`] = ` Map { - "ColorPropNativeComponentManagerInterface.java" => " + "ColorPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -72,7 +104,15 @@ public interface ColorPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture COMMANDS 1`] = ` Map { - "CommandNativeComponentManagerInterface.java" => " + "CommandNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -88,7 +128,15 @@ public interface CommandNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture COMMANDS_AND_PROPS 1`] = ` Map { - "CommandNativeComponentManagerInterface.java" => " + "CommandNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -104,7 +152,15 @@ public interface CommandNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture DOUBLE_PROPS 1`] = ` Map { - "DoublePropNativeComponentManagerInterface.java" => " + "DoublePropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -123,7 +179,15 @@ public interface DoublePropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture ENUM_PROP 1`] = ` Map { - "EnumPropsNativeComponentManagerInterface.java" => " + "EnumPropsNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -138,7 +202,15 @@ public interface EnumPropsNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture EVENT_NESTED_OBJECT_PROPS 1`] = ` Map { - "EventsNestedObjectNativeComponentManagerInterface.java" => " + "EventsNestedObjectNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -152,7 +224,15 @@ public interface EventsNestedObjectNativeComponentManagerInterface " + "EventsNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -166,7 +246,15 @@ public interface EventsNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture EVENTS_WITH_PAPER_NAME 1`] = ` Map { - "InterfaceOnlyComponentManagerInterface.java" => " + "InterfaceOnlyComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -180,7 +268,15 @@ public interface InterfaceOnlyComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture FLOAT_PROPS 1`] = ` Map { - "FloatPropNativeComponentManagerInterface.java" => " + "FloatPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -199,7 +295,15 @@ public interface FloatPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture IMAGE_PROP 1`] = ` Map { - "ImagePropNativeComponentManagerInterface.java" => " + "ImagePropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -215,7 +319,15 @@ public interface ImagePropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture INTEGER_PROPS 1`] = ` Map { - "IntegerPropNativeComponentManagerInterface.java" => " + "IntegerPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -231,7 +343,15 @@ public interface IntegerPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture INTERFACE_ONLY 1`] = ` Map { - "InterfaceOnlyComponentManagerInterface.java" => " + "InterfaceOnlyComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -246,7 +366,15 @@ public interface InterfaceOnlyComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture MULTI_NATIVE_PROP 1`] = ` Map { - "ImageColorPropNativeComponentManagerInterface.java" => " + "ImageColorPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -265,7 +393,15 @@ public interface ImageColorPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture NO_PROPS_NO_EVENTS 1`] = ` Map { - "NoPropsNoEventsComponentManagerInterface.java" => " + "NoPropsNoEventsComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -279,7 +415,15 @@ public interface NoPropsNoEventsComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture OBJECT_PROPS 1`] = ` Map { - "ObjectPropsManagerInterface.java" => " + "ObjectPropsManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -295,7 +439,15 @@ public interface ObjectPropsManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture POINT_PROP 1`] = ` Map { - "PointPropNativeComponentManagerInterface.java" => " + "PointPropNativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -311,7 +463,15 @@ public interface PointPropNativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture STRING_PROP 1`] = ` Map { - "StringPropComponentManagerInterface.java" => " + "StringPropComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -327,7 +487,15 @@ public interface StringPropComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture TWO_COMPONENTS_DIFFERENT_FILES 1`] = ` Map { - "MultiFile1NativeComponentManagerInterface.java" => " + "MultiFile1NativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -336,7 +504,15 @@ public interface MultiFile1NativeComponentManagerInterface { void setDisabled(T view, boolean value); } ", - "MultiFile2NativeComponentManagerInterface.java" => " + "MultiFile2NativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -350,7 +526,15 @@ public interface MultiFile2NativeComponentManagerInterface { exports[`GeneratePropsJavaInterface can generate fixture TWO_COMPONENTS_SAME_FILE 1`] = ` Map { - "MultiComponent1NativeComponentManagerInterface.java" => " + "MultiComponent1NativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; @@ -359,7 +543,15 @@ public interface MultiComponent1NativeComponentManagerInterface void setDisabled(T view, boolean value); } ", - "MultiComponent2NativeComponentManagerInterface.java" => " + "MultiComponent2NativeComponentManagerInterface.java" => "/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + package com.facebook.react.viewmanagers; import android.view.View; From 3d3db71763342a7e62a2c54118dd65bd633f889f Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Thu, 29 Aug 2019 16:07:04 -0700 Subject: [PATCH 0074/1244] Generate OSS view manager interfaces and delegates Summary: This diff checks in the OSS view manager interfaces and delegates generated by the JS codegen. This is a temporary workaround since we don't have the JS codegen running in open source. Reviewed By: fkgozali Differential Revision: D17104816 fbshipit-source-id: 848afc081785c9a78891d3dc0740ebe858eb8891 --- .../ActivityIndicatorViewManagerDelegate.java | 41 +++++++++++ ...ActivityIndicatorViewManagerInterface.java | 20 ++++++ .../AndroidDrawerLayoutManagerDelegate.java | 59 +++++++++++++++ .../AndroidDrawerLayoutManagerInterface.java | 24 +++++++ .../AndroidProgressBarManagerDelegate.java | 50 +++++++++++++ .../AndroidProgressBarManagerInterface.java | 23 ++++++ ...roidSwipeRefreshLayoutManagerDelegate.java | 48 +++++++++++++ ...oidSwipeRefreshLayoutManagerInterface.java | 23 ++++++ .../java/com/facebook/react/viewmanagers/BUCK | 17 +++++ .../ModalHostViewManagerDelegate.java | 51 +++++++++++++ .../ModalHostViewManagerInterface.java | 24 +++++++ .../PullToRefreshViewManagerDelegate.java | 41 +++++++++++ .../PullToRefreshViewManagerInterface.java | 20 ++++++ .../RCTInputAccessoryViewManagerDelegate.java | 32 +++++++++ ...RCTInputAccessoryViewManagerInterface.java | 17 +++++ .../RCTMaskedViewManagerDelegate.java | 26 +++++++ .../RCTMaskedViewManagerInterface.java | 16 +++++ .../RCTProgressViewManagerDelegate.java | 48 +++++++++++++ .../RCTProgressViewManagerInterface.java | 23 ++++++ .../RCTSafeAreaViewManagerDelegate.java | 32 +++++++++ .../RCTSafeAreaViewManagerInterface.java | 16 +++++ .../RCTSegmentedControlManagerDelegate.java | 45 ++++++++++++ .../RCTSegmentedControlManagerInterface.java | 22 ++++++ .../viewmanagers/SliderManagerDelegate.java | 72 +++++++++++++++++++ .../viewmanagers/SliderManagerInterface.java | 31 ++++++++ .../viewmanagers/SwitchManagerDelegate.java | 53 ++++++++++++++ .../viewmanagers/SwitchManagerInterface.java | 24 +++++++ ...nimplementedNativeViewManagerDelegate.java | 32 +++++++++ ...implementedNativeViewManagerInterface.java | 17 +++++ 29 files changed, 947 insertions(+) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerInterface.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerInterface.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerDelegate.java new file mode 100644 index 00000000000000..20acd61d723872 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerDelegate.java @@ -0,0 +1,41 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class ActivityIndicatorViewManagerDelegate & ActivityIndicatorViewManagerInterface> extends BaseViewManagerDelegate { + public ActivityIndicatorViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "hidesWhenStopped": + mViewManager.setHidesWhenStopped(view, value == null ? false : (boolean) value); + break; + case "animating": + mViewManager.setAnimating(view, value == null ? false : (boolean) value); + break; + case "color": + mViewManager.setColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "size": + mViewManager.setSize(view, (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerInterface.java new file mode 100644 index 00000000000000..d217b8bc2fdfbe --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ActivityIndicatorViewManagerInterface.java @@ -0,0 +1,20 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface ActivityIndicatorViewManagerInterface { + void setHidesWhenStopped(T view, boolean value); + void setAnimating(T view, boolean value); + void setColor(T view, @Nullable Integer value); + void setSize(T view, @Nullable String value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerDelegate.java new file mode 100644 index 00000000000000..9bd531194b2356 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerDelegate.java @@ -0,0 +1,59 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class AndroidDrawerLayoutManagerDelegate & AndroidDrawerLayoutManagerInterface> extends BaseViewManagerDelegate { + public AndroidDrawerLayoutManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "keyboardDismissMode": + mViewManager.setKeyboardDismissMode(view, (String) value); + break; + case "drawerBackgroundColor": + mViewManager.setDrawerBackgroundColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "drawerPosition": + mViewManager.setDrawerPosition(view, (String) value); + break; + case "drawerWidth": + mViewManager.setDrawerWidth(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "drawerLockMode": + mViewManager.setDrawerLockMode(view, (String) value); + break; + case "statusBarBackgroundColor": + mViewManager.setStatusBarBackgroundColor(view, value == null ? null : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } + + public void receiveCommand(AndroidDrawerLayoutManagerInterface viewManager, T view, String commandName, ReadableArray args) { + switch (commandName) { + case "openDrawer": + viewManager.openDrawer(view); + break; + case "closeDrawer": + viewManager.closeDrawer(view); + break; + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerInterface.java new file mode 100644 index 00000000000000..c5ce4106f07eee --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidDrawerLayoutManagerInterface.java @@ -0,0 +1,24 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface AndroidDrawerLayoutManagerInterface { + void setKeyboardDismissMode(T view, @Nullable String value); + void setDrawerBackgroundColor(T view, @Nullable Integer value); + void setDrawerPosition(T view, @Nullable String value); + void setDrawerWidth(T view, float value); + void setDrawerLockMode(T view, @Nullable String value); + void setStatusBarBackgroundColor(T view, @Nullable Integer value); + void openDrawer(T view); + void closeDrawer(T view); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerDelegate.java new file mode 100644 index 00000000000000..f47432f721b5a2 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerDelegate.java @@ -0,0 +1,50 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class AndroidProgressBarManagerDelegate & AndroidProgressBarManagerInterface> extends BaseViewManagerDelegate { + public AndroidProgressBarManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "styleAttr": + mViewManager.setStyleAttr(view, value == null ? null : (String) value); + break; + case "typeAttr": + mViewManager.setTypeAttr(view, value == null ? null : (String) value); + break; + case "indeterminate": + mViewManager.setIndeterminate(view, value == null ? false : (boolean) value); + break; + case "progress": + mViewManager.setProgress(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "animating": + mViewManager.setAnimating(view, value == null ? true : (boolean) value); + break; + case "color": + mViewManager.setColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "testID": + mViewManager.setTestID(view, value == null ? "" : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerInterface.java new file mode 100644 index 00000000000000..8c804fdf83db46 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidProgressBarManagerInterface.java @@ -0,0 +1,23 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface AndroidProgressBarManagerInterface { + void setStyleAttr(T view, @Nullable String value); + void setTypeAttr(T view, @Nullable String value); + void setIndeterminate(T view, boolean value); + void setProgress(T view, float value); + void setAnimating(T view, boolean value); + void setColor(T view, @Nullable Integer value); + void setTestID(T view, @Nullable String value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerDelegate.java new file mode 100644 index 00000000000000..192fa053b7b65c --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerDelegate.java @@ -0,0 +1,48 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class AndroidSwipeRefreshLayoutManagerDelegate & AndroidSwipeRefreshLayoutManagerInterface> extends BaseViewManagerDelegate { + public AndroidSwipeRefreshLayoutManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "enabled": + mViewManager.setEnabled(view, value == null ? false : (boolean) value); + break; + case "colors": + mViewManager.setColors(view, (ReadableArray) value); + break; + case "progressBackgroundColor": + mViewManager.setProgressBackgroundColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "size": + mViewManager.setSize(view, value == null ? 1 : ((Double) value).intValue()); + break; + case "progressViewOffset": + mViewManager.setProgressViewOffset(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "refreshing": + mViewManager.setRefreshing(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerInterface.java new file mode 100644 index 00000000000000..90707ec0b4fde8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/AndroidSwipeRefreshLayoutManagerInterface.java @@ -0,0 +1,23 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; + +public interface AndroidSwipeRefreshLayoutManagerInterface { + void setEnabled(T view, boolean value); + void setColors(T view, @Nullable ReadableArray value); + void setProgressBackgroundColor(T view, @Nullable Integer value); + void setSize(T view, int value); + void setProgressViewOffset(T view, float value); + void setRefreshing(T view, boolean value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/BUCK b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/BUCK new file mode 100644 index 00000000000000..16bd74bbb87148 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/BUCK @@ -0,0 +1,17 @@ +load("//tools/build_defs/oss:rn_defs.bzl", "react_native_dep", "react_native_target", "rn_android_library") + +rn_android_library( + name = "viewmanagers", + srcs = glob(["*.java"]), + is_androidx = True, + provided_deps = [ + react_native_dep("third-party/android/androidx:annotation"), + ], + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/uimanager:uimanager"), + ], +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerDelegate.java new file mode 100644 index 00000000000000..07ab506ac1853f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerDelegate.java @@ -0,0 +1,51 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class ModalHostViewManagerDelegate & ModalHostViewManagerInterface> extends BaseViewManagerDelegate { + public ModalHostViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "animationType": + mViewManager.setAnimationType(view, (String) value); + break; + case "presentationStyle": + mViewManager.setPresentationStyle(view, (String) value); + break; + case "transparent": + mViewManager.setTransparent(view, value == null ? false : (boolean) value); + break; + case "hardwareAccelerated": + mViewManager.setHardwareAccelerated(view, value == null ? false : (boolean) value); + break; + case "animated": + mViewManager.setAnimated(view, value == null ? false : (boolean) value); + break; + case "supportedOrientations": + mViewManager.setSupportedOrientations(view, (ReadableArray) value); + break; + case "identifier": + mViewManager.setIdentifier(view, value == null ? 0 : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerInterface.java new file mode 100644 index 00000000000000..ab8122bd2075bf --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ModalHostViewManagerInterface.java @@ -0,0 +1,24 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; + +public interface ModalHostViewManagerInterface { + void setAnimationType(T view, @Nullable String value); + void setPresentationStyle(T view, @Nullable String value); + void setTransparent(T view, boolean value); + void setHardwareAccelerated(T view, boolean value); + void setAnimated(T view, boolean value); + void setSupportedOrientations(T view, @Nullable ReadableArray value); + void setIdentifier(T view, int value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerDelegate.java new file mode 100644 index 00000000000000..9ff2d6aacfe575 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerDelegate.java @@ -0,0 +1,41 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class PullToRefreshViewManagerDelegate & PullToRefreshViewManagerInterface> extends BaseViewManagerDelegate { + public PullToRefreshViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "tintColor": + mViewManager.setTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "titleColor": + mViewManager.setTitleColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "title": + mViewManager.setTitle(view, value == null ? null : (String) value); + break; + case "refreshing": + mViewManager.setRefreshing(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerInterface.java new file mode 100644 index 00000000000000..cbc8f16b672dea --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/PullToRefreshViewManagerInterface.java @@ -0,0 +1,20 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface PullToRefreshViewManagerInterface { + void setTintColor(T view, @Nullable Integer value); + void setTitleColor(T view, @Nullable Integer value); + void setTitle(T view, @Nullable String value); + void setRefreshing(T view, boolean value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java new file mode 100644 index 00000000000000..38f9f246eff556 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java @@ -0,0 +1,32 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class RCTInputAccessoryViewManagerDelegate & RCTInputAccessoryViewManagerInterface> extends BaseViewManagerDelegate { + public RCTInputAccessoryViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "backgroundColor": + mViewManager.setBackgroundColor(view, value == null ? null : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java new file mode 100644 index 00000000000000..07d5f39534c2b4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java @@ -0,0 +1,17 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface RCTInputAccessoryViewManagerInterface { + void setBackgroundColor(T view, @Nullable Integer value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java new file mode 100644 index 00000000000000..9fb175d5af6279 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java @@ -0,0 +1,26 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class RCTMaskedViewManagerDelegate & RCTMaskedViewManagerInterface> extends BaseViewManagerDelegate { + public RCTMaskedViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + super.setProperty(view, propName, value); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java new file mode 100644 index 00000000000000..44e8febd19e1b4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java @@ -0,0 +1,16 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; + +public interface RCTMaskedViewManagerInterface { + // No props +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java new file mode 100644 index 00000000000000..f466c2d01a05f5 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java @@ -0,0 +1,48 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class RCTProgressViewManagerDelegate & RCTProgressViewManagerInterface> extends BaseViewManagerDelegate { + public RCTProgressViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "progressViewStyle": + mViewManager.setProgressViewStyle(view, (String) value); + break; + case "progress": + mViewManager.setProgress(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "progressTintColor": + mViewManager.setProgressTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "trackTintColor": + mViewManager.setTrackTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "progressImage": + mViewManager.setProgressImage(view, (ReadableMap) value); + break; + case "trackImage": + mViewManager.setTrackImage(view, (ReadableMap) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java new file mode 100644 index 00000000000000..250047e92d1c88 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java @@ -0,0 +1,23 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableMap; + +public interface RCTProgressViewManagerInterface { + void setProgressViewStyle(T view, @Nullable String value); + void setProgress(T view, float value); + void setProgressTintColor(T view, @Nullable Integer value); + void setTrackTintColor(T view, @Nullable Integer value); + void setProgressImage(T view, @Nullable ReadableMap value); + void setTrackImage(T view, @Nullable ReadableMap value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java new file mode 100644 index 00000000000000..c30912e1a297cd --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java @@ -0,0 +1,32 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class RCTSafeAreaViewManagerDelegate & RCTSafeAreaViewManagerInterface> extends BaseViewManagerDelegate { + public RCTSafeAreaViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "emulateUnlessSupported": + mViewManager.setEmulateUnlessSupported(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java new file mode 100644 index 00000000000000..1018dbfa69c609 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java @@ -0,0 +1,16 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; + +public interface RCTSafeAreaViewManagerInterface { + void setEmulateUnlessSupported(T view, boolean value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java new file mode 100644 index 00000000000000..25e1adc9a172f4 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java @@ -0,0 +1,45 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class RCTSegmentedControlManagerDelegate & RCTSegmentedControlManagerInterface> extends BaseViewManagerDelegate { + public RCTSegmentedControlManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "values": + mViewManager.setValues(view, (ReadableArray) value); + break; + case "selectedIndex": + mViewManager.setSelectedIndex(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "enabled": + mViewManager.setEnabled(view, value == null ? true : (boolean) value); + break; + case "tintColor": + mViewManager.setTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "momentary": + mViewManager.setMomentary(view, value == null ? false : (boolean) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java new file mode 100644 index 00000000000000..f9e4b838f589f1 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java @@ -0,0 +1,22 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableArray; + +public interface RCTSegmentedControlManagerInterface { + void setValues(T view, @Nullable ReadableArray value); + void setSelectedIndex(T view, int value); + void setEnabled(T view, boolean value); + void setTintColor(T view, @Nullable Integer value); + void setMomentary(T view, boolean value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerDelegate.java new file mode 100644 index 00000000000000..0bfdc3ebde0b5a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerDelegate.java @@ -0,0 +1,72 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class SliderManagerDelegate & SliderManagerInterface> extends BaseViewManagerDelegate { + public SliderManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "disabled": + mViewManager.setDisabled(view, value == null ? false : (boolean) value); + break; + case "enabled": + mViewManager.setEnabled(view, value == null ? false : (boolean) value); + break; + case "maximumTrackImage": + mViewManager.setMaximumTrackImage(view, (ReadableMap) value); + break; + case "maximumTrackTintColor": + mViewManager.setMaximumTrackTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "maximumValue": + mViewManager.setMaximumValue(view, value == null ? 1f : ((Double) value).floatValue()); + break; + case "minimumTrackImage": + mViewManager.setMinimumTrackImage(view, (ReadableMap) value); + break; + case "minimumTrackTintColor": + mViewManager.setMinimumTrackTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "minimumValue": + mViewManager.setMinimumValue(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "step": + mViewManager.setStep(view, value == null ? 0f : ((Double) value).floatValue()); + break; + case "testID": + mViewManager.setTestID(view, value == null ? "" : (String) value); + break; + case "thumbImage": + mViewManager.setThumbImage(view, (ReadableMap) value); + break; + case "thumbTintColor": + mViewManager.setThumbTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "trackImage": + mViewManager.setTrackImage(view, (ReadableMap) value); + break; + case "value": + mViewManager.setValue(view, value == null ? 0f : ((Double) value).floatValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerInterface.java new file mode 100644 index 00000000000000..8779d9b34c3a83 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SliderManagerInterface.java @@ -0,0 +1,31 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.ReadableMap; + +public interface SliderManagerInterface { + void setDisabled(T view, boolean value); + void setEnabled(T view, boolean value); + void setMaximumTrackImage(T view, @Nullable ReadableMap value); + void setMaximumTrackTintColor(T view, @Nullable Integer value); + void setMaximumValue(T view, float value); + void setMinimumTrackImage(T view, @Nullable ReadableMap value); + void setMinimumTrackTintColor(T view, @Nullable Integer value); + void setMinimumValue(T view, float value); + void setStep(T view, float value); + void setTestID(T view, @Nullable String value); + void setThumbImage(T view, @Nullable ReadableMap value); + void setThumbTintColor(T view, @Nullable Integer value); + void setTrackImage(T view, @Nullable ReadableMap value); + void setValue(T view, float value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerDelegate.java new file mode 100644 index 00000000000000..6cf56c90d9632f --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerDelegate.java @@ -0,0 +1,53 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class SwitchManagerDelegate & SwitchManagerInterface> extends BaseViewManagerDelegate { + public SwitchManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "disabled": + mViewManager.setDisabled(view, value == null ? false : (boolean) value); + break; + case "value": + mViewManager.setValue(view, value == null ? false : (boolean) value); + break; + case "tintColor": + mViewManager.setTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "onTintColor": + mViewManager.setOnTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "thumbTintColor": + mViewManager.setThumbTintColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "thumbColor": + mViewManager.setThumbColor(view, value == null ? null : ((Double) value).intValue()); + break; + case "trackColorForFalse": + mViewManager.setTrackColorForFalse(view, value == null ? null : ((Double) value).intValue()); + break; + case "trackColorForTrue": + mViewManager.setTrackColorForTrue(view, value == null ? null : ((Double) value).intValue()); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerInterface.java new file mode 100644 index 00000000000000..04dce5cd1f3dcc --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SwitchManagerInterface.java @@ -0,0 +1,24 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface SwitchManagerInterface { + void setDisabled(T view, boolean value); + void setValue(T view, boolean value); + void setTintColor(T view, @Nullable Integer value); + void setOnTintColor(T view, @Nullable Integer value); + void setThumbTintColor(T view, @Nullable Integer value); + void setThumbColor(T view, @Nullable Integer value); + void setTrackColorForFalse(T view, @Nullable Integer value); + void setTrackColorForTrue(T view, @Nullable Integer value); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerDelegate.java new file mode 100644 index 00000000000000..dff2539afbfdc0 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerDelegate.java @@ -0,0 +1,32 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.uimanager.BaseViewManager; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.LayoutShadowNode; + +public class UnimplementedNativeViewManagerDelegate & UnimplementedNativeViewManagerInterface> extends BaseViewManagerDelegate { + public UnimplementedNativeViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "name": + mViewManager.setName(view, value == null ? "" : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerInterface.java new file mode 100644 index 00000000000000..c76951e2225c1a --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/UnimplementedNativeViewManagerInterface.java @@ -0,0 +1,17 @@ +/** +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; + +public interface UnimplementedNativeViewManagerInterface { + void setName(T view, @Nullable String value); +} From a939f8b31786055aba4a8284f2fc23e7f790cba3 Mon Sep 17 00:00:00 2001 From: Paul O'Shannessy Date: Thu, 29 Aug 2019 23:19:10 -0700 Subject: [PATCH 0075/1244] Adopt Contributor Covenant Summary: In order to foster healthy open source communities, we're adopting the [Contributor Covenant](https://www.contributor-covenant.org/). It has been built by open source community members and represents a shared understanding of what is expected from a healthy community. Reviewed By: josephsavona, danobi, rdzhabarov Differential Revision: D17104640 fbshipit-source-id: d210000de686c5f0d97d602b50472d5869bc6a49 --- CODE_OF_CONDUCT.md | 78 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0f7ad8bfc173ea..d1abc700d28d83 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,5 +1,77 @@ # Code of Conduct -Facebook has adopted a Code of Conduct that we expect project participants to adhere to. -Please read the [full text](https://code.fb.com/codeofconduct/) -so that you can understand what actions will and will not be tolerated. +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq + From 1c275525021f49f68f7fd1c37da936ebab5eec38 Mon Sep 17 00:00:00 2001 From: henrymoulton Date: Fri, 30 Aug 2019 04:16:54 -0700 Subject: [PATCH 0076/1244] fix: ios detox date picker test (#26111) Summary: iOS e2e tests using Detox are failing on CI: https://circleci.com/gh/facebook/react-native/107417#tests/containers/0 https://circleci.com/gh/facebook/react-native/107390 ## Changelog [INTERNAL] [FIXED] - Date Picker iOS test Pull Request resolved: https://github.com/facebook/react-native/pull/26111 Test Plan: ` yarn build-ios-e2e && yarn test-ios-e2e` Reviewed By: rubennorte Differential Revision: D17093319 Pulled By: osdnk fbshipit-source-id: fedf45aa85c1ddfe2dfdf669b5248d1393771958 --- RNTester/e2e/__tests__/DatePickerIOS-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/e2e/__tests__/DatePickerIOS-test.js b/RNTester/e2e/__tests__/DatePickerIOS-test.js index 024f237d74613b..6a7c961991aecf 100644 --- a/RNTester/e2e/__tests__/DatePickerIOS-test.js +++ b/RNTester/e2e/__tests__/DatePickerIOS-test.js @@ -43,7 +43,7 @@ describe('DatePickerIOS', () => { await testElement.setColumnToValue(2, '10'); await testElement.setColumnToValue(3, 'AM'); - await expect(dateIndicator).toHaveText('12/4/2005'); + await expect(dateIndicator).toHaveText('12/4/2006'); await expect(timeIndicator).toHaveText('4:10 AM'); }); From 36d4a969dd2e1ecf75166b24b6b0af3f7a70e71f Mon Sep 17 00:00:00 2001 From: Isaac Lem Date: Fri, 30 Aug 2019 04:56:00 -0700 Subject: [PATCH 0077/1244] Prevent usage of Array index in keys (#26102) Summary: To ensure source code conform with no-array-index-key rules: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md ## Changelog [General] [Fixed] - To avoid using index as key Pull Request resolved: https://github.com/facebook/react-native/pull/26102 Reviewed By: rubennorte Differential Revision: D17093314 Pulled By: osdnk fbshipit-source-id: 3c50f8fa0b220638e4cec1b71292f2c5c1bdc1c9 --- .../NewAppScreen/components/LearnMoreLinks.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Libraries/NewAppScreen/components/LearnMoreLinks.js b/Libraries/NewAppScreen/components/LearnMoreLinks.js index 1d63f141ebe255..d18e612729bbbd 100644 --- a/Libraries/NewAppScreen/components/LearnMoreLinks.js +++ b/Libraries/NewAppScreen/components/LearnMoreLinks.js @@ -17,44 +17,52 @@ import React from 'react'; const links = [ { + id: 1, title: 'The Basics', link: 'https://facebook.github.io/react-native/docs/tutorial', description: 'Explains a Hello World for React Native.', }, { + id: 2, title: 'Style', link: 'https://facebook.github.io/react-native/docs/style', description: 'Covers how to use the prop named style which controls the visuals.', }, { + id: 3, title: 'Layout', link: 'https://facebook.github.io/react-native/docs/flexbox', description: 'React Native uses flexbox for layout, learn how it works.', }, { + id: 4, title: 'Components', link: 'https://facebook.github.io/react-native/docs/components-and-apis', description: 'The full list of components and APIs inside React Native.', }, { + id: 5, title: 'Navigation', link: 'https://facebook.github.io/react-native/docs/navigation', description: 'How to handle moving between screens inside your application.', }, { + id: 6, title: 'Networking', link: 'https://facebook.github.io/react-native/docs/network', description: 'How to use the Fetch API in React Native.', }, { + id: 7, title: 'Help', link: 'https://facebook.github.io/react-native/help', description: 'Need more help? There are many other React Native developers who may have the answer.', }, { + id: 8, title: 'Follow us on Twitter', link: 'https://twitter.com/reactnative', description: @@ -64,16 +72,16 @@ const links = [ const LinkList = (): Node => ( - {links.map((item, index) => { + {links.map(({id, title, link, description}) => { return ( - + openURLInBrowser(item.link)} + onPress={() => openURLInBrowser(link)} style={styles.linkContainer}> - {item.title} - {item.description} + {title} + {description} ); From 82a8080f0704e83079d0429e4e367f5131052e64 Mon Sep 17 00:00:00 2001 From: Ram N Date: Fri, 30 Aug 2019 07:10:51 -0700 Subject: [PATCH 0078/1244] Change podspec name of yoga to Yoga Summary: Needed to capitalize the name, since this is the convention used elsewhere too ## Changelog: [iOS] [Changed] - Renamed yoga podspec to Yoga Reviewed By: shergin Differential Revision: D17127104 fbshipit-source-id: 14047bf452edda000037701f4ba7f4a02a0e717b --- RNTester/Podfile.lock | 44 +++++++++++++++++------------------ React-Core.podspec | 2 +- ReactCommon/yoga/yoga.podspec | 2 +- scripts/autolink-ios.rb | 2 +- template/ios/Podfile | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 7357c2f0d611c5..a8536be1a4e704 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -47,7 +47,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/ARTHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -55,7 +55,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/CoreModulesHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -63,14 +63,14 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/Default (1000.0.0): - Folly (= 2018.10.22.00) - glog - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/DevSupport (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -80,7 +80,7 @@ PODS: - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - React-jsinspector (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTActionSheetHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -88,7 +88,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTAnimationHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -96,7 +96,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTBlobHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -104,7 +104,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTImageHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -112,7 +112,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTLinkingHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -120,7 +120,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTNetworkHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -128,7 +128,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTPushNotificationHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -136,7 +136,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTSettingsHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -144,7 +144,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTTextHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -152,7 +152,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTVibrationHeaders (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -160,7 +160,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-Core/RCTWebSocket (1000.0.0): - Folly (= 2018.10.22.00) - glog @@ -168,7 +168,7 @@ PODS: - React-cxxreact (= 1000.0.0) - React-jsi (= 1000.0.0) - React-jsiexecutor (= 1000.0.0) - - yoga (= 1000.0.0.React) + - Yoga - React-CoreModules (1000.0.0): - FBReactNativeSpec (= 1000.0.0) - Folly (= 2018.10.22.00) @@ -248,7 +248,7 @@ PODS: - React-jsi (= 1000.0.0) - ReactCommon/jscallinvoker (= 1000.0.0) - ReactCommon/turbomodule/core (= 1000.0.0) - - yoga (1000.0.0.React) + - Yoga (1000.0.0.React) DEPENDENCIES: - DoubleConversion (from `../third-party-podspecs/DoubleConversion.podspec`) @@ -282,7 +282,7 @@ DEPENDENCIES: - ReactCommon/jscallinvoker (from `../ReactCommon`) - ReactCommon/turbomodule/core (from `../ReactCommon`) - ReactCommon/turbomodule/samples (from `../ReactCommon`) - - yoga (from `../ReactCommon/yoga`) + - Yoga (from `../ReactCommon/yoga`) SPEC REPOS: https://github.com/cocoapods/specs.git: @@ -343,7 +343,7 @@ EXTERNAL SOURCES: :path: "../Libraries/Vibration" ReactCommon: :path: "../ReactCommon" - yoga: + Yoga: :path: "../ReactCommon/yoga" SPEC CHECKSUMS: @@ -357,7 +357,7 @@ SPEC CHECKSUMS: RCTTypeSafety: 2b1cb2d92b779aa9a3522f67bd4f07e6b6d0797e React: 28a654b69575941571c073a656bc06795825e7f7 React-ART: a5da06a892342d03896e0db45a7072525981f63c - React-Core: 47b8ab211d9325292811e62ee23c54b464853111 + React-Core: f8656b21cfe16b1fe276686f3b921bce0fa6de4d React-CoreModules: 96b2f1e0b84493e6c1b7f3bb21357f24fdcfce2f React-cxxreact: 7c4242192149ce0205b53efaa03e3bf86ba4337c React-jsi: 98d1f9d8a79d2720ba6a44c2d928a77f315b7e4f @@ -375,8 +375,8 @@ SPEC CHECKSUMS: React-RCTText: 9078167d3bc011162326f2d8ef4dd580ec1eca17 React-RCTVibration: 63c20d89204937ff8c7bbc1e712383347e6fbd90 ReactCommon: 63d1a6355d5810a21a61efda9ac93804571a1b8b - yoga: b72aa5b3708cc93c5897f8297122d6eba1331e07 + Yoga: d2044f32d047e7f5a36b6894347569f069c0f9b7 PODFILE CHECKSUM: 060903e270072f1e192b064848e6c34528af1c87 -COCOAPODS: 1.7.1 +COCOAPODS: 1.7.2 diff --git a/React-Core.podspec b/React-Core.podspec index 77f430a032f44f..f57f6d98e7f8c8 100644 --- a/React-Core.podspec +++ b/React-Core.podspec @@ -96,6 +96,6 @@ Pod::Spec.new do |s| s.dependency "React-cxxreact", version s.dependency "React-jsi", version s.dependency "React-jsiexecutor", version - s.dependency "yoga", "#{version}.React" + s.dependency "Yoga" s.dependency "glog" end diff --git a/ReactCommon/yoga/yoga.podspec b/ReactCommon/yoga/yoga.podspec index a1e6b9cf345ad5..a27aad0d7c8ce5 100644 --- a/ReactCommon/yoga/yoga.podspec +++ b/ReactCommon/yoga/yoga.podspec @@ -15,7 +15,7 @@ else end Pod::Spec.new do |spec| - spec.name = 'yoga' + spec.name = 'Yoga' spec.version = "#{version}.React" spec.license = { :type => 'MIT' } spec.homepage = 'https://yogalayout.com' diff --git a/scripts/autolink-ios.rb b/scripts/autolink-ios.rb index 2a57c3747db16c..b776bc789675a1 100644 --- a/scripts/autolink-ios.rb +++ b/scripts/autolink-ios.rb @@ -38,7 +38,7 @@ def use_react_native! (options={}) pod 'React-jsinspector', :path => "#{prefix}/ReactCommon/jsinspector" pod 'ReactCommon/jscallinvoker', :path => "#{prefix}/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "#{prefix}/ReactCommon" - pod 'yoga', :path => "#{prefix}/ReactCommon/yoga" + pod 'Yoga', :path => "#{prefix}/ReactCommon/yoga" pod 'DoubleConversion', :podspec => "#{prefix}/third-party-podspecs/DoubleConversion.podspec" pod 'glog', :podspec => "#{prefix}/third-party-podspecs/glog.podspec" diff --git a/template/ios/Podfile b/template/ios/Podfile index fe6d533bc5f2ab..7706b8362a6a56 100644 --- a/template/ios/Podfile +++ b/template/ios/Podfile @@ -28,7 +28,7 @@ target 'HelloWorld' do pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" - pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' + pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' From a58dd9683da6135bca119a8b0ae5d0ea5382cf4c Mon Sep 17 00:00:00 2001 From: Ram N Date: Fri, 30 Aug 2019 07:10:51 -0700 Subject: [PATCH 0079/1244] Update the version of yoga podspec to match the actual version of Yoga published Summary: Yoga is currently published in cocoapods. While we don't use the Yoga from Cocoapods in React Native, we should atleast try to follow that version, so that other integrations with Yoga are possible Reviewed By: shergin Differential Revision: D17127625 fbshipit-source-id: bca2e1e33ad775e2a0d7a6f1e4177c3b480c023a --- ReactCommon/yoga/yoga.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/yoga/yoga.podspec b/ReactCommon/yoga/yoga.podspec index a27aad0d7c8ce5..20faeb476179c9 100644 --- a/ReactCommon/yoga/yoga.podspec +++ b/ReactCommon/yoga/yoga.podspec @@ -16,7 +16,7 @@ end Pod::Spec.new do |spec| spec.name = 'Yoga' - spec.version = "#{version}.React" + spec.version = '1.14.0' spec.license = { :type => 'MIT' } spec.homepage = 'https://yogalayout.com' spec.documentation_url = 'https://yogalayout.com/docs/' From b31056d802437d31c432e43bcd712b963f54116e Mon Sep 17 00:00:00 2001 From: "glevi@fb.com" Date: Fri, 30 Aug 2019 08:16:18 -0700 Subject: [PATCH 0080/1244] Deploy v0.106.3 to xplat/js Reviewed By: jbrown215 Differential Revision: D17120458 fbshipit-source-id: b1f097acffcf277b624910a3c4d7141ef5f352ad --- .flowconfig | 2 +- .flowconfig.android | 2 +- package.json | 2 +- template/_flowconfig | 2 +- yarn.lock | 8 ++++---- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.flowconfig b/.flowconfig index 62e3d599588fb6..024af087e0d5b7 100644 --- a/.flowconfig +++ b/.flowconfig @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.106.0 +^0.106.3 diff --git a/.flowconfig.android b/.flowconfig.android index 66467e11e850ba..91d1caf0d36697 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -79,4 +79,4 @@ untyped-import untyped-type-import [version] -^0.106.0 +^0.106.3 diff --git a/package.json b/package.json index c2fdec4ef2e4f4..1db9725dee86d7 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "eslint-plugin-react-hooks": "^2.0.1", "eslint-plugin-react-native": "3.6.0", "eslint-plugin-relay": "^1.3.10", - "flow-bin": "^0.106.0", + "flow-bin": "^0.106.3", "flow-remove-types": "1.2.3", "jest": "^24.8.0", "jest-junit": "^6.3.0", diff --git a/template/_flowconfig b/template/_flowconfig index 3759e18699ac5b..05b47f71220243 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -72,4 +72,4 @@ untyped-import untyped-type-import [version] -^0.106.0 +^0.106.3 diff --git a/yarn.lock b/yarn.lock index bf7ef0e3a07ddf..06219ca28e48fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3193,10 +3193,10 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" -flow-bin@^0.106.0: - version "0.106.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.106.0.tgz#55aab8c154df2bd78abfe6acfe120cf5638a0352" - integrity sha512-sV8lNBLTTfieUBNvQZFc1K1wXjC8I+O7ltv6G/nd3hdGyq2Jymyy01zAPhJ7MRw8yZ0X2dBSHFZx5DPreBqhAg== +flow-bin@^0.106.3: + version "0.106.3" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.106.3.tgz#87b5647bc23ae0efceabb6c50490c02a8478960c" + integrity sha512-QDwmhsMmiASmwgr6r2WTz9RPsN0pb84PY0whz0JqFaBX7/Fx2wj2MOtjbR2yv+qWZnozP9U40Jd9LLt8rC3WSQ== flow-parser@0.*: version "0.89.0" From 38089753efdfa5736e119ef206ed4e8ccf37f730 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Fri, 30 Aug 2019 09:39:04 -0700 Subject: [PATCH 0081/1244] Fix tests for JS codegen by renaming conflicting props Summary: ** Summary of failures encountered during the build ** Rule //fbandroid/java/com/facebook/catalyst/launcher:app_prod_debug FAILED because Command failed with exit code 1. stderr: /java/InterfaceOnlyNativeComponentViewManagerDelegate.java:18: error: reference to setAccessibilityHint is ambiguous mViewManager.setAccessibilityHint(view, value == null ? "" : (String) value); ^ both method setAccessibilityHint(T,java.lang.String) in com.facebook.react.uimanager.BaseViewManagerInterface and method setAccessibilityHint(T,java.lang.String) in com.facebook.react.viewmanagers.InterfaceOnlyNativeComponentViewManagerInterface match /java/StringPropNativeComponentViewManagerDelegate.java:18: error: reference to setAccessibilityHint is ambiguous mViewManager.setAccessibilityHint(view, value == null ? "" : (String) value); ^ both method setAccessibilityHint(T,java.lang.String) in com.facebook.react.uimanager.BaseViewManagerInterface and method setAccessibilityHint(T,java.lang.String) in com.facebook.react.viewmanagers.StringPropNativeComponentViewManagerInterface match /java/StringPropNativeComponentViewManagerDelegate.java:21: error: reference to setAccessibilityRole is ambiguous mViewManager.setAccessibilityRole(view, value == null ? null : (String) value); ^ both method setAccessibilityRole(T,java.lang.String) in com.facebook.react.uimanager.BaseViewManagerInterface and method setAccessibilityRole(T,java.lang.String) in com.facebook.react.viewmanagers.StringPropNativeComponentViewManagerInterface match Errors: 3. Warnings: 0. When running . When building rule //xplat/js/react-native-github/packages/react-native-codegen:generated_components_java-codegen_testsAndroid. ``` Reviewed By: mdvacca Differential Revision: D17107929 fbshipit-source-id: 32bc553d450628c530e22cb13f305e3a3e0f45cd --- .../java/InterfaceOnlyNativeComponentViewManager.java | 2 +- .../buck_tests/java/StringPropNativeComponentViewManager.java | 4 ++-- .../components/InterfaceOnlyNativeComponent.js | 2 +- .../__test_fixtures__/components/StringPropNativeComponent.js | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-native-codegen/buck_tests/java/InterfaceOnlyNativeComponentViewManager.java b/packages/react-native-codegen/buck_tests/java/InterfaceOnlyNativeComponentViewManager.java index afd9e9c4b23102..6a5da721165c47 100644 --- a/packages/react-native-codegen/buck_tests/java/InterfaceOnlyNativeComponentViewManager.java +++ b/packages/react-native-codegen/buck_tests/java/InterfaceOnlyNativeComponentViewManager.java @@ -26,5 +26,5 @@ public ViewGroup createViewInstance(ThemedReactContext context) { } @Override - public void setAccessibilityHint(ViewGroup view, String value) {} + public void setTitle(ViewGroup view, String value) {} } diff --git a/packages/react-native-codegen/buck_tests/java/StringPropNativeComponentViewManager.java b/packages/react-native-codegen/buck_tests/java/StringPropNativeComponentViewManager.java index 3a0ebb41a27eb3..f47d7f0f7c3b49 100644 --- a/packages/react-native-codegen/buck_tests/java/StringPropNativeComponentViewManager.java +++ b/packages/react-native-codegen/buck_tests/java/StringPropNativeComponentViewManager.java @@ -25,8 +25,8 @@ public ViewGroup createViewInstance(ThemedReactContext context) { } @Override - public void setAccessibilityHint(ViewGroup view, String value) {} + public void setPlaceholder(ViewGroup view, String value) {} @Override - public void setAccessibilityRole(ViewGroup view, String value) {} + public void setDefaultValue(ViewGroup view, String value) {} } diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/components/InterfaceOnlyNativeComponent.js b/packages/react-native-codegen/e2e/__test_fixtures__/components/InterfaceOnlyNativeComponent.js index 7d662ffd6c50cd..0e8756f2875cb4 100644 --- a/packages/react-native-codegen/e2e/__test_fixtures__/components/InterfaceOnlyNativeComponent.js +++ b/packages/react-native-codegen/e2e/__test_fixtures__/components/InterfaceOnlyNativeComponent.js @@ -22,7 +22,7 @@ type NativeProps = $ReadOnly<{| ...ViewProps, // Props - accessibilityHint?: WithDefault, + title?: WithDefault, // Events onChange?: ?BubblingEventHandler<$ReadOnly<{|value: boolean|}>>, diff --git a/packages/react-native-codegen/e2e/__test_fixtures__/components/StringPropNativeComponent.js b/packages/react-native-codegen/e2e/__test_fixtures__/components/StringPropNativeComponent.js index b23d385a9486a3..24710cbb2eed31 100644 --- a/packages/react-native-codegen/e2e/__test_fixtures__/components/StringPropNativeComponent.js +++ b/packages/react-native-codegen/e2e/__test_fixtures__/components/StringPropNativeComponent.js @@ -19,8 +19,8 @@ type NativeProps = $ReadOnly<{| ...ViewProps, // Props - accessibilityHint?: WithDefault, - accessibilityRole?: string, + placeholder?: WithDefault, + defaultValue?: string, |}>; export default (codegenNativeComponent( From 26a8d2e03ab4bba2dbdaae8d49397743c6a72859 Mon Sep 17 00:00:00 2001 From: Oleksandr Melnykov Date: Fri, 30 Aug 2019 10:01:31 -0700 Subject: [PATCH 0082/1244] Remove RCT prefix from names of generated Java classes Summary: This diff removes the 'RCT' prefix (if it's present) from the names of the generated Java classes. The motivation is that we don't want to have any Java files having this prefix in the RN Android codebase. Reviewed By: JoshuaGross Differential Revision: D17123804 fbshipit-source-id: 31905d3141e0f58ea47cdbdb0cf77d2d105de9a9 --- ...te.java => InputAccessoryViewManagerDelegate.java} | 4 ++-- ...e.java => InputAccessoryViewManagerInterface.java} | 2 +- ...erDelegate.java => MaskedViewManagerDelegate.java} | 4 ++-- ...Interface.java => MaskedViewManagerInterface.java} | 2 +- ...Delegate.java => ProgressViewManagerDelegate.java} | 4 ++-- ...terface.java => ProgressViewManagerInterface.java} | 2 +- ...Delegate.java => SafeAreaViewManagerDelegate.java} | 4 ++-- ...terface.java => SafeAreaViewManagerInterface.java} | 2 +- ...gate.java => SegmentedControlManagerDelegate.java} | 4 ++-- ...ace.java => SegmentedControlManagerInterface.java} | 2 +- .../components/GeneratePropsJavaDelegate.js | 11 ++++++++--- .../components/GeneratePropsJavaInterface.js | 8 ++++++-- .../src/generators/components/JavaHelpers.js | 10 ++++++++++ 13 files changed, 39 insertions(+), 20 deletions(-) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTInputAccessoryViewManagerDelegate.java => InputAccessoryViewManagerDelegate.java} (76%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTInputAccessoryViewManagerInterface.java => InputAccessoryViewManagerInterface.java} (85%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTMaskedViewManagerDelegate.java => MaskedViewManagerDelegate.java} (73%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTMaskedViewManagerInterface.java => MaskedViewManagerInterface.java} (83%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTProgressViewManagerDelegate.java => ProgressViewManagerDelegate.java} (85%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTProgressViewManagerInterface.java => ProgressViewManagerInterface.java} (91%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTSafeAreaViewManagerDelegate.java => SafeAreaViewManagerDelegate.java} (77%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTSafeAreaViewManagerInterface.java => SafeAreaViewManagerInterface.java} (84%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTSegmentedControlManagerDelegate.java => SegmentedControlManagerDelegate.java} (84%) rename ReactAndroid/src/main/java/com/facebook/react/viewmanagers/{RCTSegmentedControlManagerInterface.java => SegmentedControlManagerInterface.java} (90%) diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerDelegate.java similarity index 76% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerDelegate.java index 38f9f246eff556..93484383eca7e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerDelegate.java @@ -15,8 +15,8 @@ import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; -public class RCTInputAccessoryViewManagerDelegate & RCTInputAccessoryViewManagerInterface> extends BaseViewManagerDelegate { - public RCTInputAccessoryViewManagerDelegate(U viewManager) { +public class InputAccessoryViewManagerDelegate & InputAccessoryViewManagerInterface> extends BaseViewManagerDelegate { + public InputAccessoryViewManagerDelegate(U viewManager) { super(viewManager); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerInterface.java similarity index 85% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerInterface.java index 07d5f39534c2b4..2fa4a4d14a33e0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTInputAccessoryViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/InputAccessoryViewManagerInterface.java @@ -12,6 +12,6 @@ import android.view.View; import androidx.annotation.Nullable; -public interface RCTInputAccessoryViewManagerInterface { +public interface InputAccessoryViewManagerInterface { void setBackgroundColor(T view, @Nullable Integer value); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerDelegate.java similarity index 73% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerDelegate.java index 9fb175d5af6279..1b849a5bbdf8c0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerDelegate.java @@ -15,8 +15,8 @@ import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; -public class RCTMaskedViewManagerDelegate & RCTMaskedViewManagerInterface> extends BaseViewManagerDelegate { - public RCTMaskedViewManagerDelegate(U viewManager) { +public class MaskedViewManagerDelegate & MaskedViewManagerInterface> extends BaseViewManagerDelegate { + public MaskedViewManagerDelegate(U viewManager) { super(viewManager); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerInterface.java similarity index 83% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerInterface.java index 44e8febd19e1b4..0b930ee79c1be0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTMaskedViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/MaskedViewManagerInterface.java @@ -11,6 +11,6 @@ import android.view.View; -public interface RCTMaskedViewManagerInterface { +public interface MaskedViewManagerInterface { // No props } diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerDelegate.java similarity index 85% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerDelegate.java index f466c2d01a05f5..4e8b33449e0af4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerDelegate.java @@ -16,8 +16,8 @@ import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; -public class RCTProgressViewManagerDelegate & RCTProgressViewManagerInterface> extends BaseViewManagerDelegate { - public RCTProgressViewManagerDelegate(U viewManager) { +public class ProgressViewManagerDelegate & ProgressViewManagerInterface> extends BaseViewManagerDelegate { + public ProgressViewManagerDelegate(U viewManager) { super(viewManager); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerInterface.java similarity index 91% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerInterface.java index 250047e92d1c88..bbfbdf4e31bb02 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTProgressViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/ProgressViewManagerInterface.java @@ -13,7 +13,7 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableMap; -public interface RCTProgressViewManagerInterface { +public interface ProgressViewManagerInterface { void setProgressViewStyle(T view, @Nullable String value); void setProgress(T view, float value); void setProgressTintColor(T view, @Nullable Integer value); diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerDelegate.java similarity index 77% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerDelegate.java index c30912e1a297cd..91b24353e170f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerDelegate.java @@ -15,8 +15,8 @@ import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; -public class RCTSafeAreaViewManagerDelegate & RCTSafeAreaViewManagerInterface> extends BaseViewManagerDelegate { - public RCTSafeAreaViewManagerDelegate(U viewManager) { +public class SafeAreaViewManagerDelegate & SafeAreaViewManagerInterface> extends BaseViewManagerDelegate { + public SafeAreaViewManagerDelegate(U viewManager) { super(viewManager); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerInterface.java similarity index 84% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerInterface.java index 1018dbfa69c609..073e2c01c76826 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSafeAreaViewManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SafeAreaViewManagerInterface.java @@ -11,6 +11,6 @@ import android.view.View; -public interface RCTSafeAreaViewManagerInterface { +public interface SafeAreaViewManagerInterface { void setEmulateUnlessSupported(T view, boolean value); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerDelegate.java similarity index 84% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerDelegate.java index 25e1adc9a172f4..2618c63e218e3c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerDelegate.java @@ -16,8 +16,8 @@ import com.facebook.react.uimanager.BaseViewManagerDelegate; import com.facebook.react.uimanager.LayoutShadowNode; -public class RCTSegmentedControlManagerDelegate & RCTSegmentedControlManagerInterface> extends BaseViewManagerDelegate { - public RCTSegmentedControlManagerDelegate(U viewManager) { +public class SegmentedControlManagerDelegate & SegmentedControlManagerInterface> extends BaseViewManagerDelegate { + public SegmentedControlManagerDelegate(U viewManager) { super(viewManager); } @Override diff --git a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerInterface.java similarity index 90% rename from ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java rename to ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerInterface.java index f9e4b838f589f1..e6c50357616b50 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/RCTSegmentedControlManagerInterface.java +++ b/ReactAndroid/src/main/java/com/facebook/react/viewmanagers/SegmentedControlManagerInterface.java @@ -13,7 +13,7 @@ import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableArray; -public interface RCTSegmentedControlManagerInterface { +public interface SegmentedControlManagerInterface { void setValues(T view, @Nullable ReadableArray value); void setSelectedIndex(T view, int value); void setEnabled(T view, boolean value); diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js index f20296116398cd..6a11f144354f74 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaDelegate.js @@ -16,7 +16,12 @@ import type { PropTypeShape, SchemaType, } from '../../CodegenSchema'; -const {getImports, toSafeJavaString} = require('./JavaHelpers'); +const { + getImports, + toSafeJavaString, + getInterfaceJavaClassName, + getDelegateJavaClassName, +} = require('./JavaHelpers'); // File path -> contents type FilesOutput = Map; @@ -254,8 +259,8 @@ module.exports = { return Object.keys(components).forEach(componentName => { const component = components[componentName]; - const className = `${componentName}ManagerDelegate`; - const interfaceClassName = `${componentName}ManagerInterface`; + const className = getDelegateJavaClassName(componentName); + const interfaceClassName = getInterfaceJavaClassName(componentName); const fileName = `${className}.java`; const imports = getDelegateImports(component); diff --git a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js index d8e63634a16aa5..7aa9ad6e0959c5 100644 --- a/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js +++ b/packages/react-native-codegen/src/generators/components/GeneratePropsJavaInterface.js @@ -16,7 +16,11 @@ import type { PropTypeShape, SchemaType, } from '../../CodegenSchema'; -const {getImports, toSafeJavaString} = require('./JavaHelpers'); +const { + getImports, + toSafeJavaString, + getInterfaceJavaClassName, +} = require('./JavaHelpers'); // File path -> contents type FilesOutput = Map; @@ -190,7 +194,7 @@ module.exports = { return Object.keys(components).forEach(componentName => { const component = components[componentName]; - const className = `${componentName}ManagerInterface`; + const className = getInterfaceJavaClassName(componentName); const fileName = `${className}.java`; const imports = getImports(component); diff --git a/packages/react-native-codegen/src/generators/components/JavaHelpers.js b/packages/react-native-codegen/src/generators/components/JavaHelpers.js index 04f89398b37bbd..aca8d2d96816db 100644 --- a/packages/react-native-codegen/src/generators/components/JavaHelpers.js +++ b/packages/react-native-codegen/src/generators/components/JavaHelpers.js @@ -16,6 +16,14 @@ function upperCaseFirst(inString: string): string { return inString[0].toUpperCase() + inString.slice(1); } +function getInterfaceJavaClassName(componentName: string): string { + return `${componentName.replace(/^RCT/, '')}ManagerInterface`; +} + +function getDelegateJavaClassName(componentName: string): string { + return `${componentName.replace(/^RCT/, '')}ManagerDelegate`; +} + function toSafeJavaString( input: string, shouldUpperCaseFirst?: boolean, @@ -87,6 +95,8 @@ function getImports(component: ComponentShape): Set { } module.exports = { + getInterfaceJavaClassName, + getDelegateJavaClassName, toSafeJavaString, getImports, }; From 63fa3f21c5ab308def450bffb22054241a8842ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Fri, 30 Aug 2019 17:06:03 -0700 Subject: [PATCH 0083/1244] Add Appearance native module Summary: Implements the Appearance native module as discussed in https://github.com/react-native-community/discussions-and-proposals/issues/126. The purpose of the Appearance native module is to expose the user's appearance preferences. It provides a basic get() API that returns the user's preferred color scheme on iOS 13 devices, also known as Dark Mode. It also provides the ability to subscribe to events whenever an appearance preference changes. The name, "Appearance", was chosen purposefully to allow for future expansion to cover other appearance preferences such as reduced motion, reduced transparency, or high contrast modes. Changelog: [iOS] [Added] - The Appearance native module can be used to prepare your app for Dark Mode on iOS 13. Reviewed By: yungsters Differential Revision: D16699954 fbshipit-source-id: 03b4cc5d2a1a69f31f3a6d9bece23f6867b774ea --- .../FBReactNativeSpec-generated.mm | 64 +++++++++++ .../FBReactNativeSpec/FBReactNativeSpec.h | 48 ++++++++ Libraries/Utilities/Appearance.js | 79 +++++++++++++ Libraries/Utilities/NativeAppearance.js | 36 ++++++ .../react-native-implementation.js | 4 + RNTester/Podfile.lock | 6 +- React/Base/RCTRootView.m | 19 +++- React/CoreModules/BUCK | 4 + React/CoreModules/CoreModulesPlugins.h | 1 + React/CoreModules/CoreModulesPlugins.mm | 1 + React/CoreModules/RCTAppearance.h | 16 +++ React/CoreModules/RCTAppearance.mm | 107 ++++++++++++++++++ 12 files changed, 381 insertions(+), 4 deletions(-) create mode 100644 Libraries/Utilities/Appearance.js create mode 100644 Libraries/Utilities/NativeAppearance.js create mode 100644 React/CoreModules/RCTAppearance.h create mode 100644 React/CoreModules/RCTAppearance.mm diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm index 5ec9e809029750..2104b1dbfeff02 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm @@ -12,6 +12,7 @@ */ #import "FBReactNativeSpec.h" +#import namespace facebook { @@ -452,6 +453,69 @@ + (RCTManagedPointer *)JS_NativeAppState_SpecGetCurrentAppStateSuccessAppState:( } // namespace react } // namespace facebook +namespace facebook { + namespace react { + + + static facebook::jsi::Value __hostFunction_NativeAppearanceSpecJSI_getColorScheme(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, StringKind, "getColorScheme", @selector(getColorScheme), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeAppearanceSpecJSI_addListener(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "addListener", @selector(addListener:), args, count); + } + + static facebook::jsi::Value __hostFunction_NativeAppearanceSpecJSI_removeListeners(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) { + return static_cast(turboModule).invokeObjCMethod(rt, VoidKind, "removeListeners", @selector(removeListeners:), args, count); + } + + + NativeAppearanceSpecJSI::NativeAppearanceSpecJSI(id instance, std::shared_ptr jsInvoker) + : ObjCTurboModule("Appearance", instance, jsInvoker) { + + methodMap_["getColorScheme"] = MethodMetadata {0, __hostFunction_NativeAppearanceSpecJSI_getColorScheme}; + + + methodMap_["addListener"] = MethodMetadata {1, __hostFunction_NativeAppearanceSpecJSI_addListener}; + + + methodMap_["removeListeners"] = MethodMetadata {1, __hostFunction_NativeAppearanceSpecJSI_removeListeners}; + + + + } + + } // namespace react +} // namespace facebook +folly::Optional NSStringToNativeAppearanceColorSchemeName(NSString *value) { + static NSDictionary *dict = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dict = @{ + @"light": @0, + @"dark": @1, + }; + }); + return value ? (NativeAppearanceColorSchemeName)[dict[value] integerValue] : folly::Optional{}; +} + +NSString *NativeAppearanceColorSchemeNameToNSString(folly::Optional value) { + static NSDictionary *dict = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dict = @{ + @0: @"light", + @1: @"dark", + }; + }); + return value.hasValue() ? dict[@(value.value())] : nil; +} +@implementation RCTCxxConvert (NativeAppearance_AppearancePreferences) ++ (RCTManagedPointer *)JS_NativeAppearance_AppearancePreferences:(id)json +{ + return facebook::react::managedPointer(json); +} +@end @implementation RCTCxxConvert (NativeAsyncStorage_SpecMultiGetCallbackErrorsElement) + (RCTManagedPointer *)JS_NativeAsyncStorage_SpecMultiGetCallbackErrorsElement:(id)json { diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index c0d786e86dbfef..a5561e3bcce80d 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -432,6 +432,49 @@ namespace facebook { }; } // namespace react } // namespace facebook +@protocol NativeAppearanceSpec + +- (NSString *)getColorScheme; +- (void)addListener:(NSString *)eventName; +- (void)removeListeners:(double)count; + +@end +namespace facebook { + namespace react { + /** + * ObjC++ class for module 'Appearance' + */ + + class JSI_EXPORT NativeAppearanceSpecJSI : public ObjCTurboModule { + public: + NativeAppearanceSpecJSI(id instance, std::shared_ptr jsInvoker); + + }; + } // namespace react +} // namespace facebook +typedef NS_ENUM(NSInteger, NativeAppearanceColorSchemeName) { + NativeAppearanceColorSchemeNameLight = 0, + NativeAppearanceColorSchemeNameDark, +}; + +folly::Optional NSStringToNativeAppearanceColorSchemeName(NSString *value); +NSString *NativeAppearanceColorSchemeNameToNSString(folly::Optional value); + +namespace JS { + namespace NativeAppearance { + struct AppearancePreferences { + NSString *colorScheme() const; + + AppearancePreferences(NSDictionary *const v) : _v(v) {} + private: + NSDictionary *_v; + }; + } +} + +@interface RCTCxxConvert (NativeAppearance_AppearancePreferences) ++ (RCTManagedPointer *)JS_NativeAppearance_AppearancePreferences:(id)json; +@end namespace JS { namespace NativeAsyncStorage { @@ -2553,6 +2596,11 @@ inline JS::NativeAppState::Constants::Builder::Builder(const Input i) : _factory inline JS::NativeAppState::Constants::Builder::Builder(Constants i) : _factory(^{ return i.unsafeRawValue(); }) {} +inline NSString *JS::NativeAppearance::AppearancePreferences::colorScheme() const +{ + id const p = _v[@"colorScheme"]; + return RCTBridgingToString(p); +} inline NSString *JS::NativeAsyncStorage::SpecMultiGetCallbackErrorsElement::message() const { id const p = _v[@"message"]; diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js new file mode 100644 index 00000000000000..60bd0c92d9b319 --- /dev/null +++ b/Libraries/Utilities/Appearance.js @@ -0,0 +1,79 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; + +import EventEmitter from '../vendor/emitter/EventEmitter'; +import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; +import NativeAppearance, { + type AppearancePreferences, + type ColorSchemeName, +} from './NativeAppearance'; +import invariant from 'invariant'; + +type AppearanceListener = (preferences: AppearancePreferences) => void; +const eventEmitter = new EventEmitter(); + +const nativeColorScheme: ?string = + NativeAppearance == null ? null : NativeAppearance.getColorScheme(); +invariant( + nativeColorScheme === 'dark' || + nativeColorScheme === 'light' || + nativeColorScheme == null, + "Unrecognized color scheme. Did you mean 'dark' or 'light'?", +); + +let currentColorScheme: ?ColorSchemeName = nativeColorScheme; + +if (NativeAppearance) { + const nativeEventEmitter = new NativeEventEmitter(NativeAppearance); + nativeEventEmitter.addListener( + 'appearanceChanged', + (newAppearance: AppearancePreferences) => { + const {colorScheme} = newAppearance; + invariant( + colorScheme === 'dark' || + colorScheme === 'light' || + colorScheme == null, + "Unrecognized color scheme. Did you mean 'dark' or 'light'?", + ); + currentColorScheme = colorScheme; + eventEmitter.emit('change', {colorScheme}); + }, + ); +} + +module.exports = { + /** + * Note: Although color scheme is available immediately, it may change at any + * time. Any rendering logic or styles that depend on this should try to call + * this function on every render, rather than caching the value (for example, + * using inline styles rather than setting a value in a `StyleSheet`). + * + * Example: `const colorScheme = Appearance.getColorScheme();` + * + * @returns {?ColorSchemeName} Value for the color scheme preference. + */ + getColorScheme(): ?ColorSchemeName { + return currentColorScheme; + }, + /** + * Add an event handler that is fired when appearance preferences change. + */ + addChangeListener(listener: AppearanceListener): void { + eventEmitter.addListener('change', listener); + }, + /** + * Remove an event handler. + */ + removeChangeListener(listener: AppearanceListener): void { + eventEmitter.removeListener('change', listener); + }, +}; diff --git a/Libraries/Utilities/NativeAppearance.js b/Libraries/Utilities/NativeAppearance.js new file mode 100644 index 00000000000000..5d37b8aded32a9 --- /dev/null +++ b/Libraries/Utilities/NativeAppearance.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from '../TurboModule/RCTExport'; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export type ColorSchemeName = 'light' | 'dark'; + +export type AppearancePreferences = {| + // TODO: (hramos) T52919652 Use ?ColorSchemeName once codegen supports union + // types. + /* 'light' | 'dark' */ + colorScheme?: ?string, +|}; + +export interface Spec extends TurboModule { + // TODO: (hramos) T52919652 Use ?ColorSchemeName once codegen supports union + // types. + /* 'light' | 'dark' */ + +getColorScheme: () => ?string; + + // RCTEventEmitter + +addListener: (eventName: string) => void; + +removeListeners: (count: number) => void; +} + +export default (TurboModuleRegistry.get('Appearance'): ?Spec); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index 4b186729337dd0..56a8232080d244 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -49,6 +49,7 @@ import typeof VirtualizedSectionList from '../Lists/VirtualizedSectionList'; import typeof ActionSheetIOS from '../ActionSheetIOS/ActionSheetIOS'; import typeof Alert from '../Alert/Alert'; import typeof Animated from '../Animated/src/Animated'; +import typeof Appearance from '../Utilities/Appearance'; import typeof AppRegistry from '../ReactNative/AppRegistry'; import typeof AppState from '../AppState/AppState'; import typeof AsyncStorage from '../Storage/AsyncStorage'; @@ -252,6 +253,9 @@ module.exports = { get Animated(): Animated { return require('../Animated/src/Animated'); }, + get Appearance(): Appearance { + return require('../Utilities/Appearance'); + }, get AppRegistry(): AppRegistry { return require('../ReactNative/AppRegistry'); }, diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index a8536be1a4e704..83b13126ff9b8c 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -248,7 +248,7 @@ PODS: - React-jsi (= 1000.0.0) - ReactCommon/jscallinvoker (= 1000.0.0) - ReactCommon/turbomodule/core (= 1000.0.0) - - Yoga (1000.0.0.React) + - Yoga (1.14.0) DEPENDENCIES: - DoubleConversion (from `../third-party-podspecs/DoubleConversion.podspec`) @@ -375,8 +375,8 @@ SPEC CHECKSUMS: React-RCTText: 9078167d3bc011162326f2d8ef4dd580ec1eca17 React-RCTVibration: 63c20d89204937ff8c7bbc1e712383347e6fbd90 ReactCommon: 63d1a6355d5810a21a61efda9ac93804571a1b8b - Yoga: d2044f32d047e7f5a36b6894347569f069c0f9b7 + Yoga: 0abc4039ca4c0de783ab88c0ee21273583cbc2af PODFILE CHECKSUM: 060903e270072f1e192b064848e6c34528af1c87 -COCOAPODS: 1.7.2 +COCOAPODS: 1.7.1 diff --git a/React/Base/RCTRootView.m b/React/Base/RCTRootView.m index f806a4974dc45c..4dd34e6f457704 100644 --- a/React/Base/RCTRootView.m +++ b/React/Base/RCTRootView.m @@ -33,6 +33,7 @@ #endif NSString *const RCTContentDidAppearNotification = @"RCTContentDidAppearNotification"; +NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification"; @interface RCTUIManager (RCTRootView) @@ -347,7 +348,7 @@ - (void)setIntrinsicContentSize:(CGSize)intrinsicContentSize if (bothSizesHaveAZeroDimension || sizesAreEqual) { return; } - + [self invalidateIntrinsicContentSize]; [self.superview setNeedsLayout]; @@ -366,6 +367,22 @@ - (void)contentViewInvalidated [self showLoadingView]; } +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \ + __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection +{ + [super traitCollectionDidChange:previousTraitCollection]; + + if (@available(iOS 13.0, *)) { + if ([previousTraitCollection hasDifferentColorAppearanceComparedToTraitCollection:self.traitCollection]) { + [[NSNotificationCenter defaultCenter] postNotificationName:RCTUserInterfaceStyleDidChangeNotification + object:self + userInfo:@{@"traitCollection": self.traitCollection}]; + } + } +} +#endif + - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/React/CoreModules/BUCK b/React/CoreModules/BUCK index cc18821485d42f..35f0ee65eca024 100644 --- a/React/CoreModules/BUCK +++ b/React/CoreModules/BUCK @@ -41,6 +41,10 @@ rn_apple_library( name = "AccessibilityManager", native_class_func = "RCTAccessibilityManagerCls", ) + + react_module_plugin_providers( + name = "Appearance", + native_class_func = "RCTAppearanceCls", + ) + react_module_plugin_providers( name = "DeviceInfo", native_class_func = "RCTDeviceInfoCls", diff --git a/React/CoreModules/CoreModulesPlugins.h b/React/CoreModules/CoreModulesPlugins.h index 849ba766f5f5b0..30aeb8ce5db217 100644 --- a/React/CoreModules/CoreModulesPlugins.h +++ b/React/CoreModules/CoreModulesPlugins.h @@ -30,6 +30,7 @@ Class RCTCoreModulesClassProvider(const char *name); // Lookup functions Class RCTAccessibilityManagerCls(void); +Class RCTAppearanceCls(void); Class RCTDeviceInfoCls(void); Class RCTExceptionsManagerCls(void); Class RCTImageLoaderCls(void); diff --git a/React/CoreModules/CoreModulesPlugins.mm b/React/CoreModules/CoreModulesPlugins.mm index 6b14b5f0dbb923..b72ebf0afa1eec 100644 --- a/React/CoreModules/CoreModulesPlugins.mm +++ b/React/CoreModules/CoreModulesPlugins.mm @@ -18,6 +18,7 @@ static std::unordered_map sCoreModuleClassMap = { {"AccessibilityManager", RCTAccessibilityManagerCls}, +{"Appearance", RCTAppearanceCls}, {"DeviceInfo", RCTDeviceInfoCls}, {"ExceptionsManager", RCTExceptionsManagerCls}, {"ImageLoader", RCTImageLoaderCls}, diff --git a/React/CoreModules/RCTAppearance.h b/React/CoreModules/RCTAppearance.h new file mode 100644 index 00000000000000..689ef7e113ead9 --- /dev/null +++ b/React/CoreModules/RCTAppearance.h @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +#import +#import + +NSString *const RCTUserInterfaceStyleDidChangeNotification = @"RCTUserInterfaceStyleDidChangeNotification"; + +@interface RCTAppearance : RCTEventEmitter +@end diff --git a/React/CoreModules/RCTAppearance.mm b/React/CoreModules/RCTAppearance.mm new file mode 100644 index 00000000000000..0b9f1d067f4791 --- /dev/null +++ b/React/CoreModules/RCTAppearance.mm @@ -0,0 +1,107 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTAppearance.h" + +#import +#import + +#import "CoreModulesPlugins.h" + +using namespace facebook::react; + +NSString *const RCTAppearanceColorSchemeLight = @"light"; +NSString *const RCTAppearanceColorSchemeDark = @"dark"; + +static NSString *RCTColorSchemePreference(UITraitCollection *traitCollection) +{ +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 + if (@available(iOS 13.0, *)) { + static NSDictionary *appearances; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + appearances = @{ + @(UIUserInterfaceStyleLight): RCTAppearanceColorSchemeLight, + @(UIUserInterfaceStyleDark): RCTAppearanceColorSchemeDark + }; + }); + + traitCollection = traitCollection ?: [UITraitCollection currentTraitCollection]; + return appearances[@(traitCollection.userInterfaceStyle)] ?: nil; + } +#endif + + return nil; +} + +@interface RCTAppearance () +@end + +@implementation RCTAppearance + +RCT_EXPORT_MODULE(Appearance) + ++ (BOOL)requiresMainQueueSetup +{ + return YES; +} + +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} + +- (std::shared_ptr)getTurboModuleWithJsInvoker:(std::shared_ptr)jsInvoker +{ + return std::make_shared(self, jsInvoker); +} + +RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme) +{ + return RCTColorSchemePreference(nil); +} + +- (void)appearanceChanged:(NSNotification *)notification +{ + NSDictionary *userInfo = [notification userInfo]; + UITraitCollection *traitCollection = nil; + if (userInfo) { + traitCollection = userInfo[@"traitCollection"]; + } + [self sendEventWithName:@"appearanceChanged" body:@{@"colorScheme": RCTColorSchemePreference(traitCollection)}]; +} + +#pragma mark - RCTEventEmitter + +- (NSArray *)supportedEvents +{ + return @[@"appearanceChanged"]; +} + +- (void)startObserving +{ + if (@available(iOS 13.0, *)) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appearanceChanged:) + name:RCTUserInterfaceStyleDidChangeNotification + object:nil]; + } +} + +- (void)stopObserving +{ + if (@available(iOS 13.0, *)) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + } +} + +@end + +Class RCTAppearanceCls(void) { + return RCTAppearance.class; +} From 951785de8a6a7df1b782701f8c480ae5ba691e38 Mon Sep 17 00:00:00 2001 From: Kevin Gozali Date: Fri, 30 Aug 2019 17:12:48 -0700 Subject: [PATCH 0084/1244] Architecture indicator: hide the overlay when Fabric/TM are both disabled Summary: Instead of showing a thin gray line, don't render anything if no new architecture project is active. Reviewed By: ejanzer Differential Revision: D17142557 fbshipit-source-id: 644a8e515c04f84336d80bea00d641c2bfa3be41 --- Libraries/ReactNative/ReactNativeArchitectureIndicator.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Libraries/ReactNative/ReactNativeArchitectureIndicator.js b/Libraries/ReactNative/ReactNativeArchitectureIndicator.js index 9cc4bc6e2bd5e2..7fc2f3aec29027 100644 --- a/Libraries/ReactNative/ReactNativeArchitectureIndicator.js +++ b/Libraries/ReactNative/ReactNativeArchitectureIndicator.js @@ -32,6 +32,11 @@ function ReactNativeArchitectureIndicator(props: {| parts.push('TM'); } } + + if (parts.length === 0) { + return null; + } + return ( {parts.join('+')} From f107d3b78c95ed0313b39e55976cf6b6be36775e Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 30 Aug 2019 18:08:28 -0700 Subject: [PATCH 0085/1244] Fix Redbox on iOS Summary: Looks like we broke iOS redbox in D16812212. It stopped showing up because the feature detection stopped working, and we started calling noops. The fix is an explicit platform check. Fixes #26260 Reviewed By: motiz88 Differential Revision: D17139310 fbshipit-source-id: 829eec23cbb49151ac250889c34ab28d36b05e6a --- Libraries/Core/NativeExceptionsManager.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Libraries/Core/NativeExceptionsManager.js b/Libraries/Core/NativeExceptionsManager.js index f75c91999f650b..cbbc151e9f4d96 100644 --- a/Libraries/Core/NativeExceptionsManager.js +++ b/Libraries/Core/NativeExceptionsManager.js @@ -46,16 +46,19 @@ export interface Spec extends TurboModule { stack: Array, exceptionId: number, ) => void; + // TODO(T53311281): This is a noop on iOS now. Implement it. +reportException?: (data: ExceptionData) => void; +updateExceptionMessage: ( message: string, stack: Array, exceptionId: number, ) => void; - // Android only + // TODO(T53311281): This is a noop on iOS now. Implement it. +dismissRedbox?: () => void; } +const Platform = require('../Utilities/Platform'); + const NativeModule = TurboModuleRegistry.getEnforcing( 'ExceptionsManager', ); @@ -83,12 +86,14 @@ const ExceptionsManager = { NativeModule.updateExceptionMessage(message, stack, exceptionId); }, dismissRedbox(): void { - if (NativeModule.dismissRedbox) { + if (Platform.OS !== 'ios' && NativeModule.dismissRedbox) { + // TODO(T53311281): This is a noop on iOS now. Implement it. NativeModule.dismissRedbox(); } }, reportException(data: ExceptionData): void { - if (NativeModule.reportException) { + if (Platform.OS !== 'ios' && NativeModule.reportException) { + // TODO(T53311281): This is a noop on iOS now. Implement it. NativeModule.reportException(data); return; } From 42a385bddf895be5b00dd30f82396f0d8197cfc1 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 30 Aug 2019 18:08:28 -0700 Subject: [PATCH 0086/1244] Partial RN sync Summary: This cherry-picks one commit: https://github.com/facebook/react/commit/01fb68b9bf680ab8bbf96e86501e0fc540b3cc97 It fixes a bug in Fast Refresh. Reviewed By: threepointone Differential Revision: D17140543 fbshipit-source-id: a7654152d1cc7c27e7c4024380349b44ac496b22 --- Libraries/Renderer/implementations/ReactFabric-dev.fb.js | 5 +++++ Libraries/Renderer/implementations/ReactFabric-dev.js | 5 +++++ .../Renderer/implementations/ReactNativeRenderer-dev.fb.js | 5 +++++ .../Renderer/implementations/ReactNativeRenderer-dev.js | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js index 68b992fd50d5ea..45ceec34b6a481 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.fb.js @@ -11122,6 +11122,11 @@ function renderWithHooks( do { didScheduleRenderPhaseUpdate = false; numberOfReRenders += 1; + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list nextCurrentHook = current !== null ? current.memoizedState : null; diff --git a/Libraries/Renderer/implementations/ReactFabric-dev.js b/Libraries/Renderer/implementations/ReactFabric-dev.js index ad2a1b865b9341..2b189740eebd84 100644 --- a/Libraries/Renderer/implementations/ReactFabric-dev.js +++ b/Libraries/Renderer/implementations/ReactFabric-dev.js @@ -11118,6 +11118,11 @@ function renderWithHooks( do { didScheduleRenderPhaseUpdate = false; numberOfReRenders += 1; + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list nextCurrentHook = current !== null ? current.memoizedState : null; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js index 4d155951884124..a9f3f89e72f218 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.fb.js @@ -10699,6 +10699,11 @@ function renderWithHooks( do { didScheduleRenderPhaseUpdate = false; numberOfReRenders += 1; + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list nextCurrentHook = current !== null ? current.memoizedState : null; diff --git a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js index b38efdcb4ed9f4..c21f80dc4e58ba 100644 --- a/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js @@ -10695,6 +10695,11 @@ function renderWithHooks( do { didScheduleRenderPhaseUpdate = false; numberOfReRenders += 1; + { + // Even when hot reloading, allow dependencies to stabilize + // after first render to prevent infinite render phase updates. + ignorePreviousDependencies = false; + } // Start over from the beginning of the list nextCurrentHook = current !== null ? current.memoizedState : null; From 6a10feacda3c37fc30f6008d3f4833471435d766 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0087/1244] Fabric: Passing EventDispatcher as a weak pointer everywhere Summary: Storing a strong shared pointer to `ComponentDescriptor` can cause a memory leak. Therefore we enforce all call sides and params to be weak pointers. The only Scheduler preserves a retaining pointer to it (to prevent preliminary deallocation). Reviewed By: sammy-SC Differential Revision: D17115540 fbshipit-source-id: fdea7d19f742ff04d5ba5470dd9748a5b226aa7c --- React/Fabric/RCTSurfacePresenter.mm | 2 +- .../image/ImageComponentDescriptor.h | 2 +- .../modal/ModalHostViewComponentDescriptor.h | 2 +- .../slider/SliderComponentDescriptor.h | 2 +- .../paragraph/ParagraphComponentDescriptor.h | 2 +- .../ComponentDescriptor.cpp | 2 +- .../componentdescriptor/ComponentDescriptor.h | 4 ++-- .../ConcreteComponentDescriptor.h | 2 +- .../core/tests/ComponentDescriptorTest.cpp | 9 ++++++--- .../fabric/core/tests/ShadowNodeTest.cpp | 18 ++++++++++++------ .../uimanager/ComponentDescriptorFactory.h | 2 +- .../uimanager/ComponentDescriptorProvider.h | 6 +++--- ReactCommon/fabric/uimanager/Scheduler.cpp | 2 ++ ReactCommon/fabric/uimanager/Scheduler.h | 1 + .../tests/UITemplateProcessorTest.cpp | 8 +++++--- 15 files changed, 39 insertions(+), 25 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index 44a99619ee3e37..c3a1823b53d9f3 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -195,7 +195,7 @@ - (RCTScheduler *)_scheduler } auto componentRegistryFactory = [factory = wrapManagedObject(self.componentViewFactory)]( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) { return [(RCTComponentViewFactory *)unwrapManagedObject(factory) createComponentDescriptorRegistryWithParameters:{eventDispatcher, contextContainer}]; diff --git a/ReactCommon/fabric/components/image/ImageComponentDescriptor.h b/ReactCommon/fabric/components/image/ImageComponentDescriptor.h index d05be1215fe34e..6ff78abc6de96e 100644 --- a/ReactCommon/fabric/components/image/ImageComponentDescriptor.h +++ b/ReactCommon/fabric/components/image/ImageComponentDescriptor.h @@ -22,7 +22,7 @@ class ImageComponentDescriptor final : public ConcreteComponentDescriptor { public: ImageComponentDescriptor( - EventDispatcher::Shared eventDispatcher, + EventDispatcher::Weak eventDispatcher, ContextContainer::Shared const &contextContainer) : ConcreteComponentDescriptor(eventDispatcher), imageManager_(std::make_shared(contextContainer)){}; diff --git a/ReactCommon/fabric/components/modal/ModalHostViewComponentDescriptor.h b/ReactCommon/fabric/components/modal/ModalHostViewComponentDescriptor.h index 7f8b7c691adfcf..73453b4f6c1fe8 100644 --- a/ReactCommon/fabric/components/modal/ModalHostViewComponentDescriptor.h +++ b/ReactCommon/fabric/components/modal/ModalHostViewComponentDescriptor.h @@ -22,7 +22,7 @@ class ModalHostViewComponentDescriptor final : public ConcreteComponentDescriptor { public: #ifdef ANDROID - ModalHostViewComponentDescriptor(EventDispatcher::Shared eventDispatcher) + ModalHostViewComponentDescriptor(EventDispatcher::Weak eventDispatcher) : ConcreteComponentDescriptor(eventDispatcher) {} #else using ConcreteComponentDescriptor::ConcreteComponentDescriptor; diff --git a/ReactCommon/fabric/components/slider/SliderComponentDescriptor.h b/ReactCommon/fabric/components/slider/SliderComponentDescriptor.h index 725d08bd412747..7374df65a1e110 100644 --- a/ReactCommon/fabric/components/slider/SliderComponentDescriptor.h +++ b/ReactCommon/fabric/components/slider/SliderComponentDescriptor.h @@ -21,7 +21,7 @@ class SliderComponentDescriptor final : public ConcreteComponentDescriptor { public: SliderComponentDescriptor( - EventDispatcher::Shared eventDispatcher, + EventDispatcher::Weak eventDispatcher, ContextContainer::Shared const &contextContainer) : ConcreteComponentDescriptor(eventDispatcher), imageManager_(std::make_shared(contextContainer)), diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h index a0dd2abff798dc..80510ce44d6317 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h @@ -26,7 +26,7 @@ class ParagraphComponentDescriptor final : public ConcreteComponentDescriptor { public: ParagraphComponentDescriptor( - EventDispatcher::Shared eventDispatcher, + EventDispatcher::Weak eventDispatcher, ContextContainer::Shared const &contextContainer) : ConcreteComponentDescriptor(eventDispatcher) { // Every single `ParagraphShadowNode` will have a reference to diff --git a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.cpp b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.cpp index d26a1483a81fe0..37671c2981a890 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.cpp +++ b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.cpp @@ -11,7 +11,7 @@ namespace facebook { namespace react { ComponentDescriptor::ComponentDescriptor( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) : eventDispatcher_(eventDispatcher), contextContainer_(contextContainer) {} diff --git a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h index 1eb5cb81cf41dc..6fd7d26a5f7f96 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h @@ -34,7 +34,7 @@ class ComponentDescriptor { using Unique = std::unique_ptr; ComponentDescriptor( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer); virtual ~ComponentDescriptor() = default; @@ -111,7 +111,7 @@ class ComponentDescriptor { const StateData::Shared &data) const = 0; protected: - EventDispatcher::Shared eventDispatcher_; + EventDispatcher::Weak eventDispatcher_; ContextContainer::Shared contextContainer_; RawPropsParser rawPropsParser_{}; }; diff --git a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h index b0ab8c3b88caf9..e5a3912a2f612f 100644 --- a/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h +++ b/ReactCommon/fabric/core/componentdescriptor/ConcreteComponentDescriptor.h @@ -46,7 +46,7 @@ class ConcreteComponentDescriptor : public ComponentDescriptor { using ConcreteStateData = typename ShadowNodeT::ConcreteState::Data; ConcreteComponentDescriptor( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer = {}) : ComponentDescriptor(eventDispatcher, contextContainer) { rawPropsParser_.prepare(); diff --git a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp index 362966bd623b77..10eabe4749b686 100644 --- a/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp +++ b/ReactCommon/fabric/core/tests/ComponentDescriptorTest.cpp @@ -12,8 +12,9 @@ using namespace facebook::react; TEST(ComponentDescriptorTest, createShadowNode) { + auto eventDispatcher = std::shared_ptr(); SharedComponentDescriptor descriptor = - std::make_shared(nullptr); + std::make_shared(eventDispatcher); ASSERT_EQ(descriptor->getComponentHandle(), TestShadowNode::Handle()); ASSERT_STREQ(descriptor->getComponentName(), TestShadowNode::Name()); @@ -37,8 +38,9 @@ TEST(ComponentDescriptorTest, createShadowNode) { } TEST(ComponentDescriptorTest, cloneShadowNode) { + auto eventDispatcher = std::shared_ptr(); SharedComponentDescriptor descriptor = - std::make_shared(nullptr); + std::make_shared(eventDispatcher); const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); SharedProps props = descriptor->cloneProps(nullptr, raw); @@ -57,8 +59,9 @@ TEST(ComponentDescriptorTest, cloneShadowNode) { } TEST(ComponentDescriptorTest, appendChild) { + auto eventDispatcher = std::shared_ptr(); SharedComponentDescriptor descriptor = - std::make_shared(nullptr); + std::make_shared(eventDispatcher); const auto &raw = RawProps(folly::dynamic::object("nativeID", "abc")); SharedProps props = descriptor->cloneProps(nullptr, raw); diff --git a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp index 5b87630061e054..7f8bbb2ecf4873 100644 --- a/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp +++ b/ReactCommon/fabric/core/tests/ShadowNodeTest.cpp @@ -30,7 +30,8 @@ TEST(ShadowNodeTest, handleProps) { } TEST(ShadowNodeTest, handleShadowNodeCreation) { - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto node = std::make_shared( ShadowNodeFragment{ /* .tag = */ 9, @@ -54,7 +55,8 @@ TEST(ShadowNodeTest, handleShadowNodeCreation) { } TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) { - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto node = std::make_shared( ShadowNodeFragment{ /* .tag = */ 9, @@ -73,7 +75,8 @@ TEST(ShadowNodeTest, handleShadowNodeSimpleCloning) { } TEST(ShadowNodeTest, handleShadowNodeMutation) { - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto props = std::make_shared(); auto node1 = std::make_shared( ShadowNodeFragment{ @@ -132,7 +135,8 @@ TEST(ShadowNodeTest, handleShadowNodeMutation) { } TEST(ShadowNodeTest, handleCloneFunction) { - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto firstNode = std::make_shared( ShadowNodeFragment{ @@ -160,7 +164,8 @@ TEST(ShadowNodeTest, handleCloneFunction) { } TEST(ShadowNodeTest, handleLocalData) { - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto localData42 = std::make_shared(); localData42->setNumber(42); @@ -227,7 +232,8 @@ TEST(ShadowNodeTest, handleBacktracking) { * */ - auto componentDescriptor = TestComponentDescriptor(nullptr); + auto eventDispatcher = std::shared_ptr(); + auto componentDescriptor = TestComponentDescriptor(eventDispatcher); auto props = std::make_shared(); auto nodeAA = std::make_shared( diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h b/ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h index 38a82483eedcac..5514dd5c14ef3e 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h @@ -25,7 +25,7 @@ namespace react { */ using ComponentRegistryFactory = std::function; ComponentRegistryFactory getDefaultComponentRegistryFactory(); diff --git a/ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h b/ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h index dc93a6312b69a6..54c697c50131e3 100644 --- a/ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h +++ b/ReactCommon/fabric/uimanager/ComponentDescriptorProvider.h @@ -20,7 +20,7 @@ namespace react { */ class ComponentDescriptorParameters { public: - EventDispatcher::Shared eventDispatcher; + EventDispatcher::Weak eventDispatcher; ContextContainer::Shared contextContainer; }; @@ -30,7 +30,7 @@ class ComponentDescriptorParameters { * abstract type and ownership of the newly created object. */ using ComponentDescriptorConstructor = ComponentDescriptor::Unique( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer); /* @@ -52,7 +52,7 @@ class ComponentDescriptorProvider final { */ template ComponentDescriptor::Unique concreteComponentDescriptorConstructor( - EventDispatcher::Shared const &eventDispatcher, + EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) { static_assert( std::is_base_of::value, diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index cb4b38c61c0539..902087eb280298 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -72,6 +72,8 @@ Scheduler::Scheduler( "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE", std::weak_ptr( componentDescriptorRegistry_)); + + eventDispatcher_ = eventDispatcher; } Scheduler::~Scheduler() { diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index 4f87ab778030cc..9a9dbdf96e2bbc 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -110,6 +110,7 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate { RuntimeExecutor runtimeExecutor_; std::shared_ptr uiManagerBinding_; std::shared_ptr reactNativeConfig_; + EventDispatcher::Shared eventDispatcher_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp b/ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp index 7a16b525552982..ad2b2d7bf9d6a0 100644 --- a/ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp +++ b/ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp @@ -27,7 +27,7 @@ namespace react { // TODO (T29441913): Codegen this app-specific implementation. ComponentRegistryFactory getDefaultComponentRegistryFactory() { - return [](const EventDispatcher::Shared &eventDispatcher, + return [](const EventDispatcher::Weak &eventDispatcher, const ContextContainer::Shared &contextContainer) { auto registry = std::make_shared(); registry->registerComponentDescriptor( @@ -83,8 +83,9 @@ std::shared_ptr mockReactNativeConfig_ = TEST(UITemplateProcessorTest, testSimpleBytecode) { auto surfaceId = 11; + auto eventDispatcher = std::shared_ptr(); auto componentDescriptorRegistry = - getDefaultComponentRegistryFactory()(nullptr, nullptr); + getDefaultComponentRegistryFactory()(eventDispatcher, nullptr); auto nativeModuleRegistry = buildNativeModuleRegistry(); auto bytecode = R"delim({"version":0.1,"commands":[ @@ -117,8 +118,9 @@ TEST(UITemplateProcessorTest, testSimpleBytecode) { TEST(UITemplateProcessorTest, testConditionalBytecode) { auto surfaceId = 11; + auto eventDispatcher = std::shared_ptr(); auto componentDescriptorRegistry = - getDefaultComponentRegistryFactory()(nullptr, nullptr); + getDefaultComponentRegistryFactory()(eventDispatcher, nullptr); auto nativeModuleRegistry = buildNativeModuleRegistry(); auto bytecode = R"delim({"version":0.1,"commands":[ From 4ffe5b6f6de5e2711629db75d52ac494faefac61 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0088/1244] Fabric: Farewell EventBeatBasedExecutor Summary: We don't use it anymore. Reviewed By: JoshuaGross Differential Revision: D17115539 fbshipit-source-id: e1fa5cc023cd27e53307aa0ea8eae0bad5413be3 --- .../core/events/EventBeatBasedExecutor.cpp | 82 ------------------- .../core/events/EventBeatBasedExecutor.h | 53 ------------ 2 files changed, 135 deletions(-) delete mode 100644 ReactCommon/fabric/core/events/EventBeatBasedExecutor.cpp delete mode 100644 ReactCommon/fabric/core/events/EventBeatBasedExecutor.h diff --git a/ReactCommon/fabric/core/events/EventBeatBasedExecutor.cpp b/ReactCommon/fabric/core/events/EventBeatBasedExecutor.cpp deleted file mode 100644 index d9b630c4f9b040..00000000000000 --- a/ReactCommon/fabric/core/events/EventBeatBasedExecutor.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include "EventBeatBasedExecutor.h" - -namespace facebook { -namespace react { - -using Mode = EventBeatBasedExecutor::Mode; - -EventBeatBasedExecutor::EventBeatBasedExecutor( - std::unique_ptr eventBeat) - : eventBeat_(std::move(eventBeat)) { - eventBeat_->setBeatCallback( - std::bind(&EventBeatBasedExecutor::onBeat, this, true)); - eventBeat_->setFailCallback( - std::bind(&EventBeatBasedExecutor::onBeat, this, false)); -} - -void EventBeatBasedExecutor::operator()(Routine routine, Mode mode) const { - if (mode == Mode::Asynchronous) { - execute({ - /* .routine = */ std::move(routine), - }); - return; - } - - std::mutex mutex; - mutex.lock(); - - execute({ - /* .routine = */ std::move(routine), - /* .callback = */ [&mutex]() { mutex.unlock(); }, - }); - - mutex.lock(); -} - -void EventBeatBasedExecutor::execute(Task task) const { - { - std::lock_guard lock(mutex_); - - tasks_.push_back(std::move(task)); - } - - eventBeat_->request(); - eventBeat_->induce(); -} - -void EventBeatBasedExecutor::onBeat(bool success) const { - std::vector tasks; - - { - std::lock_guard lock(mutex_); - - if (tasks_.size() == 0) { - return; - } - - tasks = std::move(tasks_); - tasks_.clear(); - } - - for (const auto task : tasks) { - if (success) { - task.routine(); - } - - if (task.callback) { - task.callback(); - } - } -} - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/core/events/EventBeatBasedExecutor.h b/ReactCommon/fabric/core/events/EventBeatBasedExecutor.h deleted file mode 100644 index ea281ae731cb15..00000000000000 --- a/ReactCommon/fabric/core/events/EventBeatBasedExecutor.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#pragma once - -#include -#include -#include - -#include - -namespace facebook { -namespace react { - -/* - * General purpose executor that uses EventBeat to ensure proper threading. - */ -class EventBeatBasedExecutor { - public: - using Routine = std::function; - using Callback = std::function; - - struct Task { - Routine routine; - Callback callback; - }; - - enum class Mode { Synchronous, Asynchronous }; - - EventBeatBasedExecutor(std::unique_ptr eventBeat); - - /* - * Executes given routine with given mode. - */ - void operator()(Routine routine, Mode mode = Mode::Asynchronous) const; - - private: - void onBeat(bool success = true) const; - void execute(Task task) const; - - std::unique_ptr eventBeat_; - mutable std::vector tasks_; // Protected by `mutex_`. - mutable std::mutex mutex_; -}; - -using EventBeatFactory = std::function()>; - -} // namespace react -} // namespace facebook From e6c6ebf08e9baf9a9796de261f1d8a3577444c2e Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0089/1244] Fabric: Removing `EventBeat::setFailCallback` Summary: We don't use it anymore. (And that was debug only concept.) Reviewed By: sammy-SC Differential Revision: D17115538 fbshipit-source-id: 20aac5457e37666cbf9ca9f62cdfca411026c219 --- React/Fabric/Utils/RuntimeEventBeat.mm | 19 ------------------- ReactCommon/fabric/core/events/EventBeat.cpp | 4 ---- ReactCommon/fabric/core/events/EventBeat.h | 10 ---------- 3 files changed, 33 deletions(-) diff --git a/React/Fabric/Utils/RuntimeEventBeat.mm b/React/Fabric/Utils/RuntimeEventBeat.mm index 6b05f2c60942bd..77b6b14415be6b 100644 --- a/React/Fabric/Utils/RuntimeEventBeat.mm +++ b/React/Fabric/Utils/RuntimeEventBeat.mm @@ -40,29 +40,10 @@ return; } -#ifndef NDEBUG - // We do a trick here. - // If `wasExecuted` was destroyed before set to `true`, - // it means that the execution block was deallocated not being executed. - // This indicates that `messageQueueThread_` is being deallocated. - // This trick is quite expensive due to deallocation and messing with atomic - // counters. Seems we need this only for making hot-reloading mechanism - // thread-safe. Hence, let's leave it to be DEBUG-only for now. - auto wasExecuted = std::shared_ptr(new bool{false}, [this](bool *wasExecuted) { - if (!*wasExecuted && failCallback_) { - failCallback_(); - } - delete wasExecuted; - }); -#endif - isBusy_ = true; runtimeExecutor_([=](jsi::Runtime &runtime) mutable { this->beat(runtime); isBusy_ = false; -#ifndef NDEBUG - *wasExecuted = true; -#endif }); } diff --git a/ReactCommon/fabric/core/events/EventBeat.cpp b/ReactCommon/fabric/core/events/EventBeat.cpp index 2ce95b4d3284a7..d16cfa36c751b6 100644 --- a/ReactCommon/fabric/core/events/EventBeat.cpp +++ b/ReactCommon/fabric/core/events/EventBeat.cpp @@ -34,9 +34,5 @@ void EventBeat::setBeatCallback(const BeatCallback &beatCallback) { beatCallback_ = beatCallback; } -void EventBeat::setFailCallback(const FailCallback &failCallback) { - failCallback_ = failCallback; -} - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/events/EventBeat.h b/ReactCommon/fabric/core/events/EventBeat.h index 664a7292f9f7da..f0c88f15d04b32 100644 --- a/ReactCommon/fabric/core/events/EventBeat.h +++ b/ReactCommon/fabric/core/events/EventBeat.h @@ -24,7 +24,6 @@ class EventBeat { virtual ~EventBeat() = default; using BeatCallback = std::function; - using FailCallback = std::function; /* * Communicates to the Beat that a consumer is waiting for the coming beat. @@ -50,14 +49,6 @@ class EventBeat { */ void setBeatCallback(const BeatCallback &beatCallback); - /* - * Sets the fail callback function. - * Called in case if the beat cannot be performed anymore because of - * some external circumstances (e.g. execution thread is beling destructed). - * The callback can be called on any thread. - */ - void setFailCallback(const FailCallback &failCallback); - /* * Should be used by sublasses to send a beat. * Receiver might ignore the call if a beat was not requested. @@ -66,7 +57,6 @@ class EventBeat { protected: BeatCallback beatCallback_; - FailCallback failCallback_; mutable std::atomic isRequested_{false}; }; From dd7f99b1ae0384ddc77ca138a1e0a29ba5594806 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0090/1244] Fabric: Changing retaining configuration among `UIManager`, `UIManagerBindging`, `Scheduler` and `EventDisaptcher` Summary: This diff changes the way how `UIManager`, `UIManagerBindging`, `Scheduler` and `EventDisaptcher` refer to each other which should help with stability and reliability. Here is the node that describes the details: # Retaining dilemma # Players We have many logical of moving pieces but most of them can be abstracted by following high-level components. * **Scheduler** `Scheduler` is the main representation of running React Native infrastructure. Creation of it means the creation of all React Native C++ subsystems (excluding RuntimeExecutor) and destruction of that means the destruction of all dependent parts. Both processes must be thread-safe. * **UIManager** UIManager is a module that contains the most high-level logic of managing shadow trees. All React Renderer calls are practically implemented there. * **UIManagerBinding** UIManagerBinding is a representation (aka `HostObject`) of UIManager in the JavaScript world. * **EventDispatcher** EventDispatcher is a class that implements all logic related to dispatching events: from calling event on any thread anywhere to executing a particular JavaScript handler responsible for handling that event. Instances of those classes have complex relationships in terms of owning each other, order of creation and destruction. The configuration of these relationships is dictated by a set of constraints that those classes need to satisfy to be constructed, accessed, and destructed in a hostile multithreaded environment. Messing with that can cause deadlocks, random crashes, suboptimal performance or memory leaks. Make sure you consider all constraints and requirements before changing that. # Goal We need to have a safe and reliable way to construct and destroy those objects (on any thread, in any random moment). Keep in mind that all of those objects are being accessed from random threads and have random states in any particular moment. Switching threads happens all the time, so having some state in one place does not guarantee any state in other places. # Caveats Let's discuss all concrete constrains that the moving pieces have to satisfy. * **UIManagerBinding is a HostObject** Practically that means: 1. It must be constructed "on JavaScript thread" (with exclusive access to JavaScript VM); 2. It must not be retained by other parts of the system because overliving the VM will cause a crash. 3. It can be destructed on any thread (VM does not give any guarantees here). The particular configuration guarantees that the destruction cannot be run concurrently with any JS execution though (because we never clear the reference to the host object from JavaScript side). * **UIManager needs to be connected with UIManagerBinding and vice-versa** Those to modules call each other to perform some UI updates or deliver events. * **Scheduler can be deallocated on any thread at any time** Timing and thread are up to the application side. The Scheduler must be resilient to that. * **EventDispatcher can call UIManager at any time** Luckily, that happens only on JavaScript thread. * **Using weak pointers cames at a cost** `std::weak_ptr` is a concept for managing the non-owning relationships in a safe manner. Dereferencing such pointers cames at a cost (additional object construction and atomic counters bumps). So, we should use that carefully; we cannot use shared and week pointers everywhere and assume that will work magically. # How does this blow up? Without describing the current configuration, here are a variety of cases that we currently observe. 1. `Scheduler` was deallocated and destroyed UIManager but VM is still running. The VM calls the UIManagerBinding, UIManagerBinding calls a method on already deallocated UIManager. Boom. 2. VM is being deallocated and deletes all host object as part of this process. Some UI event is sill in flight on some thread. The event retains UIManagerBinding via UIManager. VM cannot destroy UIManagerBinding because it's being retained. Boom. 3. VM was deallocated. `Scheduler` was deallocated. But some native state update is still in flight. It retains EventDispatcher and eventually trying to access some shadow tree that was retained by Scheduler and already dead. Boom. That's pretty much routine endless nightmare of any low-level framework. Luckily, the good proper decisions (and iterating on that!) can solve that. # Proposed configuration The configuration is based on those ideas: 1. Never retain `UIManagerBinging`. 2. Never recreate `UIManagerBinging`. Create once and load lazily from JS environment on demand. 3. Consider UIManager as an object with shared ownership between JS and native. That object must be able to overlive native infra or JS VM. 4. Use EventDispatcher as a single weak representation of the JavaScript world; Never retain it strongly except by the Scheduler. 5. `UIManagerBinging` and `UIManager` can be attached or detached. `UIManagerBinging` retains `UIManager`, `UIManager` does not retain `UIManagerBinging` back. Destroying `UIManagerBinging` nulls the raw pointer to that from `UIManager`. 6. All calls from native to JavaScript can validate the pointer from `UIManager` to `UIManagerBinging` to check that the call is possible. All that calls happen on JavaScript thread. ## Stages * **Creation process** Creation Scheduler creates `UIManager` and scheduler asynchronous call to JavaScript to create `UIManagerBinding` and attach them. At the same time `Scheduler` creates `EventDispatcher` and makes it retains `UIManager`. * **JavaScript-to-native invocation** `UIManagerBinding` has a shared pointer to `UIManager` and can cheaply and safely verify that the pointer is not nullptr. Any mutation of this pointer happens on the JavaScript thread or effectively on VM destruction (non-concurrently). * **Native-to-JavaScript invocation** The invocation starts from retaining `EventDispatcher` (converting a weak pointer to strong one), that retains `UIManager`. Later, on the JavaScript thread, `UIManager` checks the raw pointer to `UIManagerBinding` to verify that the call can be performed safely. # Easy ways to break the fragile balance - Never retain `EventDispatcher` as a shared pointer. That causes a leak of UIManager and associated resources. - Access a shared pointer to `UIManager` by value only. The simple way to break that is to specify `[=]` capture block for a lambda and access an instance variable pointing to a `UIManager` (that does not retain the pointer; make a copy on the stack and copy that to the lambda). Reviewed By: JoshuaGross Differential Revision: D17120333 fbshipit-source-id: 83138657683e91ceb2f48f18f30e745199c83e82 --- ReactCommon/fabric/uimanager/Scheduler.cpp | 44 ++++--- ReactCommon/fabric/uimanager/Scheduler.h | 2 +- ReactCommon/fabric/uimanager/UIManager.cpp | 10 ++ ReactCommon/fabric/uimanager/UIManager.h | 13 +++ .../fabric/uimanager/UIManagerBinding.cpp | 108 ++++++++++++------ .../fabric/uimanager/UIManagerBinding.h | 21 +++- 6 files changed, 135 insertions(+), 63 deletions(-) diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 902087eb280298..50f2552d02f04d 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -27,20 +27,19 @@ Scheduler::Scheduler( schedulerToolbox.contextContainer ->at>("ReactNativeConfig"); - auto uiManager = std::make_unique(); - auto &uiManagerRef = *uiManager; - uiManagerBinding_ = std::make_shared(std::move(uiManager)); + auto uiManager = std::make_shared(); - auto eventPipe = [uiManagerBinding = uiManagerBinding_.get()]( - jsi::Runtime &runtime, + auto eventPipe = [=](jsi::Runtime &runtime, const EventTarget *eventTarget, const std::string &type, const ValueFactory &payloadFactory) { - uiManagerBinding->dispatchEvent(runtime, eventTarget, type, payloadFactory); + uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { + uiManagerBinding.dispatchEvent( + runtime, eventTarget, type, payloadFactory); + }); }; - auto statePipe = [uiManager = &uiManagerRef]( - const StateData::Shared &data, + auto statePipe = [=](const StateData::Shared &data, const StateTarget &stateTarget) { uiManager->updateState( stateTarget.getShadowNode().shared_from_this(), data); @@ -52,20 +51,21 @@ Scheduler::Scheduler( schedulerToolbox.synchronousEventBeatFactory, schedulerToolbox.asynchronousEventBeatFactory); + eventDispatcher_ = eventDispatcher; + componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory( eventDispatcher, schedulerToolbox.contextContainer); rootComponentDescriptor_ = std::make_unique(eventDispatcher); - delegate_ = delegate; - - uiManagerRef.setDelegate(this); - uiManagerRef.setShadowTreeRegistry(&shadowTreeRegistry_); - uiManagerRef.setComponentDescriptorRegistry(componentDescriptorRegistry_); + uiManager->setDelegate(this); + uiManager->setShadowTreeRegistry(&shadowTreeRegistry_); + uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_); runtimeExecutor_([=](jsi::Runtime &runtime) { - UIManagerBinding::install(runtime, uiManagerBinding_); + auto uiManagerBinding = UIManagerBinding::createAndInstallIfNeeded(runtime); + uiManagerBinding->attach(uiManager); }); schedulerToolbox.contextContainer->insert( @@ -73,11 +73,13 @@ Scheduler::Scheduler( std::weak_ptr( componentDescriptorRegistry_)); + delegate_ = delegate; eventDispatcher_ = eventDispatcher; + uiManager_ = uiManager; } Scheduler::~Scheduler() { - uiManagerBinding_->invalidate(); + uiManager_->setDelegate(nullptr); } void Scheduler::startSurface( @@ -94,9 +96,12 @@ void Scheduler::startSurface( shadowTreeRegistry_.add(std::move(shadowTree)); + auto uiManager = uiManager_; runtimeExecutor_([=](jsi::Runtime &runtime) { - uiManagerBinding_->startSurface( - runtime, surfaceId, moduleName, initialProps); + uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { + uiManagerBinding.startSurface( + runtime, surfaceId, moduleName, initialProps); + }); }); } @@ -166,8 +171,11 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { auto shadowTree = shadowTreeRegistry_.remove(surfaceId); shadowTree->setDelegate(nullptr); + auto uiManager = uiManager_; runtimeExecutor_([=](jsi::Runtime &runtime) { - uiManagerBinding_->stopSurface(runtime, surfaceId); + uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { + uiManagerBinding.stopSurface(runtime, surfaceId); + }); }); } diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index 9a9dbdf96e2bbc..43fccd7aabf41a 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -108,7 +108,7 @@ class Scheduler final : public UIManagerDelegate, public ShadowTreeDelegate { std::unique_ptr rootComponentDescriptor_; ShadowTreeRegistry shadowTreeRegistry_; RuntimeExecutor runtimeExecutor_; - std::shared_ptr uiManagerBinding_; + std::shared_ptr uiManager_; std::shared_ptr reactNativeConfig_; EventDispatcher::Shared eventDispatcher_; }; diff --git a/ReactCommon/fabric/uimanager/UIManager.cpp b/ReactCommon/fabric/uimanager/UIManager.cpp index 0f74d2503d4063..b38e1e5ab5f824 100644 --- a/ReactCommon/fabric/uimanager/UIManager.cpp +++ b/ReactCommon/fabric/uimanager/UIManager.cpp @@ -208,5 +208,15 @@ UIManagerDelegate *UIManager::getDelegate() { return delegate_; } +void UIManager::visitBinding( + std::function callback) + const { + if (!uiManagerBinding_) { + return; + } + + callback(*uiManagerBinding_); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/uimanager/UIManager.h b/ReactCommon/fabric/uimanager/UIManager.h index 1ca5909f93c711..124cb262d7ace1 100644 --- a/ReactCommon/fabric/uimanager/UIManager.h +++ b/ReactCommon/fabric/uimanager/UIManager.h @@ -15,6 +15,8 @@ namespace facebook { namespace react { +class UIManagerBinding; + class UIManager { public: void setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry); @@ -30,6 +32,16 @@ class UIManager { void setDelegate(UIManagerDelegate *delegate); UIManagerDelegate *getDelegate(); + /* + * Provides access to a UIManagerBindging. + * The `callback` methods will not be called if the internal pointer to + * `UIManagerBindging` is `nullptr`. + * The callback is called synchronously on the same thread. + */ + void visitBinding( + std::function callback) + const; + private: friend class UIManagerBinding; friend class Scheduler; @@ -89,6 +101,7 @@ class UIManager { ShadowTreeRegistry *shadowTreeRegistry_; SharedComponentDescriptorRegistry componentDescriptorRegistry_; UIManagerDelegate *delegate_; + UIManagerBinding *uiManagerBinding_; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index 57c252bbf97bf3..00de25f8654faf 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -25,16 +25,48 @@ static jsi::Object getModule( return module; } -void UIManagerBinding::install( - jsi::Runtime &runtime, - std::shared_ptr uiManagerBinding) { +std::shared_ptr UIManagerBinding::createAndInstallIfNeeded( + jsi::Runtime &runtime) { auto uiManagerModuleName = "nativeFabricUIManager"; - auto object = jsi::Object::createFromHostObject(runtime, uiManagerBinding); - runtime.global().setProperty(runtime, uiManagerModuleName, std::move(object)); + + auto uiManagerValue = + runtime.global().getProperty(runtime, uiManagerModuleName); + if (uiManagerValue.isUndefined()) { + // The global namespace does not have an instance of the binding; + // we need to create, install and return it. + auto uiManagerBinding = std::make_shared(); + auto object = jsi::Object::createFromHostObject(runtime, uiManagerBinding); + runtime.global().setProperty( + runtime, uiManagerModuleName, std::move(object)); + return uiManagerBinding; + } + + // The global namespace already has an instance of the binding; + // we need to return that. + auto uiManagerObject = uiManagerValue.asObject(runtime); + return uiManagerObject.getHostObject(runtime); +} + +UIManagerBinding::~UIManagerBinding() { + // We must detach the `UIBinding` on deallocation to prevent accessing + // deallocated `UIManagerBinding`. + // Since `UIManagerBinding` retains `UIManager`, `UIManager` always overlive + // `UIManagerBinding`, therefore we don't need similar logic in `UIManager`'s + // destructor. + attach(nullptr); } -UIManagerBinding::UIManagerBinding(std::unique_ptr uiManager) - : uiManager_(std::move(uiManager)) {} +void UIManagerBinding::attach(std::shared_ptr const &uiManager) { + if (uiManager_) { + uiManager_->uiManagerBinding_ = nullptr; + } + + uiManager_ = uiManager; + + if (uiManager_) { + uiManager_->uiManagerBinding_ = this; + } +} void UIManagerBinding::startSurface( jsi::Runtime &runtime, @@ -124,7 +156,7 @@ jsi::Value UIManagerBinding::get( jsi::Runtime &runtime, const jsi::PropNameID &name) { auto methodName = name.utf8(runtime); - auto &uiManager = *uiManager_; + auto uiManager = uiManager_; // Semantic: Creates a new node with given pieces. if (methodName == "createNode") { @@ -132,14 +164,14 @@ jsi::Value UIManagerBinding::get( runtime, name, 5, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { return valueFromShadowNode( runtime, - uiManager.createNode( + uiManager->createNode( tagFromValue(runtime, arguments[0]), stringFromValue(runtime, arguments[1]), surfaceIdFromValue(runtime, arguments[2]), @@ -154,14 +186,14 @@ jsi::Value UIManagerBinding::get( runtime, name, 1, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { return valueFromShadowNode( runtime, - uiManager.cloneNode(shadowNodeFromValue(runtime, arguments[0]))); + uiManager->cloneNode(shadowNodeFromValue(runtime, arguments[0]))); }); } @@ -170,12 +202,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.setJSResponder( + uiManager->setJSResponder( shadowNodeFromValue(runtime, arguments[0]), arguments[1].getBool()); @@ -188,12 +220,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 0, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.clearJSResponder(); + uiManager->clearJSResponder(); return jsi::Value::undefined(); }); @@ -205,14 +237,14 @@ jsi::Value UIManagerBinding::get( runtime, name, 1, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { return valueFromShadowNode( runtime, - uiManager.cloneNode( + uiManager->cloneNode( shadowNodeFromValue(runtime, arguments[0]), ShadowNode::emptySharedShadowNodeSharedList())); }); @@ -224,7 +256,7 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, @@ -232,7 +264,7 @@ jsi::Value UIManagerBinding::get( const auto &rawProps = RawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, - uiManager.cloneNode( + uiManager->cloneNode( shadowNodeFromValue(runtime, arguments[0]), nullptr, &rawProps)); @@ -245,7 +277,7 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, @@ -253,7 +285,7 @@ jsi::Value UIManagerBinding::get( const auto &rawProps = RawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, - uiManager.cloneNode( + uiManager->cloneNode( shadowNodeFromValue(runtime, arguments[0]), ShadowNode::emptySharedShadowNodeSharedList(), &rawProps)); @@ -265,12 +297,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.appendChild( + uiManager->appendChild( shadowNodeFromValue(runtime, arguments[0]), shadowNodeFromValue(runtime, arguments[1])); return jsi::Value::undefined(); @@ -313,12 +345,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.completeSurface( + uiManager->completeSurface( surfaceIdFromValue(runtime, arguments[0]), shadowNodeListFromValue(runtime, arguments[1])); return jsi::Value::undefined(); @@ -348,12 +380,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - auto layoutMetrics = uiManager.getRelativeLayoutMetrics( + auto layoutMetrics = uiManager->getRelativeLayoutMetrics( *shadowNodeFromValue(runtime, arguments[0]), shadowNodeFromValue(runtime, arguments[1]).get()); auto frame = layoutMetrics.frame; @@ -371,12 +403,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 3, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.dispatchCommand( + uiManager->dispatchCommand( shadowNodeFromValue(runtime, arguments[0]), stringFromValue(runtime, arguments[1]), commandArgsFromValue(runtime, arguments[2])); @@ -391,12 +423,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 4, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - auto layoutMetrics = uiManager.getRelativeLayoutMetrics( + auto layoutMetrics = uiManager->getRelativeLayoutMetrics( *shadowNodeFromValue(runtime, arguments[0]), shadowNodeFromValue(runtime, arguments[1]).get()); @@ -426,12 +458,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - auto layoutMetrics = uiManager.getRelativeLayoutMetrics( + auto layoutMetrics = uiManager->getRelativeLayoutMetrics( *shadowNodeFromValue(runtime, arguments[0]), nullptr); auto frame = layoutMetrics.frame; auto onSuccessFunction = @@ -454,12 +486,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - auto layoutMetrics = uiManager.getRelativeLayoutMetrics( + auto layoutMetrics = uiManager->getRelativeLayoutMetrics( *shadowNodeFromValue(runtime, arguments[0]), nullptr); auto onSuccessFunction = @@ -481,12 +513,12 @@ jsi::Value UIManagerBinding::get( runtime, name, 2, - [&uiManager]( + [uiManager]( jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *arguments, size_t count) -> jsi::Value { - uiManager.setNativeProps( + uiManager->setNativeProps( shadowNodeFromValue(runtime, arguments[0]), RawProps(runtime, arguments[1])); diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.h b/ReactCommon/fabric/uimanager/UIManagerBinding.h index 40c5fccf3bf831..b7563c12cfd00f 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.h +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.h @@ -16,14 +16,23 @@ namespace react { class UIManagerBinding : public jsi::HostObject { public: /* - * Installs UIManagerBinding into JavaScript runtime. + * Installs UIManagerBinding into JavaScript runtime if needed. + * Creates and sets `UIManagerBinding` into the global namespace. + * In case if the global namespace already has a `UIManagerBinding` installed, + * returns that. * Thread synchronization must be enforced externally. */ - static void install( - jsi::Runtime &runtime, - std::shared_ptr uiManagerBinding); + static std::shared_ptr createAndInstallIfNeeded( + jsi::Runtime &runtime); + + ~UIManagerBinding(); - UIManagerBinding(std::unique_ptr uiManager); + /* + * Establish a relationship between `UIManager` and `UIManagerBinding` by + * setting internal pointers to each other. + * Must be called on JavaScript thread or during VM destruction. + */ + void attach(std::shared_ptr const &uiManager); /* * Starts React Native Surface with given id, moduleName, and props. @@ -66,7 +75,7 @@ class UIManagerBinding : public jsi::HostObject { jsi::Value get(jsi::Runtime &runtime, const jsi::PropNameID &name) override; private: - std::unique_ptr uiManager_; + std::shared_ptr uiManager_; std::unique_ptr eventHandler_; }; From 5c39c22187030c9adfb55cf28616e34cf5916973 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0091/1244] Fabric: Moving ShadowTreeRegistry from Scheduler to UIManager Summary: Seems it's more logical and safe to store ShadowTreeRegistry in UIManager than in Scheduler. We also probably will move some functionality dealing with the registry to UIManager. But most importantly we need it to manage the ownership properly. UIManager might overlive Scheduler and still get a call to process a shadow tree. In the current configuration, it causes a crash because the registry owns by Scheduler. Moving that to UIManager solves that. Reviewed By: JoshuaGross Differential Revision: D17128550 fbshipit-source-id: e6735acaa11f2ed82ca17f18a45e389d79aa1a08 --- ReactCommon/fabric/uimanager/Scheduler.cpp | 88 ++++++++++--------- ReactCommon/fabric/uimanager/Scheduler.h | 1 - ReactCommon/fabric/uimanager/UIManager.cpp | 14 +-- ReactCommon/fabric/uimanager/UIManager.h | 5 +- .../fabric/uimanager/UIManagerBinding.cpp | 1 - 5 files changed, 57 insertions(+), 52 deletions(-) diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index 50f2552d02f04d..f52e1e9328728a 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -60,7 +60,6 @@ Scheduler::Scheduler( std::make_unique(eventDispatcher); uiManager->setDelegate(this); - uiManager->setShadowTreeRegistry(&shadowTreeRegistry_); uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_); runtimeExecutor_([=](jsi::Runtime &runtime) { @@ -94,9 +93,10 @@ void Scheduler::startSurface( surfaceId, layoutConstraints, layoutContext, *rootComponentDescriptor_); shadowTree->setDelegate(this); - shadowTreeRegistry_.add(std::move(shadowTree)); - auto uiManager = uiManager_; + + uiManager->getShadowTreeRegistry().add(std::move(shadowTree)); + runtimeExecutor_([=](jsi::Runtime &runtime) { uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) { uiManagerBinding.startSurface( @@ -122,9 +122,10 @@ void Scheduler::renderTemplateToSurface( nMR, reactNativeConfig_); - shadowTreeRegistry_.visit(surfaceId, [=](const ShadowTree &shadowTree) { - return shadowTree.tryCommit( - [&](const SharedRootShadowNode &oldRootShadowNode) { + uiManager_->getShadowTreeRegistry().visit( + surfaceId, [=](const ShadowTree &shadowTree) { + return shadowTree.tryCommit([&](const SharedRootShadowNode + &oldRootShadowNode) { return std::make_shared( *oldRootShadowNode, ShadowNodeFragment{ @@ -139,7 +140,7 @@ void Scheduler::renderTemplateToSurface( SharedShadowNodeList{tree}), }); }); - }); + }); } catch (const std::exception &e) { LOG(ERROR) << " >>>> EXCEPTION <<< rendering uiTemplate in " << "Scheduler::renderTemplateToSurface: " << e.what(); @@ -149,10 +150,11 @@ void Scheduler::renderTemplateToSurface( void Scheduler::stopSurface(SurfaceId surfaceId) const { SystraceSection s("Scheduler::stopSurface"); - shadowTreeRegistry_.visit(surfaceId, [](const ShadowTree &shadowTree) { - // As part of stopping the Surface, we have to commit an empty tree. - return shadowTree.tryCommit( - [&](const SharedRootShadowNode &oldRootShadowNode) { + uiManager_->getShadowTreeRegistry().visit( + surfaceId, [](const ShadowTree &shadowTree) { + // As part of stopping the Surface, we have to commit an empty tree. + return shadowTree.tryCommit([&](const SharedRootShadowNode + &oldRootShadowNode) { return std::make_shared( *oldRootShadowNode, ShadowNodeFragment{ @@ -166,9 +168,9 @@ void Scheduler::stopSurface(SurfaceId surfaceId) const { ShadowNode::emptySharedShadowNodeSharedList(), }); }); - }); + }); - auto shadowTree = shadowTreeRegistry_.remove(surfaceId); + auto shadowTree = uiManager_->getShadowTreeRegistry().remove(surfaceId); shadowTree->setDelegate(nullptr); auto uiManager = uiManager_; @@ -186,15 +188,17 @@ Size Scheduler::measureSurface( SystraceSection s("Scheduler::measureSurface"); Size size; - shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) { - shadowTree.tryCommit([&](const SharedRootShadowNode &oldRootShadowNode) { - auto rootShadowNode = - oldRootShadowNode->clone(layoutConstraints, layoutContext); - rootShadowNode->layout(); - size = rootShadowNode->getLayoutMetrics().frame.size; - return nullptr; - }); - }); + uiManager_->getShadowTreeRegistry().visit( + surfaceId, [&](const ShadowTree &shadowTree) { + shadowTree.tryCommit( + [&](const SharedRootShadowNode &oldRootShadowNode) { + auto rootShadowNode = + oldRootShadowNode->clone(layoutConstraints, layoutContext); + rootShadowNode->layout(); + size = rootShadowNode->getLayoutMetrics().frame.size; + return nullptr; + }); + }); return size; } @@ -204,11 +208,12 @@ void Scheduler::constraintSurfaceLayout( const LayoutContext &layoutContext) const { SystraceSection s("Scheduler::constraintSurfaceLayout"); - shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) { - shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { - return oldRootShadowNode->clone(layoutConstraints, layoutContext); - }); - }); + uiManager_->getShadowTreeRegistry().visit( + surfaceId, [&](const ShadowTree &shadowTree) { + shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { + return oldRootShadowNode->clone(layoutConstraints, layoutContext); + }); + }); } const ComponentDescriptor &Scheduler::getComponentDescriptor( @@ -245,20 +250,21 @@ void Scheduler::uiManagerDidFinishTransaction( const SharedShadowNodeUnsharedList &rootChildNodes) { SystraceSection s("Scheduler::uiManagerDidFinishTransaction"); - shadowTreeRegistry_.visit(surfaceId, [&](const ShadowTree &shadowTree) { - shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { - return std::make_shared( - *oldRootShadowNode, - ShadowNodeFragment{ - /* .tag = */ ShadowNodeFragment::tagPlaceholder(), - /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), - /* .props = */ ShadowNodeFragment::propsPlaceholder(), - /* .eventEmitter = */ - ShadowNodeFragment::eventEmitterPlaceholder(), - /* .children = */ rootChildNodes, - }); - }); - }); + uiManager_->getShadowTreeRegistry().visit( + surfaceId, [&](const ShadowTree &shadowTree) { + shadowTree.commit([&](const SharedRootShadowNode &oldRootShadowNode) { + return std::make_shared( + *oldRootShadowNode, + ShadowNodeFragment{ + /* .tag = */ ShadowNodeFragment::tagPlaceholder(), + /* .surfaceId = */ ShadowNodeFragment::surfaceIdPlaceholder(), + /* .props = */ ShadowNodeFragment::propsPlaceholder(), + /* .eventEmitter = */ + ShadowNodeFragment::eventEmitterPlaceholder(), + /* .children = */ rootChildNodes, + }); + }); + }); } void Scheduler::uiManagerDidCreateShadowNode( diff --git a/ReactCommon/fabric/uimanager/Scheduler.h b/ReactCommon/fabric/uimanager/Scheduler.h index 43fccd7aabf41a..5ab8f21145ce4c 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.h +++ b/ReactCommon/fabric/uimanager/Scheduler.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/ReactCommon/fabric/uimanager/UIManager.cpp b/ReactCommon/fabric/uimanager/UIManager.cpp index b38e1e5ab5f824..ee0e812eb5ae8e 100644 --- a/ReactCommon/fabric/uimanager/UIManager.cpp +++ b/ReactCommon/fabric/uimanager/UIManager.cpp @@ -119,7 +119,7 @@ void UIManager::setNativeProps( /* .props = */ props, }); - shadowTreeRegistry_->visit( + shadowTreeRegistry_.visit( shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) { shadowTree.tryCommit( [&](const SharedRootShadowNode &oldRootShadowNode) { @@ -134,7 +134,7 @@ LayoutMetrics UIManager::getRelativeLayoutMetrics( SystraceSection s("UIManager::getRelativeLayoutMetrics"); if (!ancestorShadowNode) { - shadowTreeRegistry_->visit( + shadowTreeRegistry_.visit( shadowNode.getSurfaceId(), [&](const ShadowTree &shadowTree) { shadowTree.tryCommit( [&](const SharedRootShadowNode &oldRootShadowNode) { @@ -173,7 +173,7 @@ void UIManager::updateState( /* .state = */ state, }); - shadowTreeRegistry_->visit( + shadowTreeRegistry_.visit( shadowNode->getSurfaceId(), [&](const ShadowTree &shadowTree) { shadowTree.tryCommit( [&](const SharedRootShadowNode &oldRootShadowNode) { @@ -191,10 +191,6 @@ void UIManager::dispatchCommand( } } -void UIManager::setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry) { - shadowTreeRegistry_ = shadowTreeRegistry; -} - void UIManager::setComponentDescriptorRegistry( const SharedComponentDescriptorRegistry &componentDescriptorRegistry) { componentDescriptorRegistry_ = componentDescriptorRegistry; @@ -218,5 +214,9 @@ void UIManager::visitBinding( callback(*uiManagerBinding_); } +ShadowTreeRegistry const &UIManager::getShadowTreeRegistry() const { + return shadowTreeRegistry_; +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/uimanager/UIManager.h b/ReactCommon/fabric/uimanager/UIManager.h index 124cb262d7ace1..5ba848f87ce9c0 100644 --- a/ReactCommon/fabric/uimanager/UIManager.h +++ b/ReactCommon/fabric/uimanager/UIManager.h @@ -19,7 +19,6 @@ class UIManagerBinding; class UIManager { public: - void setShadowTreeRegistry(ShadowTreeRegistry *shadowTreeRegistry); void setComponentDescriptorRegistry( const SharedComponentDescriptorRegistry &componentDescriptorRegistry); @@ -98,10 +97,12 @@ class UIManager { std::string const &commandName, folly::dynamic const args) const; - ShadowTreeRegistry *shadowTreeRegistry_; + ShadowTreeRegistry const &getShadowTreeRegistry() const; + SharedComponentDescriptorRegistry componentDescriptorRegistry_; UIManagerDelegate *delegate_; UIManagerBinding *uiManagerBinding_; + ShadowTreeRegistry shadowTreeRegistry_{}; }; } // namespace react diff --git a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp index 00de25f8654faf..6af3dfccea9830 100644 --- a/ReactCommon/fabric/uimanager/UIManagerBinding.cpp +++ b/ReactCommon/fabric/uimanager/UIManagerBinding.cpp @@ -148,7 +148,6 @@ void UIManagerBinding::dispatchEvent( } void UIManagerBinding::invalidate() const { - uiManager_->setShadowTreeRegistry(nullptr); uiManager_->setDelegate(nullptr); } From c80192c2ab6ab642ba64be86071711894f263090 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 30 Aug 2019 18:21:59 -0700 Subject: [PATCH 0092/1244] Fabric: EventBeat::Owner to help with crashes Summary: The purpose of `EventBeat` is handling an asynchronous callback to itself which is being delivered on some different thread. That brings a challenge of ensuring that the `EventBeat` object stays valid during the timeframe of callback execution. The concept of Owner helps with that. The owner is a shared pointer that retains (probably indirectly) the `EventBeat` object. To ensure the correctness of the call, `EventBeat` retains the owner (practically creating a retain cycle) during executing the callback. In case if the pointer to the owner already null, `EventBeat` skips executing the callback. It's impossible to retain itself directly or refer to the shared pointer to itself from a constructor. `OwnerBox` is designed to work around this issue; it allows to store the pointer later, right after the creation of some other object that owns an `EventBeat`. Reviewed By: JoshuaGross Differential Revision: D17128549 fbshipit-source-id: 7ed34fd865430975157fd362f51c4a3d64214430 --- React/Fabric/RCTSurfacePresenter.mm | 8 ++--- React/Fabric/Utils/MainRunLoopEventBeat.h | 4 ++- React/Fabric/Utils/MainRunLoopEventBeat.mm | 10 ++++-- React/Fabric/Utils/RuntimeEventBeat.h | 4 ++- React/Fabric/Utils/RuntimeEventBeat.mm | 10 ++++-- .../react/fabric/jni/AsyncEventBeat.h | 2 ++ .../com/facebook/react/fabric/jni/Binding.cpp | 12 +++---- ReactCommon/fabric/core/events/EventBeat.cpp | 2 ++ ReactCommon/fabric/core/events/EventBeat.h | 31 +++++++++++++++++-- .../fabric/core/events/EventDispatcher.cpp | 19 ++++++------ .../fabric/core/events/EventDispatcher.h | 17 +++++----- ReactCommon/fabric/uimanager/Scheduler.cpp | 13 ++++---- .../fabric/uimanager/SchedulerToolbox.h | 4 +-- 13 files changed, 91 insertions(+), 45 deletions(-) diff --git a/React/Fabric/RCTSurfacePresenter.mm b/React/Fabric/RCTSurfacePresenter.mm index c3a1823b53d9f3..87a078abe88913 100644 --- a/React/Fabric/RCTSurfacePresenter.mm +++ b/React/Fabric/RCTSurfacePresenter.mm @@ -208,12 +208,12 @@ - (RCTScheduler *)_scheduler toolbox.componentRegistryFactory = componentRegistryFactory; toolbox.runtimeExecutor = runtimeExecutor; - toolbox.synchronousEventBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); + toolbox.synchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) { + return std::make_unique(ownerBox, runtimeExecutor); }; - toolbox.asynchronousEventBeatFactory = [runtimeExecutor]() { - return std::make_unique(runtimeExecutor); + toolbox.asynchronousEventBeatFactory = [runtimeExecutor](EventBeat::SharedOwnerBox const &ownerBox) { + return std::make_unique(ownerBox, runtimeExecutor); }; _scheduler = [[RCTScheduler alloc] initWithToolbox:toolbox]; diff --git a/React/Fabric/Utils/MainRunLoopEventBeat.h b/React/Fabric/Utils/MainRunLoopEventBeat.h index 8b78ffaa4fd577..49eb4cb863e909 100644 --- a/React/Fabric/Utils/MainRunLoopEventBeat.h +++ b/React/Fabric/Utils/MainRunLoopEventBeat.h @@ -19,7 +19,9 @@ namespace react { */ class MainRunLoopEventBeat final : public EventBeat { public: - MainRunLoopEventBeat(RuntimeExecutor runtimeExecutor); + MainRunLoopEventBeat( + EventBeat::SharedOwnerBox const &ownerBox, + RuntimeExecutor runtimeExecutor); ~MainRunLoopEventBeat(); void induce() const override; diff --git a/React/Fabric/Utils/MainRunLoopEventBeat.mm b/React/Fabric/Utils/MainRunLoopEventBeat.mm index 1585e28a2a53b5..2e158a6b5b3995 100644 --- a/React/Fabric/Utils/MainRunLoopEventBeat.mm +++ b/React/Fabric/Utils/MainRunLoopEventBeat.mm @@ -11,8 +11,8 @@ namespace facebook { namespace react { -MainRunLoopEventBeat::MainRunLoopEventBeat(RuntimeExecutor runtimeExecutor) - : runtimeExecutor_(std::move(runtimeExecutor)) +MainRunLoopEventBeat::MainRunLoopEventBeat(EventBeat::SharedOwnerBox const &ownerBox, RuntimeExecutor runtimeExecutor) + : EventBeat(ownerBox), runtimeExecutor_(std::move(runtimeExecutor)) { mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler( NULL /* allocator */, @@ -51,9 +51,13 @@ void MainRunLoopEventBeat::lockExecutorAndBeat() const { + auto owner = ownerBox_->owner.lock(); + if (!owner) { + return; + } + // Note: We need the third mutex to get back to the main thread before // the lambda is finished (because all mutexes are allocated on the stack). - std::mutex mutex1; std::mutex mutex2; std::mutex mutex3; diff --git a/React/Fabric/Utils/RuntimeEventBeat.h b/React/Fabric/Utils/RuntimeEventBeat.h index 67ba74fdb597e3..446b798351de58 100644 --- a/React/Fabric/Utils/RuntimeEventBeat.h +++ b/React/Fabric/Utils/RuntimeEventBeat.h @@ -20,7 +20,9 @@ namespace react { */ class RuntimeEventBeat : public EventBeat { public: - RuntimeEventBeat(RuntimeExecutor runtimeExecutor); + RuntimeEventBeat( + EventBeat::SharedOwnerBox const &ownerBox, + RuntimeExecutor runtimeExecutor); ~RuntimeEventBeat(); void induce() const override; diff --git a/React/Fabric/Utils/RuntimeEventBeat.mm b/React/Fabric/Utils/RuntimeEventBeat.mm index 77b6b14415be6b..3adb4d6a2c3472 100644 --- a/React/Fabric/Utils/RuntimeEventBeat.mm +++ b/React/Fabric/Utils/RuntimeEventBeat.mm @@ -10,7 +10,8 @@ namespace facebook { namespace react { -RuntimeEventBeat::RuntimeEventBeat(RuntimeExecutor runtimeExecutor) : runtimeExecutor_(std::move(runtimeExecutor)) +RuntimeEventBeat::RuntimeEventBeat(EventBeat::SharedOwnerBox const &ownerBox, RuntimeExecutor runtimeExecutor) + : EventBeat(ownerBox), runtimeExecutor_(std::move(runtimeExecutor)) { mainRunLoopObserver_ = CFRunLoopObserverCreateWithHandler( NULL /* allocator */, @@ -41,7 +42,12 @@ } isBusy_ = true; - runtimeExecutor_([=](jsi::Runtime &runtime) mutable { + runtimeExecutor_([this, ownerBox = ownerBox_](jsi::Runtime &runtime) mutable { + auto owner = ownerBox->owner.lock(); + if (!owner) { + return; + } + this->beat(runtime); isBusy_ = false; }); diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h index cdd78cfb2e105f..b0811831704d51 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeat.h @@ -25,9 +25,11 @@ class AsyncEventBeat : public EventBeat { friend class EventBeatManager; AsyncEventBeat( + EventBeat::SharedOwnerBox const &ownerBox, EventBeatManager* eventBeatManager, RuntimeExecutor runtimeExecutor, jni::global_ref javaUIManager) : + EventBeat(ownerBox), eventBeatManager_(eventBeatManager), runtimeExecutor_(std::move(runtimeExecutor)), javaUIManager_(javaUIManager) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 2a7dfede65ab1d..a3ca8d369b3cee 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -206,16 +206,16 @@ void Binding::installFabricUIManager( // TODO: T31905686 Create synchronous Event Beat jni::global_ref localJavaUIManager = javaUIManager_; - EventBeatFactory synchronousBeatFactory = - [eventBeatManager, runtimeExecutor, localJavaUIManager]() { + EventBeat::Factory synchronousBeatFactory = + [eventBeatManager, runtimeExecutor, localJavaUIManager](EventBeat::SharedOwnerBox const &ownerBox) { return std::make_unique( - eventBeatManager, runtimeExecutor, localJavaUIManager); + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); }; - EventBeatFactory asynchronousBeatFactory = - [eventBeatManager, runtimeExecutor, localJavaUIManager]() { + EventBeat::Factory asynchronousBeatFactory = + [eventBeatManager, runtimeExecutor, localJavaUIManager](EventBeat::SharedOwnerBox const &ownerBox) { return std::make_unique( - eventBeatManager, runtimeExecutor, localJavaUIManager); + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); }; std::shared_ptr config = diff --git a/ReactCommon/fabric/core/events/EventBeat.cpp b/ReactCommon/fabric/core/events/EventBeat.cpp index d16cfa36c751b6..c99c56964733db 100644 --- a/ReactCommon/fabric/core/events/EventBeat.cpp +++ b/ReactCommon/fabric/core/events/EventBeat.cpp @@ -10,6 +10,8 @@ namespace facebook { namespace react { +EventBeat::EventBeat(SharedOwnerBox const &ownerBox) : ownerBox_(ownerBox) {} + void EventBeat::request() const { isRequested_ = true; } diff --git a/ReactCommon/fabric/core/events/EventBeat.h b/ReactCommon/fabric/core/events/EventBeat.h index f0c88f15d04b32..13ffb90c31eb6e 100644 --- a/ReactCommon/fabric/core/events/EventBeat.h +++ b/ReactCommon/fabric/core/events/EventBeat.h @@ -21,10 +21,36 @@ namespace react { */ class EventBeat { public: - virtual ~EventBeat() = default; + /* + * The concept of `Owner` + * The purpose of `EventBeat` is handling an asynchronous callback to itself + * which is being delivered on some different thread. That brings a challenge + * of ensuring that the `EventBeat` object stays valid during the timeframe of + * callback execution. The concept of Owner helps with that. The owner is a + * shared pointer that retains (probably indirectly) the `EventBeat` object. + * To ensure the correctness of the call, `EventBeat` retains the owner + * (practically creating a retain cycle) during executing the callback. In + * case if the pointer to the owner already null, `EventBeat` skips executing + * the callback. It's impossible to retain itself directly or refer to the + * shared pointer to itself from a constructor. `OwnerBox` is designed to work + * around this issue; it allows to store the pointer later, right after the + * creation of some other object that owns an `EventBeat`. + */ + using Owner = std::weak_ptr; + struct OwnerBox { + Owner owner; + }; + using SharedOwnerBox = std::shared_ptr; + + using Factory = + std::function(SharedOwnerBox const &ownerBox)>; using BeatCallback = std::function; + EventBeat(SharedOwnerBox const &ownerBox); + + virtual ~EventBeat() = default; + /* * Communicates to the Beat that a consumer is waiting for the coming beat. * A consumer must request coming beat after the previous beat happened @@ -57,10 +83,9 @@ class EventBeat { protected: BeatCallback beatCallback_; + SharedOwnerBox ownerBox_; mutable std::atomic isRequested_{false}; }; -using EventBeatFactory = std::function()>; - } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/core/events/EventDispatcher.cpp b/ReactCommon/fabric/core/events/EventDispatcher.cpp index 00c7dbd5a3214b..9edafb7c0917d1 100644 --- a/ReactCommon/fabric/core/events/EventDispatcher.cpp +++ b/ReactCommon/fabric/core/events/EventDispatcher.cpp @@ -19,33 +19,34 @@ namespace facebook { namespace react { EventDispatcher::EventDispatcher( - const EventPipe &eventPipe, - const StatePipe &statePipe, - const EventBeatFactory &synchonousEventBeatFactory, - const EventBeatFactory &asynchonousEventBeatFactory) { + EventPipe const &eventPipe, + StatePipe const &statePipe, + EventBeat::Factory const &synchonousEventBeatFactory, + EventBeat::Factory const &asynchonousEventBeatFactory, + EventBeat::SharedOwnerBox const &ownerBox) { // Synchronous/Unbatched eventQueues_[(int)EventPriority::SynchronousUnbatched] = std::make_unique( - eventPipe, statePipe, synchonousEventBeatFactory()); + eventPipe, statePipe, synchonousEventBeatFactory(ownerBox)); // Synchronous/Batched eventQueues_[(int)EventPriority::SynchronousBatched] = std::make_unique( - eventPipe, statePipe, synchonousEventBeatFactory()); + eventPipe, statePipe, synchonousEventBeatFactory(ownerBox)); // Asynchronous/Unbatched eventQueues_[(int)EventPriority::AsynchronousUnbatched] = std::make_unique( - eventPipe, statePipe, asynchonousEventBeatFactory()); + eventPipe, statePipe, asynchonousEventBeatFactory(ownerBox)); // Asynchronous/Batched eventQueues_[(int)EventPriority::AsynchronousBatched] = std::make_unique( - eventPipe, statePipe, asynchonousEventBeatFactory()); + eventPipe, statePipe, asynchonousEventBeatFactory(ownerBox)); } void EventDispatcher::dispatchEvent( - const RawEvent &rawEvent, + RawEvent const &rawEvent, EventPriority priority) const { getEventQueue(priority).enqueueEvent(std::move(rawEvent)); } diff --git a/ReactCommon/fabric/core/events/EventDispatcher.h b/ReactCommon/fabric/core/events/EventDispatcher.h index 026ed66b68e69f..b07738cb543444 100644 --- a/ReactCommon/fabric/core/events/EventDispatcher.h +++ b/ReactCommon/fabric/core/events/EventDispatcher.h @@ -27,19 +27,20 @@ class StateUpdate; */ class EventDispatcher { public: - using Shared = std::shared_ptr; - using Weak = std::weak_ptr; + using Shared = std::shared_ptr; + using Weak = std::weak_ptr; EventDispatcher( - const EventPipe &eventPipe, - const StatePipe &statePipe, - const EventBeatFactory &synchonousEventBeatFactory, - const EventBeatFactory &asynchonousEventBeatFactory); + EventPipe const &eventPipe, + StatePipe const &statePipe, + EventBeat::Factory const &synchonousEventBeatFactory, + EventBeat::Factory const &asynchonousEventBeatFactory, + EventBeat::SharedOwnerBox const &ownerBox); /* * Dispatches a raw event with given priority using event-delivery pipe. */ - void dispatchEvent(const RawEvent &rawEvent, EventPriority priority) const; + void dispatchEvent(RawEvent const &rawEvent, EventPriority priority) const; /* * Dispatches a state update with given priority. @@ -48,7 +49,7 @@ class EventDispatcher { const; private: - const EventQueue &getEventQueue(EventPriority priority) const; + EventQueue const &getEventQueue(EventPriority priority) const; std::array, 4> eventQueues_; }; diff --git a/ReactCommon/fabric/uimanager/Scheduler.cpp b/ReactCommon/fabric/uimanager/Scheduler.cpp index f52e1e9328728a..139ec13c147b03 100644 --- a/ReactCommon/fabric/uimanager/Scheduler.cpp +++ b/ReactCommon/fabric/uimanager/Scheduler.cpp @@ -28,6 +28,7 @@ Scheduler::Scheduler( ->at>("ReactNativeConfig"); auto uiManager = std::make_shared(); + auto eventOwnerBox = std::make_shared(); auto eventPipe = [=](jsi::Runtime &runtime, const EventTarget *eventTarget, @@ -45,19 +46,20 @@ Scheduler::Scheduler( stateTarget.getShadowNode().shared_from_this(), data); }; - auto eventDispatcher = std::make_shared( + eventDispatcher_ = std::make_shared( eventPipe, statePipe, schedulerToolbox.synchronousEventBeatFactory, - schedulerToolbox.asynchronousEventBeatFactory); + schedulerToolbox.asynchronousEventBeatFactory, + eventOwnerBox); - eventDispatcher_ = eventDispatcher; + eventOwnerBox->owner = eventDispatcher_; componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory( - eventDispatcher, schedulerToolbox.contextContainer); + eventDispatcher_, schedulerToolbox.contextContainer); rootComponentDescriptor_ = - std::make_unique(eventDispatcher); + std::make_unique(eventDispatcher_); uiManager->setDelegate(this); uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_); @@ -73,7 +75,6 @@ Scheduler::Scheduler( componentDescriptorRegistry_)); delegate_ = delegate; - eventDispatcher_ = eventDispatcher; uiManager_ = uiManager; } diff --git a/ReactCommon/fabric/uimanager/SchedulerToolbox.h b/ReactCommon/fabric/uimanager/SchedulerToolbox.h index 9505572229db7f..bb4d868f0039e7 100644 --- a/ReactCommon/fabric/uimanager/SchedulerToolbox.h +++ b/ReactCommon/fabric/uimanager/SchedulerToolbox.h @@ -39,8 +39,8 @@ struct SchedulerToolbox final { * Represent connections with the platform-specific run loops and general * purpose background queue. */ - EventBeatFactory asynchronousEventBeatFactory; - EventBeatFactory synchronousEventBeatFactory; + EventBeat::Factory asynchronousEventBeatFactory; + EventBeat::Factory synchronousEventBeatFactory; }; } // namespace react From 898124541c314e77ea80a229f4630a0e8fd1fdd4 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 30 Aug 2019 19:02:33 -0700 Subject: [PATCH 0093/1244] Support `sendAccessibilityEvent` in Fabric Summary: Support for `sendAccessibilityEvent` in the FabricUIManager. Reviewed By: shergin Differential Revision: D17142507 fbshipit-source-id: 5c131d7caa1e4189fd41ecfb558d0027394b6a15 --- .../com/facebook/react/bridge/UIManager.java | 8 +++++ .../react/fabric/FabricUIManager.java | 8 +++++ .../fabric/mounting/MountingManager.java | 14 +++++++++ .../mountitems/SendAccessibilityEvent.java | 30 +++++++++++++++++++ .../react/uimanager/UIManagerModule.java | 9 +++++- 5 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/SendAccessibilityEvent.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java index b1c51c6ed7353d..2b6fb107efd562 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/UIManager.java @@ -53,4 +53,12 @@ int addRootView( * @param props {@link ReadableMap} props that should be immediately updated in view */ void synchronouslyUpdateViewOnUIThread(int reactTag, ReadableMap props); + + /** + * Dispatch an accessibility event to a view asynchronously. + * + * @param reactTag + * @param eventType + */ + void sendAccessibilityEvent(int reactTag, int eventType); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index 2bfa8d17798bbb..0e278e9003fbef 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -51,6 +51,7 @@ import com.facebook.react.fabric.mounting.mountitems.MountItem; import com.facebook.react.fabric.mounting.mountitems.PreAllocateViewMountItem; import com.facebook.react.fabric.mounting.mountitems.RemoveMountItem; +import com.facebook.react.fabric.mounting.mountitems.SendAccessibilityEvent; import com.facebook.react.fabric.mounting.mountitems.UpdateEventEmitterMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLayoutMountItem; import com.facebook.react.fabric.mounting.mountitems.UpdateLocalDataMountItem; @@ -566,6 +567,13 @@ public void dispatchCommand( } } + @Override + public void sendAccessibilityEvent(int reactTag, int eventType) { + synchronized (mMountItemsLock) { + mMountItems.add(new SendAccessibilityEvent(reactTag, eventType)); + } + } + /** * Set the JS responder for the view associated with the tags received as a parameter. * diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java index f48548fbe1d653..5c668434c6076f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java @@ -143,6 +143,20 @@ public void receiveCommand(int reactTag, String commandId, @Nullable ReadableArr viewState.mViewManager.receiveCommand(viewState.mView, commandId, commandArgs); } + public void sendAccessibilityEvent(int reactTag, int eventType) { + ViewState viewState = getViewState(reactTag); + + if (viewState.mViewManager == null) { + throw new IllegalStateException("Unable to find viewState manager for tag " + reactTag); + } + + if (viewState.mView == null) { + throw new IllegalStateException("Unable to find viewState view for tag " + reactTag); + } + + viewState.mView.sendAccessibilityEvent(eventType); + } + @SuppressWarnings("unchecked") // prevents unchecked conversion warn of the type private static ViewGroupManager getViewGroupManager(ViewState viewState) { if (viewState.mViewManager == null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/SendAccessibilityEvent.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/SendAccessibilityEvent.java new file mode 100644 index 00000000000000..633d1095a8090d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/SendAccessibilityEvent.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.facebook.react.fabric.mounting.mountitems; + +import com.facebook.react.fabric.mounting.MountingManager; + +public class SendAccessibilityEvent implements MountItem { + + private final int mReactTag; + private final int mEventType; + + public SendAccessibilityEvent(int reactTag, int eventType) { + mReactTag = reactTag; + mEventType = eventType; + } + + @Override + public void execute(MountingManager mountingManager) { + mountingManager.sendAccessibilityEvent(mReactTag, mEventType); + } + + @Override + public String toString() { + return "SendAccessibilityEvent [" + mReactTag + "] " + mEventType; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index 1668f11d01958d..db8f05286f2670 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -796,7 +796,14 @@ public EventDispatcher getEventDispatcher() { @ReactMethod public void sendAccessibilityEvent(int tag, int eventType) { - mUIImplementation.sendAccessibilityEvent(tag, eventType); + int uiManagerType = ViewUtil.getUIManagerType(tag); + if (uiManagerType == FABRIC) { + UIManager fabricUIManager = + UIManagerHelper.getUIManager(getReactApplicationContext(), uiManagerType); + fabricUIManager.sendAccessibilityEvent(tag, eventType); + } else { + mUIImplementation.sendAccessibilityEvent(tag, eventType); + } } /** From 5abe5843e2b659ed21ca87abfa5b549394a1ca0e Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 30 Aug 2019 19:02:33 -0700 Subject: [PATCH 0094/1244] Add C++ AndroidTextInput component for backwards-compatible Fabric support of TextInput on Android Summary: Support existing, backwards-compatible AndroidTextInput component for minimal support of TextInput on Android. Reviewed By: shergin, mdvacca Differential Revision: D17086758 fbshipit-source-id: 25726f22229e0d5dfe96eb36b386a5317601283d --- .../textinput/ReactTextInputManager.java | 21 + .../components/slider/SliderShadowNode.cpp | 3 +- .../text/basetext/BaseTextShadowNode.cpp | 2 +- .../text/basetext/BaseTextShadowNode.h | 8 +- ReactCommon/fabric/components/textinput/BUCK | 98 +++++ .../AndroidTextInputComponentDescriptor.h | 46 +++ .../AndroidTextInputEventEmitter.cpp | 179 ++++++++ .../AndroidTextInputEventEmitter.h | 148 +++++++ .../AndroidTextInputProps.cpp | 383 ++++++++++++++++++ .../androidtextinput/AndroidTextInputProps.h | 163 ++++++++ .../AndroidTextInputShadowNode.cpp | 102 +++++ .../AndroidTextInputShadowNode.h | 50 +++ .../view/yoga/YogaLayoutableShadowNode.cpp | 2 + 13 files changed, 1200 insertions(+), 5 deletions(-) create mode 100644 ReactCommon/fabric/components/textinput/BUCK create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.cpp create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.h create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.cpp create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.h create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp create mode 100644 ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 11b4d950d8ee35..d1b76b9f27261d 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -6,6 +6,7 @@ */ package com.facebook.react.views.textinput; +import android.content.Context; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -20,6 +21,7 @@ import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.EditText; import android.widget.TextView; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; @@ -29,6 +31,7 @@ import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableType; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; @@ -50,7 +53,9 @@ import com.facebook.react.views.text.ReactFontManager; import com.facebook.react.views.text.ReactTextUpdate; import com.facebook.react.views.text.TextInlineImageSpan; +import com.facebook.react.views.text.TextLayoutManager; import com.facebook.yoga.YogaConstants; +import com.facebook.yoga.YogaMeasureMode; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.Map; @@ -91,6 +96,8 @@ public class ReactTextInputManager extends BaseViewManager -#include #include namespace facebook { diff --git a/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.cpp b/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.cpp index c7443aead7c020..5034d201988fdd 100644 --- a/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.cpp +++ b/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.cpp @@ -19,7 +19,7 @@ namespace react { AttributedString BaseTextShadowNode::getAttributedString( const TextAttributes &textAttributes, - const SharedShadowNode &parentNode) const { + const SharedShadowNode &parentNode) { auto attributedString = AttributedString{}; for (const auto &childNode : parentNode->getChildren()) { diff --git a/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.h b/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.h index 7da118643cd004..2f1862751c2ff9 100644 --- a/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.h +++ b/ReactCommon/fabric/components/text/basetext/BaseTextShadowNode.h @@ -21,10 +21,14 @@ class BaseTextShadowNode { public: /* * Returns a `AttributedString` which represents text content of the node. + * This is static so that both Paragraph (which subclasses BaseText) and + * TextInput (which does not) can use this. + * TODO T53299884: decide if this should be moved out and made a static + * function, or if TextInput should inherit from BaseTextShadowNode. */ - AttributedString getAttributedString( + static AttributedString getAttributedString( const TextAttributes &baseTextAttributes, - const SharedShadowNode &parentNode) const; + const SharedShadowNode &parentNode); }; } // namespace react diff --git a/ReactCommon/fabric/components/textinput/BUCK b/ReactCommon/fabric/components/textinput/BUCK new file mode 100644 index 00000000000000..1494bfdc7d1beb --- /dev/null +++ b/ReactCommon/fabric/components/textinput/BUCK @@ -0,0 +1,98 @@ +load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_debug_preprocessor_flags") +load( + "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", + "YOGA_CXX_TARGET", + "fb_xplat_cxx_test", + "get_apple_compiler_flags", + "get_apple_inspector_flags", + "react_native_xplat_target", + "rn_xplat_cxx_library", + "subdir_glob", +) + +APPLE_COMPILER_FLAGS = get_apple_compiler_flags() + +rn_xplat_cxx_library( + name = "androidtextinput", + srcs = glob( + ["**/*.cpp"], + exclude = glob(["tests/**/*.cpp"]), + ), + headers = glob( + ["**/*.h"], + exclude = glob(["tests/**/*.h"]), + ), + header_namespace = "", + exported_headers = subdir_glob( + [ + ("", "*.h"), + ("androidtextinput", "*.h"), + ], + prefix = "react/components/androidtextinput", + ), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + cxx_tests = [":tests"], + fbobjc_compiler_flags = APPLE_COMPILER_FLAGS, + fbobjc_preprocessor_flags = get_debug_preprocessor_flags() + get_apple_inspector_flags(), + force_static = True, + platforms = (ANDROID, APPLE, CXX), + preprocessor_flags = [ + "-DLOG_TAG=\"ReactNative\"", + "-DWITH_FBSYSTRACE=1", + ], + visibility = ["PUBLIC"], + deps = [ + "fbsource//xplat/fbsystrace:fbsystrace", + "fbsource//xplat/folly:evicting_cache_map", + "fbsource//xplat/folly:headers_only", + "fbsource//xplat/folly:memory", + "fbsource//xplat/folly:molly", + "fbsource//xplat/third-party/glog:glog", + YOGA_CXX_TARGET, + react_native_xplat_target("utils:utils"), + react_native_xplat_target("fabric/attributedstring:attributedstring"), + react_native_xplat_target("fabric/core:core"), + react_native_xplat_target("fabric/debug:debug"), + react_native_xplat_target("fabric/graphics:graphics"), + react_native_xplat_target("fabric/textlayoutmanager:textlayoutmanager"), + react_native_xplat_target("fabric/components/text:text"), + react_native_xplat_target("fabric/components/view:view"), + react_native_xplat_target("fabric/components/image:image"), + react_native_xplat_target("fabric/uimanager:uimanager"), + react_native_xplat_target("fabric/imagemanager:imagemanager"), + ], +) + +fb_xplat_cxx_test( + name = "tests", + srcs = glob(["tests/**/*.cpp"]), + headers = glob(["tests/**/*.h"]), + compiler_flags = [ + "-fexceptions", + "-frtti", + "-std=c++14", + "-Wall", + ], + contacts = ["oncall+react_native@xmail.facebook.com"], + platforms = ( + # `Apple` and `Android` flavors are disabled because the module depends on `textlayoutmanager` which requires real an Emulator/Simulator to run. + # At the same time, the code of tests does not rely on the simulator capabilities and it would be wasteful to add `fbandroid_use_instrumentation_test = True`. + # (Beware of this option though.) + # ANDROID, + # APPLE, + CXX + ), + deps = [ + "fbsource//xplat/folly:molly", + "fbsource//xplat/third-party/gmock:gtest", + ":androidtextinput", + ], +) diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h new file mode 100644 index 00000000000000..d43edb6217bab8 --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h @@ -0,0 +1,46 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include "AndroidTextInputShadowNode.h" + +namespace facebook { +namespace react { + +/* + * Descriptor for component. + */ +class AndroidTextInputComponentDescriptor final + : public ConcreteComponentDescriptor { + public: + AndroidTextInputComponentDescriptor( + EventDispatcher::Shared eventDispatcher, + const ContextContainer::Shared &contextContainer) + : ConcreteComponentDescriptor( + eventDispatcher, + contextContainer) {} + + protected: + void adopt(UnsharedShadowNode shadowNode) const override { + assert(std::dynamic_pointer_cast(shadowNode)); + auto concreteShadowNode = + std::static_pointer_cast(shadowNode); + + concreteShadowNode->setContextContainer( + const_cast(getContextContainer().get())); + + concreteShadowNode->dirtyLayout(); + concreteShadowNode->enableMeasurement(); + + ConcreteComponentDescriptor::adopt(shadowNode); + } +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.cpp b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.cpp new file mode 100644 index 00000000000000..36959cf022e9bb --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.cpp @@ -0,0 +1,179 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AndroidTextInputEventEmitter.h" + +namespace facebook { +namespace react { + +void AndroidTextInputEventEmitter::onBlur( + AndroidTextInputOnBlurStruct event) const { + dispatchEvent("blur", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} +void AndroidTextInputEventEmitter::onFocus( + AndroidTextInputOnFocusStruct event) const { + dispatchEvent("focus", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + return payload; + }); +} +void AndroidTextInputEventEmitter::onChange( + AndroidTextInputOnChangeStruct event) const { + dispatchEvent("change", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "eventCount", event.eventCount); + payload.setProperty(runtime, "text", event.text); + return payload; + }); +} +void AndroidTextInputEventEmitter::onChangeText( + AndroidTextInputOnChangeTextStruct event) const { + dispatchEvent( + "changeText", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "eventCount", event.eventCount); + payload.setProperty(runtime, "text", event.text); + return payload; + }); +} +void AndroidTextInputEventEmitter::onContentSizeChange( + AndroidTextInputOnContentSizeChangeStruct event) const { + dispatchEvent( + "contentSizeChange", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + { + auto contentSize = jsi::Object(runtime); + contentSize.setProperty(runtime, "width", event.contentSize.width); + contentSize.setProperty(runtime, "height", event.contentSize.height); + + payload.setProperty(runtime, "contentSize", contentSize); + } + return payload; + }); +} +void AndroidTextInputEventEmitter::onTextInput( + AndroidTextInputOnTextInputStruct event) const { + dispatchEvent("textInput", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "text", event.text); + payload.setProperty(runtime, "previousText", event.previousText); + { + auto range = jsi::Object(runtime); + range.setProperty(runtime, "start", event.range.start); + range.setProperty(runtime, "end", event.range.end); + + payload.setProperty(runtime, "range", range); + } + return payload; + }); +} +void AndroidTextInputEventEmitter::onEndEditing( + AndroidTextInputOnEndEditingStruct event) const { + dispatchEvent( + "endEditing", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "text", event.text); + return payload; + }); +} +void AndroidTextInputEventEmitter::onSelectionChange( + AndroidTextInputOnSelectionChangeStruct event) const { + dispatchEvent( + "selectionChange", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + { + auto selection = jsi::Object(runtime); + selection.setProperty(runtime, "start", event.selection.start); + selection.setProperty(runtime, "end", event.selection.end); + + payload.setProperty(runtime, "selection", selection); + } + return payload; + }); +} +void AndroidTextInputEventEmitter::onSubmitEditing( + AndroidTextInputOnSubmitEditingStruct event) const { + dispatchEvent( + "submitEditing", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "text", event.text); + return payload; + }); +} +void AndroidTextInputEventEmitter::onKeyPress( + AndroidTextInputOnKeyPressStruct event) const { + dispatchEvent("keyPress", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty(runtime, "key", event.key); + return payload; + }); +} +void AndroidTextInputEventEmitter::onScroll( + AndroidTextInputOnScrollStruct event) const { + dispatchEvent("scroll", [event = std::move(event)](jsi::Runtime &runtime) { + auto payload = jsi::Object(runtime); + payload.setProperty(runtime, "target", event.target); + payload.setProperty( + runtime, "responderIgnoreScroll", event.responderIgnoreScroll); + { + auto contentInset = jsi::Object(runtime); + contentInset.setProperty(runtime, "top", event.contentInset.top); + contentInset.setProperty(runtime, "bottom", event.contentInset.bottom); + contentInset.setProperty(runtime, "left", event.contentInset.left); + contentInset.setProperty(runtime, "right", event.contentInset.right); + + payload.setProperty(runtime, "contentInset", contentInset); + } + { + auto contentOffset = jsi::Object(runtime); + contentOffset.setProperty(runtime, "x", event.contentOffset.x); + contentOffset.setProperty(runtime, "y", event.contentOffset.y); + + payload.setProperty(runtime, "contentOffset", contentOffset); + } + { + auto contentSize = jsi::Object(runtime); + contentSize.setProperty(runtime, "width", event.contentSize.width); + contentSize.setProperty(runtime, "height", event.contentSize.height); + + payload.setProperty(runtime, "contentSize", contentSize); + } + { + auto layoutMeasurement = jsi::Object(runtime); + layoutMeasurement.setProperty( + runtime, "width", event.layoutMeasurement.width); + layoutMeasurement.setProperty( + runtime, "height", event.layoutMeasurement.height); + + payload.setProperty(runtime, "layoutMeasurement", layoutMeasurement); + } + { + auto velocity = jsi::Object(runtime); + velocity.setProperty(runtime, "x", event.velocity.x); + velocity.setProperty(runtime, "y", event.velocity.y); + + payload.setProperty(runtime, "velocity", velocity); + } + return payload; + }); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.h b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.h new file mode 100644 index 00000000000000..c06df23c96d701 --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputEventEmitter.h @@ -0,0 +1,148 @@ + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +#include + +namespace facebook { +namespace react { + +struct AndroidTextInputOnBlurStruct { + int target; +}; + +struct AndroidTextInputOnFocusStruct { + int target; +}; + +struct AndroidTextInputOnChangeStruct { + int target; + int eventCount; + std::string text; +}; + +struct AndroidTextInputOnChangeTextStruct { + int target; + int eventCount; + std::string text; +}; + +struct AndroidTextInputOnContentSizeChangeContentSizeStruct { + double width; + double height; +}; + +struct AndroidTextInputOnContentSizeChangeStruct { + int target; + AndroidTextInputOnContentSizeChangeContentSizeStruct contentSize; +}; + +struct AndroidTextInputOnTextInputRangeStruct { + double start; + double end; +}; + +struct AndroidTextInputOnTextInputStruct { + int target; + std::string text; + std::string previousText; + AndroidTextInputOnTextInputRangeStruct range; +}; + +struct AndroidTextInputOnEndEditingStruct { + int target; + std::string text; +}; + +struct AndroidTextInputOnSelectionChangeSelectionStruct { + double start; + double end; +}; + +struct AndroidTextInputOnSelectionChangeStruct { + int target; + AndroidTextInputOnSelectionChangeSelectionStruct selection; +}; + +struct AndroidTextInputOnSubmitEditingStruct { + int target; + std::string text; +}; + +struct AndroidTextInputOnKeyPressStruct { + int target; + std::string key; +}; + +struct AndroidTextInputOnScrollContentInsetStruct { + double top; + double bottom; + double left; + double right; +}; + +struct AndroidTextInputOnScrollContentOffsetStruct { + double x; + double y; +}; + +struct AndroidTextInputOnScrollContentSizeStruct { + double width; + double height; +}; + +struct AndroidTextInputOnScrollLayoutMeasurementStruct { + double width; + double height; +}; + +struct AndroidTextInputOnScrollVelocityStruct { + double x; + double y; +}; + +struct AndroidTextInputOnScrollStruct { + int target; + bool responderIgnoreScroll; + AndroidTextInputOnScrollContentInsetStruct contentInset; + AndroidTextInputOnScrollContentOffsetStruct contentOffset; + AndroidTextInputOnScrollContentSizeStruct contentSize; + AndroidTextInputOnScrollLayoutMeasurementStruct layoutMeasurement; + AndroidTextInputOnScrollVelocityStruct velocity; +}; + +class AndroidTextInputEventEmitter : public ViewEventEmitter { + public: + using ViewEventEmitter::ViewEventEmitter; + + void onBlur(AndroidTextInputOnBlurStruct value) const; + + void onFocus(AndroidTextInputOnFocusStruct value) const; + + void onChange(AndroidTextInputOnChangeStruct value) const; + + void onChangeText(AndroidTextInputOnChangeTextStruct value) const; + + void onContentSizeChange( + AndroidTextInputOnContentSizeChangeStruct value) const; + + void onTextInput(AndroidTextInputOnTextInputStruct value) const; + + void onEndEditing(AndroidTextInputOnEndEditingStruct value) const; + + void onSelectionChange(AndroidTextInputOnSelectionChangeStruct value) const; + + void onSubmitEditing(AndroidTextInputOnSubmitEditingStruct value) const; + + void onKeyPress(AndroidTextInputOnKeyPressStruct value) const; + + void onScroll(AndroidTextInputOnScrollStruct value) const; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.cpp b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.cpp new file mode 100644 index 00000000000000..79abf42ad5e610 --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.cpp @@ -0,0 +1,383 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AndroidTextInputProps.h" +#include +#include +#include + +namespace facebook { +namespace react { + +/** + * This was cribbed from BaseTextProps. Maybe we can unify someday. + * TODO: we should probably just move this to BaseTextProps / subclass it + * + * @param rawProps + * @param defaultTextAttributes + * @return + */ +static TextAttributes convertRawProp( + const RawProps &rawProps, + const TextAttributes defaultTextAttributes) { + auto textAttributes = TextAttributes{}; + + // Color + textAttributes.foregroundColor = + convertRawProp(rawProps, "color", defaultTextAttributes.foregroundColor); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.backgroundColor = convertRawProp( + rawProps, "backgroundColor", defaultTextAttributes.backgroundColor); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.opacity = + convertRawProp(rawProps, "opacity", defaultTextAttributes.opacity); + + // Font + textAttributes.fontFamily = + convertRawProp(rawProps, "fontFamily", defaultTextAttributes.fontFamily); + textAttributes.fontSize = + convertRawProp(rawProps, "fontSize", defaultTextAttributes.fontSize); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + // is this maxFontSizeMultiplier? + textAttributes.fontSizeMultiplier = convertRawProp( + rawProps, "fontSizeMultiplier", defaultTextAttributes.fontSizeMultiplier); + textAttributes.fontWeight = + convertRawProp(rawProps, "fontWeight", defaultTextAttributes.fontWeight); + textAttributes.fontStyle = + convertRawProp(rawProps, "fontStyle", defaultTextAttributes.fontStyle); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.fontVariant = convertRawProp( + rawProps, "fontVariant", defaultTextAttributes.fontVariant); + textAttributes.allowFontScaling = convertRawProp( + rawProps, "allowFontScaling", defaultTextAttributes.allowFontScaling); + textAttributes.letterSpacing = convertRawProp( + rawProps, "letterSpacing", defaultTextAttributes.letterSpacing); + + // Paragraph + textAttributes.lineHeight = + convertRawProp(rawProps, "lineHeight", defaultTextAttributes.lineHeight); + textAttributes.alignment = + convertRawProp(rawProps, "textAlign", defaultTextAttributes.alignment); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.baseWritingDirection = convertRawProp( + rawProps, + "baseWritingDirection", + defaultTextAttributes.baseWritingDirection); + + // Decoration + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.textDecorationColor = convertRawProp( + rawProps, + "textDecorationColor", + defaultTextAttributes.textDecorationColor); + textAttributes.textDecorationLineType = convertRawProp( + rawProps, + "textDecorationLine", + defaultTextAttributes.textDecorationLineType); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.textDecorationLineStyle = convertRawProp( + rawProps, + "textDecorationLineStyle", + defaultTextAttributes.textDecorationLineStyle); + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.textDecorationLinePattern = convertRawProp( + rawProps, + "textDecorationLinePattern", + defaultTextAttributes.textDecorationLinePattern); + + // Shadow + textAttributes.textShadowOffset = convertRawProp( + rawProps, "textShadowOffset", defaultTextAttributes.textShadowOffset); + textAttributes.textShadowRadius = convertRawProp( + rawProps, "textShadowRadius", defaultTextAttributes.textShadowRadius); + textAttributes.textShadowColor = convertRawProp( + rawProps, "textShadowColor", defaultTextAttributes.textShadowColor); + + // Special + // Todo T53300333: not found in AndroidTextInput (java) and/or TextInput + textAttributes.isHighlighted = convertRawProp( + rawProps, "isHighlighted", defaultTextAttributes.isHighlighted); + + return textAttributes; +} + +AndroidTextInputProps::AndroidTextInputProps( + const AndroidTextInputProps &sourceProps, + const RawProps &rawProps) + : ViewProps(sourceProps, rawProps), + + autoCompleteType(convertRawProp( + rawProps, + "autoCompleteType", + sourceProps.autoCompleteType, + {})), + returnKeyLabel(convertRawProp( + rawProps, + "returnKeyLabel", + sourceProps.returnKeyLabel, + {})), + numberOfLines(convertRawProp( + rawProps, + "numberOfLines", + sourceProps.numberOfLines, + {0})), + disableFullscreenUI(convertRawProp( + rawProps, + "disableFullscreenUI", + sourceProps.disableFullscreenUI, + {false})), + textBreakStrategy(convertRawProp( + rawProps, + "textBreakStrategy", + sourceProps.textBreakStrategy, + {})), + underlineColorAndroid(convertRawProp( + rawProps, + "underlineColorAndroid", + sourceProps.underlineColorAndroid, + {})), + inlineImageLeft(convertRawProp( + rawProps, + "inlineImageLeft", + sourceProps.inlineImageLeft, + {})), + inlineImagePadding(convertRawProp( + rawProps, + "inlineImagePadding", + sourceProps.inlineImagePadding, + {0})), + importantForAutofill(convertRawProp( + rawProps, + "importantForAutofill", + sourceProps.importantForAutofill, + {})), + showSoftInputOnFocus(convertRawProp( + rawProps, + "showSoftInputOnFocus", + sourceProps.showSoftInputOnFocus, + {false})), + autoCapitalize(convertRawProp( + rawProps, + "autoCapitalize", + sourceProps.autoCapitalize, + {})), + autoCorrect(convertRawProp( + rawProps, + "autoCorrect", + sourceProps.autoCorrect, + {false})), + autoFocus(convertRawProp( + rawProps, + "autoFocus", + sourceProps.autoFocus, + {false})), + allowFontScaling(convertRawProp( + rawProps, + "allowFontScaling", + sourceProps.allowFontScaling, + {false})), + maxFontSizeMultiplier(convertRawProp( + rawProps, + "maxFontSizeMultiplier", + sourceProps.maxFontSizeMultiplier, + {0.0})), + editable( + convertRawProp(rawProps, "editable", sourceProps.editable, {false})), + keyboardType(convertRawProp( + rawProps, + "keyboardType", + sourceProps.keyboardType, + {})), + returnKeyType(convertRawProp( + rawProps, + "returnKeyType", + sourceProps.returnKeyType, + {})), + maxLength( + convertRawProp(rawProps, "maxLength", sourceProps.maxLength, {0})), + multiline(convertRawProp( + rawProps, + "multiline", + sourceProps.multiline, + {false})), + placeholder( + convertRawProp(rawProps, "placeholder", sourceProps.placeholder, {})), + placeholderTextColor(convertRawProp( + rawProps, + "placeholderTextColor", + sourceProps.placeholderTextColor, + {})), + secureTextEntry(convertRawProp( + rawProps, + "secureTextEntry", + sourceProps.secureTextEntry, + {false})), + selectionColor(convertRawProp( + rawProps, + "selectionColor", + sourceProps.selectionColor, + {})), + selection( + convertRawProp(rawProps, "selection", sourceProps.selection, {})), + value(convertRawProp(rawProps, "value", sourceProps.value, {})), + defaultValue(convertRawProp( + rawProps, + "defaultValue", + sourceProps.defaultValue, + {})), + selectTextOnFocus(convertRawProp( + rawProps, + "selectTextOnFocus", + sourceProps.selectTextOnFocus, + {false})), + blurOnSubmit(convertRawProp( + rawProps, + "blurOnSubmit", + sourceProps.blurOnSubmit, + {false})), + caretHidden(convertRawProp( + rawProps, + "caretHidden", + sourceProps.caretHidden, + {false})), + contextMenuHidden(convertRawProp( + rawProps, + "contextMenuHidden", + sourceProps.contextMenuHidden, + {false})), + textShadowColor(convertRawProp( + rawProps, + "textShadowColor", + sourceProps.textShadowColor, + {})), + textShadowRadius(convertRawProp( + rawProps, + "textShadowRadius", + sourceProps.textShadowRadius, + {0.0})), + textDecorationLine(convertRawProp( + rawProps, + "textDecorationLine", + sourceProps.textDecorationLine, + {})), + fontStyle( + convertRawProp(rawProps, "fontStyle", sourceProps.fontStyle, {})), + textShadowOffset(convertRawProp( + rawProps, + "textShadowOffset", + sourceProps.textShadowOffset, + {})), + lineHeight(convertRawProp( + rawProps, + "lineHeight", + sourceProps.lineHeight, + {0.0})), + textTransform(convertRawProp( + rawProps, + "textTransform", + sourceProps.textTransform, + {})), + color(convertRawProp(rawProps, "color", sourceProps.color, {0})), + letterSpacing(convertRawProp( + rawProps, + "letterSpacing", + sourceProps.letterSpacing, + {0.0})), + fontSize( + convertRawProp(rawProps, "fontSize", sourceProps.fontSize, {0.0})), + textAlign( + convertRawProp(rawProps, "textAlign", sourceProps.textAlign, {})), + includeFontPadding(convertRawProp( + rawProps, + "includeFontPadding", + sourceProps.includeFontPadding, + {false})), + fontWeight( + convertRawProp(rawProps, "fontWeight", sourceProps.fontWeight, {})), + fontFamily( + convertRawProp(rawProps, "fontFamily", sourceProps.fontFamily, {})), + textAlignVertical(convertRawProp( + rawProps, + "textAlignVertical", + sourceProps.textAlignVertical, + {})), + cursorColor( + convertRawProp(rawProps, "cursorColor", sourceProps.cursorColor, {})), + mostRecentEventCount(convertRawProp( + rawProps, + "mostRecentEventCount", + sourceProps.mostRecentEventCount, + {0})), + text(convertRawProp(rawProps, "text", sourceProps.text, {})), + textAttributes(convertRawProp(rawProps, sourceProps.textAttributes)) {} + +// TODO T53300085: support this in codegen; this was hand-written +folly::dynamic AndroidTextInputProps::getDynamic() const { + folly::dynamic props = folly::dynamic::object(); + props["autoCompleteType"] = autoCompleteType; + props["returnKeyLabel"] = returnKeyLabel; + props["numberOfLines"] = numberOfLines; + props["disableFullscreenUI"] = disableFullscreenUI; + props["textBreakStrategy"] = textBreakStrategy; + props["underlineColorAndroid"] = toDynamic(underlineColorAndroid); + props["inlineImageLeft"] = inlineImageLeft; + props["inlineImagePadding"] = inlineImagePadding; + props["importantForAutofill"] = importantForAutofill; + props["showSoftInputOnFocus"] = showSoftInputOnFocus; + props["autoCapitalize"] = autoCapitalize; + props["autoCorrect"] = autoCorrect; + props["autoFocus"] = autoFocus; + props["allowFontScaling"] = allowFontScaling; + props["maxFontSizeMultiplier"] = maxFontSizeMultiplier; + props["editable"] = editable; + props["keyboardType"] = keyboardType; + props["returnKeyType"] = returnKeyType; + props["maxLength"] = maxLength; + props["multiline"] = multiline; + props["placeholder"] = placeholder; + props["placeholderTextColor"] = toDynamic(placeholderTextColor); + props["secureTextEntry"] = secureTextEntry; + props["selectionColor"] = toDynamic(selectionColor); + props["selection"] = toDynamic(selection); + props["value"] = value; + props["defaultValue"] = defaultValue; + props["selectTextOnFocus"] = selectTextOnFocus; + props["blurOnSubmit"] = blurOnSubmit; + props["caretHidden"] = caretHidden; + props["contextMenuHidden"] = contextMenuHidden; + props["textShadowColor"] = toDynamic(textShadowColor); + props["textShadowRadius"] = textShadowRadius; + props["textDecorationLine"] = textDecorationLine; + props["fontStyle"] = fontStyle; + props["textShadowOffset"] = toDynamic(textShadowOffset); + props["lineHeight"] = lineHeight; + props["textTransform"] = textTransform; + props["color"] = color; + props["letterSpacing"] = letterSpacing; + props["fontSize"] = fontSize; + props["textAlign"] = textAlign; + props["includeFontPadding"] = includeFontPadding; + props["fontWeight"] = fontWeight; + props["fontFamily"] = fontFamily; + props["textAlignVertical"] = textAlignVertical; + props["cursorColor"] = toDynamic(cursorColor); + props["mostRecentEventCount"] = mostRecentEventCount; + props["text"] = text; + return props; +} + +#pragma mark - DebugStringConvertible + +#if RN_DEBUG_STRING_CONVERTIBLE +// TODO: codegen these +SharedDebugStringConvertibleList TextProps::getDebugProps() const { + return {}; +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.h b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.h new file mode 100644 index 00000000000000..75d45eda8f6b2a --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputProps.h @@ -0,0 +1,163 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +// #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +struct AndroidTextInputSelectionStruct { + int start; + int end; +}; + +static inline void fromRawValue( + const RawValue &value, + AndroidTextInputSelectionStruct &result) { + auto map = (better::map)value; + + auto start = map.find("start"); + if (start != map.end()) { + fromRawValue(start->second, result.start); + } + auto end = map.find("end"); + if (end != map.end()) { + fromRawValue(end->second, result.end); + } +} + +static inline std::string toString( + const AndroidTextInputSelectionStruct &value) { + return "[Object AndroidTextInputSelectionStruct]"; +} + +struct AndroidTextInputTextShadowOffsetStruct { + double width; + double height; +}; + +static inline void fromRawValue( + const RawValue &value, + AndroidTextInputTextShadowOffsetStruct &result) { + auto map = (better::map)value; + + auto width = map.find("width"); + if (width != map.end()) { + fromRawValue(width->second, result.width); + } + auto height = map.find("height"); + if (height != map.end()) { + fromRawValue(height->second, result.height); + } +} + +static inline std::string toString( + const AndroidTextInputTextShadowOffsetStruct &value) { + return "[Object AndroidTextInputTextShadowOffsetStruct]"; +} + +#ifdef ANDROID +inline folly::dynamic toDynamic( + const AndroidTextInputTextShadowOffsetStruct &value) { + folly::dynamic dynamicValue = folly::dynamic::object(); + dynamicValue["width"] = value.width; + dynamicValue["height"] = value.height; + return dynamicValue; +} + +inline folly::dynamic toDynamic(const AndroidTextInputSelectionStruct &value) { + folly::dynamic dynamicValue = folly::dynamic::object(); + dynamicValue["start"] = value.start; + dynamicValue["end"] = value.end; + return dynamicValue; +} +#endif + +class AndroidTextInputProps final : public ViewProps { + public: + AndroidTextInputProps() = default; + AndroidTextInputProps( + const AndroidTextInputProps &sourceProps, + const RawProps &rawProps); + + folly::dynamic getDynamic() const; + +#pragma mark - Props + + const std::string autoCompleteType{}; + const std::string returnKeyLabel{}; + const int numberOfLines{0}; + const bool disableFullscreenUI{false}; + const std::string textBreakStrategy{}; + const SharedColor underlineColorAndroid{}; + const std::string inlineImageLeft{}; + const int inlineImagePadding{0}; + const std::string importantForAutofill{}; + const bool showSoftInputOnFocus{false}; + const std::string autoCapitalize{}; + const bool autoCorrect{false}; + const bool autoFocus{false}; + const bool allowFontScaling{false}; + const Float maxFontSizeMultiplier{0.0}; + const bool editable{false}; + const std::string keyboardType{}; + const std::string returnKeyType{}; + const int maxLength{0}; + const bool multiline{false}; + const std::string placeholder{}; + const SharedColor placeholderTextColor{}; + const bool secureTextEntry{false}; + const SharedColor selectionColor{}; + const AndroidTextInputSelectionStruct selection{}; + const std::string value{}; + const std::string defaultValue{}; + const bool selectTextOnFocus{false}; + const bool blurOnSubmit{false}; + const bool caretHidden{false}; + const bool contextMenuHidden{false}; + const SharedColor textShadowColor{}; + const Float textShadowRadius{0.0}; + const std::string textDecorationLine{}; + const std::string fontStyle{}; + const AndroidTextInputTextShadowOffsetStruct textShadowOffset{}; + const Float lineHeight{0.0}; + const std::string textTransform{}; + const int color{0}; + const Float letterSpacing{0.0}; + const Float fontSize{0.0}; + const std::string textAlign{}; + const bool includeFontPadding{false}; + const std::string fontWeight{}; + const std::string fontFamily{}; + const std::string textAlignVertical{}; + const SharedColor cursorColor{}; + const int mostRecentEventCount{0}; + const std::string text{}; + + /** + * TextAttributes: see all BaseText. These attributes are not set + * directly; see convertRawProps. + */ + const TextAttributes textAttributes{}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp new file mode 100644 index 00000000000000..e2ed08f4917c07 --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp @@ -0,0 +1,102 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AndroidTextInputShadowNode.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace facebook::jni; + +namespace facebook { +namespace react { + +extern const char AndroidTextInputComponentName[] = "AndroidTextInput"; + +void AndroidTextInputShadowNode::setContextContainer( + ContextContainer *contextContainer) { + ensureUnsealed(); + contextContainer_ = contextContainer; +} + +AttributedString AndroidTextInputShadowNode::getAttributedString() const { + auto textAttributes = TextAttributes::defaultTextAttributes(); + textAttributes.apply(getProps()->textAttributes); + + // Use BaseTextShadowNode to get attributed string from children + return BaseTextShadowNode::getAttributedString( + textAttributes, shared_from_this()); +} + +#pragma mark - LayoutableShadowNode + +Size AndroidTextInputShadowNode::measure( + LayoutConstraints layoutConstraints) const { + AttributedString attributedString = getAttributedString(); + + if (attributedString.isEmpty()) { + return {0, 0}; + } + + const jni::global_ref &fabricUIManager = + contextContainer_->at>("FabricUIManager"); + + static auto measure = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("measure"); + + auto minimumSize = layoutConstraints.minimumSize; + auto maximumSize = layoutConstraints.maximumSize; + + local_ref componentName = + make_jstring(AndroidTextInputComponentName); + + local_ref attributedStringRNM = + ReadableNativeMap::newObjectCxxArgs(toDynamic(attributedString)); + local_ref attributedStringRM = make_local( + reinterpret_cast(attributedStringRNM.get())); + + local_ref nativeLocalProps = make_local( + ReadableNativeMap::createWithContents(getProps()->getDynamic())); + local_ref props = make_local( + reinterpret_cast(nativeLocalProps.get())); + + // For AndroidTextInput purposes: + // localData == textAttributes + return yogaMeassureToSize(measure( + fabricUIManager, + componentName.get(), + attributedStringRM.get(), + props.get(), + nullptr, + minimumSize.width, + maximumSize.width, + minimumSize.height, + maximumSize.height)); +} + +void AndroidTextInputShadowNode::layout(LayoutContext layoutContext) { + ConcreteViewShadowNode::layout(layoutContext); +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.h b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.h new file mode 100644 index 00000000000000..995110935b6f38 --- /dev/null +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.h @@ -0,0 +1,50 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include "AndroidTextInputEventEmitter.h" +#include "AndroidTextInputProps.h" + +#include +#include + +#include + +namespace facebook { +namespace react { + +extern const char AndroidTextInputComponentName[]; + +/* + * `ShadowNode` for component. + */ +class AndroidTextInputShadowNode : public ConcreteViewShadowNode< + AndroidTextInputComponentName, + AndroidTextInputProps, + AndroidTextInputEventEmitter> { + public: + using ConcreteViewShadowNode::ConcreteViewShadowNode; + + void setContextContainer(ContextContainer *contextContainer); + + /* + * Returns a `AttributedString` which represents text content of the node. + */ + AttributedString getAttributedString() const; + +#pragma mark - LayoutableShadowNode + + Size measure(LayoutConstraints layoutConstraints) const override; + void layout(LayoutContext layoutContext) override; + + private: + ContextContainer *contextContainer_{}; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp index 62f9596ffc96dc..eabaaedd7d029e 100644 --- a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp @@ -18,6 +18,8 @@ #include #include +#include + namespace facebook { namespace react { From 6c17780a6bf7615d43e00e4e6c8e5fa4ddef0301 Mon Sep 17 00:00:00 2001 From: "--fbcode@fb.com" <--fbcode@fb.com> Date: Fri, 30 Aug 2019 20:08:40 -0700 Subject: [PATCH 0095/1244] Fix compilation error in AndroidTextInputComponentDescriptor Summary: The type is wrong in the constructor. build-break Differential Revision: D17145039 fbshipit-source-id: f6b80e38c05e60f04d029aa34baa0c55c237a39a --- .../androidtextinput/AndroidTextInputComponentDescriptor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h index d43edb6217bab8..0489ae67b83254 100644 --- a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputComponentDescriptor.h @@ -20,7 +20,7 @@ class AndroidTextInputComponentDescriptor final : public ConcreteComponentDescriptor { public: AndroidTextInputComponentDescriptor( - EventDispatcher::Shared eventDispatcher, + EventDispatcher::Weak eventDispatcher, const ContextContainer::Shared &contextContainer) : ConcreteComponentDescriptor( eventDispatcher, From a1ee1d7698081e7882d2fc5f08d848f93623f1c4 Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 30 Aug 2019 22:05:56 -0700 Subject: [PATCH 0096/1244] Unbreak master Summary: Unbreak master. Unused import in prod. Reviewed By: shergin Differential Revision: D17145399 fbshipit-source-id: 24494c713d1712612221bf1c9bd3deafc72267a3 --- .../fabric/components/view/yoga/YogaLayoutableShadowNode.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp index eabaaedd7d029e..62f9596ffc96dc 100644 --- a/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp +++ b/ReactCommon/fabric/components/view/yoga/YogaLayoutableShadowNode.cpp @@ -18,8 +18,6 @@ #include #include -#include - namespace facebook { namespace react { From ba56fa43f0a89a7f2654d6ba9655356bb975f56d Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Fri, 30 Aug 2019 22:38:10 -0700 Subject: [PATCH 0097/1244] Flow type and codegen for AndroidTextInput Summary: Flow type for AndroidTextInput. This could theoretically be used for the interface codegen in the future, and I did use this to codegen the scaffolding for AndroidTextInput (see previous diffs). Reviewed By: mdvacca Differential Revision: D16926831 fbshipit-source-id: d01c2e041efb4151f6091dd0fea191989d133881 --- .../AndroidTextInputNativeComponent.js | 559 +++++++++++++++++- 1 file changed, 555 insertions(+), 4 deletions(-) diff --git a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index baf644cbb250a4..3990208974fa0a 100644 --- a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -10,10 +10,561 @@ 'use strict'; +import type {ViewProps} from '../View/ViewPropTypes'; +import type { + BubblingEventHandler, + DirectEventHandler, + Double, + Float, + Int32, +} from 'react-native/Libraries/Types/CodegenTypes'; +import type {NativeComponent} from '../../Renderer/shims/ReactNative'; +import type {TextStyleProp, ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import type {ColorValue} from '../../StyleSheet/StyleSheetTypes'; import {requireNativeComponent} from 'react-native'; -const AndroidTextInputNativeComponent: string = requireNativeComponent( - 'AndroidTextInput', -); +/*export type KeyboardType = + // Cross Platform + | 'default' + | 'email-address' + | 'numeric' + | 'phone-pad' + | 'number-pad' + | 'decimal-pad' + // iOS-only + | 'ascii-capable' + | 'numbers-and-punctuation' + | 'url' + | 'name-phone-pad' + | 'twitter' + | 'web-search' + // Android-only + | 'visible-password';*/ + +/*export type ReturnKeyType = + // Cross Platform + | 'done' + | 'go' + | 'next' + | 'search' + | 'send' + // Android-only + | 'none' + | 'previous' + // iOS-only + | 'default' + | 'emergency-call' + | 'google' + | 'join' + | 'route' + | 'yahoo';*/ + +export type NativeProps = $ReadOnly<{| + // This allows us to inherit everything from ViewProps except for style (see below) + // This must be commented for Fabric codegen to work. + ...$Diff>, + + /** + * Android props after this + */ + /** + * Determines which content to suggest on auto complete, e.g.`username`. + * To disable auto complete, use `off`. + * + * *Android Only* + * + * The following values work on Android only: + * + * - `username` + * - `password` + * - `email` + * - `name` + * - `tel` + * - `street-address` + * - `postal-code` + * - `cc-number` + * - `cc-csc` + * - `cc-exp` + * - `cc-exp-month` + * - `cc-exp-year` + * - `off` + * + * @platform android + */ + // TODO T53321474: define as flow enum + autoCompleteType?: ?string /*WithDefault< + ?( + | 'cc-csc' + | 'cc-exp' + | 'cc-exp-month' + | 'cc-exp-year' + | 'cc-number' + | 'email' + | 'name' + | 'password' + | 'postal-code' + | 'street-address' + | 'tel' + | 'username' + | 'off' + ), + 'off', + >*/, + + /** + * Sets the return key to the label. Use it instead of `returnKeyType`. + * @platform android + */ + returnKeyLabel?: ?string, + + /** + * Sets the number of lines for a `TextInput`. Use it with multiline set to + * `true` to be able to fill the lines. + * @platform android + */ + numberOfLines?: ?Int32, + + /** + * When `false`, if there is a small amount of space available around a text input + * (e.g. landscape orientation on a phone), the OS may choose to have the user edit + * the text inside of a full screen text input mode. When `true`, this feature is + * disabled and users will always edit the text directly inside of the text input. + * Defaults to `false`. + * @platform android + */ + disableFullscreenUI?: ?boolean, + + /** + * Set text break strategy on Android API Level 23+, possible values are `simple`, `highQuality`, `balanced` + * The default value is `simple`. + * @platform android + */ + // TODO T53321474: enable enum types in codegen + textBreakStrategy?: string, // ?('simple' | 'highQuality' | 'balanced'), + + /** + * The color of the `TextInput` underline. + * @platform android + */ + underlineColorAndroid?: ?ColorValue, + + /** + * If defined, the provided image resource will be rendered on the left. + * The image resource must be inside `/android/app/src/main/res/drawable` and referenced + * like + * ``` + * + * ``` + * @platform android + */ + inlineImageLeft?: ?string, + + /** + * Padding between the inline image, if any, and the text input itself. + * @platform android + */ + inlineImagePadding?: ?Int32, + + importantForAutofill?: string /*?( + | 'auto' + | 'no' + | 'noExcludeDescendants' + | 'yes' + | 'yesExcludeDescendants' + ),*/, + + /** + * When `false`, it will prevent the soft keyboard from showing when the field is focused. + * Defaults to `true`. + * @platform android + */ + showSoftInputOnFocus?: ?boolean, + + /** + * TextInput props after this + */ + /** + * Can tell `TextInput` to automatically capitalize certain characters. + * + * - `characters`: all characters. + * - `words`: first letter of each word. + * - `sentences`: first letter of each sentence (*default*). + * - `none`: don't auto capitalize anything. + */ + autoCapitalize?: ?string, // TODO T53321474: define as enum: AutoCapitalize 'none' | 'sentences' | 'words' | 'characters' , + + /** + * If `false`, disables auto-correct. The default value is `true`. + */ + autoCorrect?: ?boolean, + + /** + * If `true`, focuses the input on `componentDidMount`. + * The default value is `false`. + */ + autoFocus?: ?boolean, + + /** + * Specifies whether fonts should scale to respect Text Size accessibility settings. The + * default is `true`. + */ + allowFontScaling?: ?boolean, + + /** + * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled. + * Possible values: + * `null/undefined` (default): inherit from the parent node or the global default (0) + * `0`: no max, ignore parent/global default + * `>= 1`: sets the maxFontSizeMultiplier of this node to this value + */ + maxFontSizeMultiplier?: ?Float, + + /** + * If `false`, text is not editable. The default value is `true`. + */ + editable?: ?boolean, + + /** + * Determines which keyboard to open, e.g.`numeric`. + * + * The following values work across platforms: + * + * - `default` + * - `numeric` + * - `number-pad` + * - `decimal-pad` + * - `email-address` + * - `phone-pad` + * + * *iOS Only* + * + * The following values work on iOS only: + * + * - `ascii-capable` + * - `numbers-and-punctuation` + * - `url` + * - `name-phone-pad` + * - `twitter` + * - `web-search` + * + * *Android Only* + * + * The following values work on Android only: + * + * - `visible-password` + */ + // TODO T53321474: enable enum codegen + keyboardType?: ?string, // ?KeyboardType, + + /** + * Determines how the return key should look. On Android you can also use + * `returnKeyLabel`. + * + * *Cross platform* + * + * The following values work across platforms: + * + * - `done` + * - `go` + * - `next` + * - `search` + * - `send` + * + * *Android Only* + * + * The following values work on Android only: + * + * - `none` + * - `previous` + * + * *iOS Only* + * + * The following values work on iOS only: + * + * - `default` + * - `emergency-call` + * - `google` + * - `join` + * - `route` + * - `yahoo` + */ + // TODO T53321474: enable enum codegen + returnKeyType?: ?string, // ?ReturnKeyType, + + /** + * Limits the maximum number of characters that can be entered. Use this + * instead of implementing the logic in JS to avoid flicker. + */ + maxLength?: ?Int32, + + /** + * If `true`, the text input can be multiple lines. + * The default value is `false`. + */ + multiline?: ?boolean, + + /** + * Callback that is called when the text input is blurred. + * `target` is the reactTag of the element + */ + onBlur?: ?BubblingEventHandler<$ReadOnly<{|target: Int32|}>>, + + /** + * Callback that is called when the text input is focused. + * `target` is the reactTag of the element + */ + onFocus?: ?BubblingEventHandler<$ReadOnly<{|target: Int32|}>>, + + /** + * Callback that is called when the text input's text changes. + * `target` is the reactTag of the element + * TODO: differentiate between onChange and onChangeText + */ + onChange?: ?BubblingEventHandler< + $ReadOnly<{|target: Int32, eventCount: Int32, text: string|}>, + >, -export default AndroidTextInputNativeComponent; + /** + * Callback that is called when the text input's text changes. + * Changed text is passed as an argument to the callback handler. + * TODO: differentiate between onChange and onChangeText + */ + onChangeText?: ?BubblingEventHandler< + $ReadOnly<{|target: Int32, eventCount: Int32, text: string|}>, + >, + + /** + * Callback that is called when the text input's content size changes. + * This will be called with + * `{ nativeEvent: { contentSize: { width, height } } }`. + * + * Only called for multiline text inputs. + */ + onContentSizeChange?: ?DirectEventHandler< + $ReadOnly<{| + target: Int32, + // contentSize: $ReadOnly<{|width: Double, height: Double|}>, + contentSize: {|width: Double, height: Double|}, + |}>, + >, + + onTextInput?: ?BubblingEventHandler< + $ReadOnly<{| + target: Int32, + text: string, + previousText: string, + // range: $ReadOnly<{|start: Double, end: Double|}>, + range: {|start: Double, end: Double|}, + |}>, + >, + + /** + * Callback that is called when text input ends. + */ + onEndEditing?: ?BubblingEventHandler< + $ReadOnly<{|target: Int32, text: string|}>, + >, + + /** + * Callback that is called when the text input selection is changed. + * This will be called with + * `{ nativeEvent: { selection: { start, end } } }`. + */ + onSelectionChange?: ?DirectEventHandler< + $ReadOnly<{| + target: Int32, + //selection: $ReadOnly<{|start: Double, end: Double|}>, + selection: {|start: Double, end: Double|}, + |}>, + >, + + /** + * Callback that is called when the text input's submit button is pressed. + * Invalid if `multiline={true}` is specified. + */ + onSubmitEditing?: ?BubblingEventHandler< + $ReadOnly<{|target: Int32, text: string|}>, + >, + + /** + * Callback that is called when a key is pressed. + * This will be called with `{ nativeEvent: { key: keyValue } }` + * where `keyValue` is `'Enter'` or `'Backspace'` for respective keys and + * the typed-in character otherwise including `' '` for space. + * Fires before `onChange` callbacks. + */ + onKeyPress?: ?BubblingEventHandler<$ReadOnly<{|target: Int32, key: string|}>>, + + /** + * Invoked on content scroll with `{ nativeEvent: { contentOffset: { x, y } } }`. + * May also contain other properties from ScrollEvent but on Android contentSize + * is not provided for performance reasons. + */ + onScroll?: ?DirectEventHandler< + $ReadOnly<{| + target: Int32, + responderIgnoreScroll: boolean, + contentInset: {| + //$ReadOnly<{| + top: Double, // always 0 on Android + bottom: Double, // always 0 on Android + left: Double, // always 0 on Android + right: Double, // always 0 on Android + |}, + contentOffset: {| + //$ReadOnly<{| + x: Double, + y: Double, + |}, + contentSize: {| + // $ReadOnly<{| + width: Double, // always 0 on Android + height: Double, // always 0 on Android + |}, + layoutMeasurement: {| + // $ReadOnly<{| + width: Double, + height: Double, + |}, + velocity: {| + // $ReadOnly<{| + x: Double, // always 0 on Android + y: Double, // always 0 on Android + |}, + |}>, + >, + + /** + * The string that will be rendered before text input has been entered. + */ + placeholder?: ?string, + + /** + * The text color of the placeholder string. + */ + placeholderTextColor?: ?ColorValue, + + /** + * If `true`, the text input obscures the text entered so that sensitive text + * like passwords stay secure. The default value is `false`. Does not work with 'multiline={true}'. + */ + secureTextEntry?: ?boolean, + + /** + * The highlight and cursor color of the text input. + */ + selectionColor?: ?ColorValue, + + /** + * The start and end of the text input's selection. Set start and end to + * the same value to position the cursor. + */ + selection?: ?$ReadOnly<{| + start: Int32, + end?: ?Int32, + |}>, + + /** + * The value to show for the text input. `TextInput` is a controlled + * component, which means the native value will be forced to match this + * value prop if provided. For most uses, this works great, but in some + * cases this may cause flickering - one common cause is preventing edits + * by keeping value the same. In addition to simply setting the same value, + * either set `editable={false}`, or set/update `maxLength` to prevent + * unwanted edits without flicker. + */ + value?: ?string, + + /** + * Provides an initial value that will change when the user starts typing. + * Useful for simple use-cases where you do not want to deal with listening + * to events and updating the value prop to keep the controlled state in sync. + */ + defaultValue?: ?string, + + /** + * If `true`, all text will automatically be selected on focus. + */ + selectTextOnFocus?: ?boolean, + + /** + * If `true`, the text field will blur when submitted. + * The default value is true for single-line fields and false for + * multiline fields. Note that for multiline fields, setting `blurOnSubmit` + * to `true` means that pressing return will blur the field and trigger the + * `onSubmitEditing` event instead of inserting a newline into the field. + */ + blurOnSubmit?: ?boolean, + + /** + * Note that not all Text styles are supported, an incomplete list of what is not supported includes: + * + * - `borderLeftWidth` + * - `borderTopWidth` + * - `borderRightWidth` + * - `borderBottomWidth` + * - `borderTopLeftRadius` + * - `borderTopRightRadius` + * - `borderBottomRightRadius` + * - `borderBottomLeftRadius` + * + * see [Issue#7070](https://github.com/facebook/react-native/issues/7070) + * for more detail. + * + * [Styles](docs/style.html) + */ + // TODO: figure out what to do with this style prop for codegen/Fabric purposes + // This must be commented for Fabric codegen to work; it's currently not possible + // to override the default View style prop in codegen. + style?: ?TextStyleProp, + + /** + * If `true`, caret is hidden. The default value is `false`. + * This property is supported only for single-line TextInput component on iOS. + */ + caretHidden?: ?boolean, + + /* + * If `true`, contextMenuHidden is hidden. The default value is `false`. + */ + contextMenuHidden?: ?boolean, + + /** + * The following are props that `BaseTextShadowNode` takes. It is unclear if they + * are used by TextInput. + */ + textShadowColor?: ?ColorValue, + textShadowRadius?: ?Float, + textDecorationLine?: ?string, + fontStyle?: ?string, + textShadowOffset?: ?$ReadOnly<{|width?: ?Double, height?: ?Double|}>, + lineHeight?: ?Float, + textTransform?: ?string, + color?: ?Int32, + letterSpacing?: ?Float, + fontSize?: ?Float, + textAlign?: ?string, + includeFontPadding?: ?boolean, + fontWeight?: ?string, + fontFamily?: ?string, + + /** + * I cannot find where these are defined but JS complains without them. + */ + textAlignVertical?: ?string, + cursorColor?: ?ColorValue, + + /** + * "Private" fields used by TextInput.js and not users of this component directly + */ + mostRecentEventCount: Int32, + text?: ?string, +|}>; + +type AndroidTextInputComponentType = Class>; + +export default ((requireNativeComponent( + 'AndroidTextInput', +): any): AndroidTextInputComponentType); From a397d330a4cf7e08095faa0e751e38d5106ed5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Sat, 31 Aug 2019 10:02:21 -0700 Subject: [PATCH 0098/1244] Support light and dark themes in RNTester Summary: Initial conversion of RNTester to support light and dark themes. Theming is implemented by providing the desired color theme via context. Example: ``` const ThemedContainer = props => ( {theme => { return ( {props.children} ); }} ); ``` As RNTester's design follows the base iOS system appearance, I've chosen light and dark themes based on the actual iOS 13 semantic colors. The themes are RNTester-specific, however, and we'd expect individual apps to build their own color palettes. ## Examples The new Appearance Examples screen demonstrates how context can be used to force a theme. It also displays the list of colors in each RNTester theme. https://pxl.cl/HmzW (screenshot: Appearance Examples screen on RNTester with Dark Mode enabled. Displays useColorScheme hook, and context examples.) https://pxl.cl/HmB3 (screenshot: Same screen, with light and dark RNTester themes visible) Theming support in this diff mostly focused on the main screen and the Dark Mode examples screen. This required updating the components used by most of the examples, as you can see in this Image example: https://pxl.cl/H0Hv (screenshot: Image Examples screen in Dark Mode theme) Note that I have yet to go through every single example screen to update it. There's individual cases, such as the FlatList example screen, that are not fully converted to use a dark theme when appropriate. This can be taken care later as it's non-blocking. Reviewed By: zackargyle Differential Revision: D16681909 fbshipit-source-id: e47484d4b3f0963ef0cc3d8aff8ce3e9051ddbae --- .../FBReactNativeSpec-generated.mm | 12 +- .../FBReactNativeSpec/FBReactNativeSpec.h | 14 +- RNTester/js/RNTesterApp.ios.js | 87 +++++--- RNTester/js/components/RNTesterBlock.js | 51 +++-- .../js/components/RNTesterExampleFilter.js | 52 +++-- RNTester/js/components/RNTesterExampleList.js | 146 +++++++++---- RNTester/js/components/RNTesterPage.js | 27 ++- RNTester/js/components/RNTesterTheme.js | 88 ++++++++ RNTester/js/components/RNTesterTitle.js | 24 ++- .../examples/Appearance/AppearanceExample.js | 201 ++++++++++++++++++ RNTester/js/examples/Button/ButtonExample.js | 77 ++++--- RNTester/js/utils/RNTesterActions.js | 20 +- RNTester/js/utils/RNTesterList.ios.js | 5 + .../js/utils/RNTesterNavigationReducer.js | 17 ++ 14 files changed, 663 insertions(+), 158 deletions(-) create mode 100644 RNTester/js/components/RNTesterTheme.js create mode 100644 RNTester/js/examples/Appearance/AppearanceExample.js diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm index 2104b1dbfeff02..bf8bfae08a4de9 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec-generated.mm @@ -487,6 +487,12 @@ + (RCTManagedPointer *)JS_NativeAppState_SpecGetCurrentAppStateSuccessAppState:( } // namespace react } // namespace facebook +@implementation RCTCxxConvert (NativeAppearance_AppearancePreferences) ++ (RCTManagedPointer *)JS_NativeAppearance_AppearancePreferences:(id)json +{ + return facebook::react::managedPointer(json); +} +@end folly::Optional NSStringToNativeAppearanceColorSchemeName(NSString *value) { static NSDictionary *dict = nil; static dispatch_once_t onceToken; @@ -510,12 +516,6 @@ + (RCTManagedPointer *)JS_NativeAppState_SpecGetCurrentAppStateSuccessAppState:( }); return value.hasValue() ? dict[@(value.value())] : nil; } -@implementation RCTCxxConvert (NativeAppearance_AppearancePreferences) -+ (RCTManagedPointer *)JS_NativeAppearance_AppearancePreferences:(id)json -{ - return facebook::react::managedPointer(json); -} -@end @implementation RCTCxxConvert (NativeAsyncStorage_SpecMultiGetCallbackErrorsElement) + (RCTManagedPointer *)JS_NativeAsyncStorage_SpecMultiGetCallbackErrorsElement:(id)json { diff --git a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h index a5561e3bcce80d..7548c6ced5608f 100644 --- a/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h +++ b/Libraries/FBReactNativeSpec/FBReactNativeSpec/FBReactNativeSpec.h @@ -452,13 +452,6 @@ namespace facebook { }; } // namespace react } // namespace facebook -typedef NS_ENUM(NSInteger, NativeAppearanceColorSchemeName) { - NativeAppearanceColorSchemeNameLight = 0, - NativeAppearanceColorSchemeNameDark, -}; - -folly::Optional NSStringToNativeAppearanceColorSchemeName(NSString *value); -NSString *NativeAppearanceColorSchemeNameToNSString(folly::Optional value); namespace JS { namespace NativeAppearance { @@ -475,6 +468,13 @@ namespace JS { @interface RCTCxxConvert (NativeAppearance_AppearancePreferences) + (RCTManagedPointer *)JS_NativeAppearance_AppearancePreferences:(id)json; @end +typedef NS_ENUM(NSInteger, NativeAppearanceColorSchemeName) { + NativeAppearanceColorSchemeNameLight = 0, + NativeAppearanceColorSchemeNameDark, +}; + +folly::Optional NSStringToNativeAppearanceColorSchemeName(NSString *value); +NSString *NativeAppearanceColorSchemeNameToNSString(folly::Optional value); namespace JS { namespace NativeAsyncStorage { diff --git a/RNTester/js/RNTesterApp.ios.js b/RNTester/js/RNTesterApp.ios.js index 646b33920c9e95..1a333589a39558 100644 --- a/RNTester/js/RNTesterApp.ios.js +++ b/RNTester/js/RNTesterApp.ios.js @@ -20,11 +20,13 @@ const SnapshotViewIOS = require('./examples/Snapshot/SnapshotViewIOS.ios'); const URIActionMap = require('./utils/URIActionMap'); const { + Appearance, AppRegistry, AsyncStorage, BackHandler, Button, Linking, + Platform, SafeAreaView, StyleSheet, Text, @@ -35,6 +37,7 @@ const { import type {RNTesterExample} from './types/RNTesterTypes'; import type {RNTesterAction} from './utils/RNTesterActions'; import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer'; +import {RNTesterThemeContext, themes} from './components/RNTesterTheme'; type Props = { exampleFromAppetizeParams?: ?string, @@ -47,18 +50,40 @@ YellowBox.ignoreWarnings([ const APP_STATE_KEY = 'RNTesterAppState.v2'; const Header = ({onBack, title}: {onBack?: () => mixed, title: string}) => ( - - - - {title} - - {onBack && ( - -