From 33b064bb9cdaac6a67a1d76da652d90288e69830 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Thu, 23 May 2024 10:58:01 -0700 Subject: [PATCH 01/67] enable preventDoubleTextMeasure optimisation by default (#44659) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44659 changelog: [internal] Reviewed By: javache Differential Revision: D57678341 fbshipit-source-id: cc6fbcfedccc0fd4610d52feee60b0fc35cc83b9 --- .../internal/featureflags/ReactNativeFeatureFlagsDefaults.kt | 4 ++-- .../react/featureflags/ReactNativeFeatureFlagsDefaults.h | 4 ++-- .../scripts/featureflags/ReactNativeFeatureFlags.config.js | 2 +- .../src/private/featureflags/ReactNativeFeatureFlags.js | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt index 149ecce3378528..980ba43a704f57 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<4f50dab251c41380a14506975355e49d>> + * @generated SignedSource<<64ab913d2c940a7abfcd2aac32be1b72>> */ /** @@ -55,7 +55,7 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi override fun lazyAnimationCallbacks(): Boolean = false - override fun preventDoubleTextMeasure(): Boolean = false + override fun preventDoubleTextMeasure(): Boolean = true override fun setAndroidLayoutDirection(): Boolean = false diff --git a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h index c50025ebf06bf6..8bde1e420dc0f4 100644 --- a/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h +++ b/packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlagsDefaults.h @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<2bfa4670757aa340c88ae8ff57270308>> + * @generated SignedSource<<54a1827a45d7dd15b5e8a26d49ad6d30>> */ /** @@ -92,7 +92,7 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider { } bool preventDoubleTextMeasure() override { - return false; + return true; } bool setAndroidLayoutDirection() override { diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index fbc772c54feea1..5d1b145c39889f 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -114,7 +114,7 @@ const definitions: FeatureFlagDefinitions = { 'Only enqueue Choreographer calls if there is an ongoing animation, instead of enqueueing every frame.', }, preventDoubleTextMeasure: { - defaultValue: false, + defaultValue: true, description: 'When enabled, ParagraphShadowNode will no longer call measure twice.', }, diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 0378f10607eece..15c717c96d8e76 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<20c3c50d2124fbfc7bbe434c940ce3bf>> + * @generated SignedSource<<63e7a8952026600cb58367e9c70fb68d>> * @flow strict-local */ @@ -170,7 +170,7 @@ export const lazyAnimationCallbacks: Getter = createNativeFlagGetter('l /** * When enabled, ParagraphShadowNode will no longer call measure twice. */ -export const preventDoubleTextMeasure: Getter = createNativeFlagGetter('preventDoubleTextMeasure', false); +export const preventDoubleTextMeasure: Getter = createNativeFlagGetter('preventDoubleTextMeasure', true); /** * Propagate layout direction to Android views. */ From 3f74f69cf00858cd18774837bf5afc3fccdfca86 Mon Sep 17 00:00:00 2001 From: zhongwuzw Date: Thu, 23 May 2024 11:11:27 -0700 Subject: [PATCH 02/67] Fixes race condition of m_batchHadNativeModuleOrTurboModuleCalls (#44653) Summary: Fixes https://github.com/facebook/react-native/issues/44649. ## Changelog: [IOS] [FIXED] - Fixes race condition of m_batchHadNativeModuleOrTurboModuleCalls Pull Request resolved: https://github.com/facebook/react-native/pull/44653 Test Plan: Demo in https://github.com/facebook/react-native/issues/44649. Reviewed By: fabriziocucci Differential Revision: D57727886 Pulled By: sammy-SC fbshipit-source-id: 967e2d8452cc477f2225151a46e9aa27698f4506 --- packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp index aeec3b7a144520..318a0ebbb9d26f 100644 --- a/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp +++ b/packages/react-native/ReactCommon/cxxreact/NativeToJsBridge.cpp @@ -101,7 +101,7 @@ class JsToNativeBridge : public react::ExecutorDelegate { // executor is destroyed synchronously on its queue. std::shared_ptr m_registry; std::shared_ptr m_callback; - bool m_batchHadNativeModuleOrTurboModuleCalls = false; + std::atomic m_batchHadNativeModuleOrTurboModuleCalls{false}; }; NativeToJsBridge::NativeToJsBridge( From 1343313dc6fd2b8bc111ec4ccf03d4aa05fcfff7 Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 23 May 2024 12:33:41 -0700 Subject: [PATCH 03/67] Invoke callableModule factory once (#44576) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44576 Store callable modules as either a factory function or an object, so we can skip invoking the factory function for frequently accessed objects. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D57338528 fbshipit-source-id: cd39ccbe7168c6f093a0e62d5880cbbcd5209c8e --- .../react/runtime/ReactInstance.cpp | 44 +++++++++++-------- .../ReactCommon/react/runtime/ReactInstance.h | 11 ++--- .../runtime/tests/cxx/ReactInstanceTest.cpp | 8 ++-- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index 7f51293d038f81..5a1d10fdaaa362 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -232,20 +232,24 @@ void ReactInstance::loadScript( void ReactInstance::callFunctionOnModule( const std::string& moduleName, const std::string& methodName, - const folly::dynamic& args) { - // TODO (C++ 20): This code previously implicitly captured `this` in a [=] - // capture group. Was it meaning to pass modules_ by value? - bufferedRuntimeExecutor_->execute([=, this](jsi::Runtime& runtime) { + folly::dynamic&& args) { + bufferedRuntimeExecutor_->execute([this, + moduleName = moduleName, + methodName = methodName, + args = std::move(args)]( + jsi::Runtime& runtime) { SystraceSection s( "ReactInstance::callFunctionOnModule", "moduleName", moduleName, "methodName", methodName); - if (modules_.find(moduleName) == modules_.end()) { + auto it = callableModules_.find(moduleName); + if (it == callableModules_.end()) { std::ostringstream knownModules; int i = 0; - for (auto it = modules_.begin(); it != modules_.end(); it++, i++) { + for (it = callableModules_.begin(); it != callableModules_.end(); + it++, i++) { const char* space = (i > 0 ? ", " : " "); knownModules << space << it->first; } @@ -254,24 +258,25 @@ void ReactInstance::callFunctionOnModule( "Failed to call into JavaScript module method " + moduleName + "." + methodName + "(). Module has not been registered as callable. Registered callable JavaScript modules (n = " + - std::to_string(modules_.size()) + "):" + knownModules.str() + - ". Did you forget to call `RN$registerCallableModule`?"); + std::to_string(callableModules_.size()) + + "):" + knownModules.str() + + ". Did you forget to call `registerCallableModule`?"); } - auto module = modules_[moduleName]->factory.call(runtime).asObject(runtime); - auto method = module.getProperty(runtime, methodName.c_str()); - if (method.isUndefined()) { - throw jsi::JSError( - runtime, - "Failed to call into JavaScript module method " + moduleName + "." + - methodName + ". Module exists, but the method is undefined."); + if (std::holds_alternative(it->second)) { + auto module = + std::get(it->second).call(runtime).asObject(runtime); + it->second = std::move(module); } + auto& module = std::get(it->second); + auto method = module.getPropertyAsFunction(runtime, methodName.c_str()); + std::vector jsArgs; for (auto& arg : args) { jsArgs.push_back(jsi::valueFromDynamic(runtime, arg)); } - method.asObject(runtime).asFunction(runtime).callWithThis( + method.callWithThis( runtime, module, (const jsi::Value*)jsArgs.data(), jsArgs.size()); }); } @@ -367,13 +372,14 @@ void ReactInstance::initializeRuntime( } auto name = args[0].asString(runtime).utf8(runtime); if (!args[1].isObject() || - !args[1].asObject(runtime).isFunction(runtime)) { + !args[1].getObject(runtime).isFunction(runtime)) { throw jsi::JSError( runtime, "The second argument to registerCallableModule must be a function that returns the JS module."); } - modules_[name] = std::make_shared( - args[1].getObject(runtime).asFunction(runtime)); + callableModules_.emplace( + std::move(name), + args[1].getObject(runtime).getFunction(runtime)); return jsi::Value::undefined(); })); diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index 2a7ccea628bbaf..5c76e1956c0b05 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -20,12 +20,6 @@ namespace facebook::react { -struct CallableModule { - explicit CallableModule(jsi::Function factory) - : factory(std::move(factory)) {} - jsi::Function factory; -}; - class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { public: using BindingsInstallFunc = std::function; @@ -61,7 +55,7 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { void callFunctionOnModule( const std::string& moduleName, const std::string& methodName, - const folly::dynamic& args); + folly::dynamic&& args); void handleMemoryPressureJs(int pressureLevel); @@ -78,7 +72,8 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { std::shared_ptr jsMessageQueueThread_; std::shared_ptr bufferedRuntimeExecutor_; std::shared_ptr timerManager_; - std::unordered_map> modules_; + std::unordered_map> + callableModules_; std::shared_ptr runtimeScheduler_; std::shared_ptr jsErrorHandler_; diff --git a/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp b/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp index 9ba769179998a7..b69d831aade2c6 100644 --- a/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp +++ b/packages/react-native/ReactCommon/react/runtime/tests/cxx/ReactInstanceTest.cpp @@ -18,6 +18,7 @@ #include using ::testing::_; +using ::testing::HasSubstr; using ::testing::SaveArg; namespace facebook::react { @@ -801,9 +802,10 @@ TEST_F(ReactInstanceTest, testCallFunctionOnModule_invalidModule) { instance_->callFunctionOnModule("invalidModule", "method", std::move(args)); step(); expectError(); - EXPECT_EQ( + EXPECT_THAT( getLastErrorMessage(), - "Failed to call into JavaScript module method invalidModule.method(). Module has not been registered as callable. Registered callable JavaScript modules (n = 0):. Did you forget to call `RN$registerCallableModule`?"); + HasSubstr( + "Failed to call into JavaScript module method invalidModule.method()")); } TEST_F(ReactInstanceTest, testCallFunctionOnModule_undefinedMethod) { @@ -820,7 +822,7 @@ RN$registerCallableModule('foo', () => module); expectError(); EXPECT_EQ( getLastErrorMessage(), - "Failed to call into JavaScript module method foo.invalidMethod. Module exists, but the method is undefined."); + "getPropertyAsObject: property 'invalidMethod' is undefined, expected an Object"); } TEST_F(ReactInstanceTest, testCallFunctionOnModule_invalidMethod) { From b2ced62d3363b9448f6e4698692c31ed2d9230aa Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Thu, 23 May 2024 14:57:00 -0700 Subject: [PATCH 04/67] Shortcut emitDeviceEvent in bridgeless (2nd attempt) (#44590) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44590 emitDeviceEvent is frequently used for perf-critical operations such as sending network responses from native to JS. We don't need to go through JavaScriptModule Proxy (which is missing caching in bridgeless) and instead can immediately invoke the callable JS module. Changelog: [Internal] Reviewed By: philIip Differential Revision: D57435750 fbshipit-source-id: 1c120073ac80afd95deb8e3e6f1c00c2d3d80133 --- .../react/runtime/BridgelessReactContext.java | 9 +++++ .../runtime/BridgelessReactContextTest.kt | 39 ++++++++++++++----- .../testutils/shadows/ShadowArguments.kt | 14 +++++++ .../testutils/shadows/ShadowNativeArray.kt | 29 ++++++++++++++ 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowNativeArray.kt diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java index 6c7b343d25b811..78f4e0c59a831f 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/runtime/BridgelessReactContext.java @@ -148,6 +148,8 @@ public T getJSModule(Class jsInterface) { && mInteropModuleRegistry.shouldReturnInteropModule(jsInterface)) { return mInteropModuleRegistry.getInteropModule(jsInterface); } + + // TODO T189052462: ReactContext caches JavaScriptModule instances JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance( @@ -157,6 +159,13 @@ public T getJSModule(Class jsInterface) { return (T) interfaceProxy; } + /** Shortcut RCTDeviceEventEmitter.emit since it's frequently used */ + @Override + public void emitDeviceEvent(String eventName, @Nullable Object args) { + mReactHost.callFunctionOnModule( + "RCTDeviceEventEmitter", "emit", Arguments.fromJavaArgs(new Object[] {eventName, args})); + } + @Override public boolean hasNativeModule(Class nativeModuleInterface) { return mReactHost.hasNativeModule(nativeModuleInterface); diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/BridgelessReactContextTest.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/BridgelessReactContextTest.kt index a3bf2053394eda..e2703be942a01d 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/BridgelessReactContextTest.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/react/runtime/BridgelessReactContextTest.kt @@ -9,23 +9,31 @@ package com.facebook.react.runtime import android.app.Activity import android.content.Context +import com.facebook.react.bridge.WritableNativeArray import com.facebook.react.fabric.FabricUIManager import com.facebook.react.uimanager.UIManagerModule +import com.facebook.testutils.shadows.ShadowArguments +import com.facebook.testutils.shadows.ShadowNativeArray import com.facebook.testutils.shadows.ShadowSoLoader -import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers -import org.mockito.Mockito import org.mockito.Mockito.doReturn +import org.mockito.Mockito.eq +import org.mockito.Mockito.mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config /** Tests [BridgelessReactContext] */ @RunWith(RobolectricTestRunner::class) -@Config(shadows = [ShadowSoLoader::class]) +@Config( + shadows = [ShadowSoLoader::class, ShadowArguments::class, ShadowNativeArray.Writable::class]) class BridgelessReactContextTest { private lateinit var context: Context private lateinit var reactHost: ReactHostImpl @@ -34,30 +42,43 @@ class BridgelessReactContextTest { @Before fun setUp() { context = Robolectric.buildActivity(Activity::class.java).create().get() - reactHost = Mockito.mock(ReactHostImpl::class.java) + reactHost = mock(ReactHostImpl::class.java) bridgelessReactContext = BridgelessReactContext(context, reactHost) } @Test fun getNativeModuleTest() { - val mUiManagerModule = Mockito.mock(UIManagerModule::class.java) + val mUiManagerModule = mock(UIManagerModule::class.java) doReturn(mUiManagerModule) .`when`(reactHost) .getNativeModule(ArgumentMatchers.any>()) val uiManagerModule = bridgelessReactContext.getNativeModule(UIManagerModule::class.java) - Assertions.assertThat(uiManagerModule).isEqualTo(mUiManagerModule) + assertThat(uiManagerModule).isEqualTo(mUiManagerModule) } @Test fun getFabricUIManagerTest() { - val fabricUiManager = Mockito.mock(FabricUIManager::class.java) + val fabricUiManager = mock(FabricUIManager::class.java) doReturn(fabricUiManager).`when`(reactHost).uiManager - Assertions.assertThat(bridgelessReactContext.getFabricUIManager()).isEqualTo(fabricUiManager) + assertThat(bridgelessReactContext.getFabricUIManager()).isEqualTo(fabricUiManager) } @Test fun getCatalystInstanceTest() { - Assertions.assertThat(bridgelessReactContext.getCatalystInstance()) + assertThat(bridgelessReactContext.getCatalystInstance()) .isInstanceOf(BridgelessCatalystInstance::class.java) } + + @Test + fun testEmitDeviceEvent() { + bridgelessReactContext.emitDeviceEvent("onNetworkResponseReceived", mapOf("foo" to "bar")) + + val argsCapture = ArgumentCaptor.forClass(WritableNativeArray::class.java) + verify(reactHost, times(1)) + .callFunctionOnModule(eq("RCTDeviceEventEmitter"), eq("emit"), argsCapture.capture()) + + val argsList = ShadowNativeArray.getContents(argsCapture.value) + assertThat(argsList[0]).isEqualTo("onNetworkResponseReceived") + @Suppress("UNCHECKED_CAST") assertThat((argsList[1] as Map)["foo"]).isEqualTo("bar") + } } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowArguments.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowArguments.kt index c8e47d678090a5..7307d503cd059c 100644 --- a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowArguments.kt +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowArguments.kt @@ -8,14 +8,28 @@ package com.facebook.testutils.shadows import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.JavaOnlyArray import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.bridge.WritableArray import com.facebook.react.bridge.WritableMap +import com.facebook.react.bridge.WritableNativeArray import org.robolectric.annotation.Implementation import org.robolectric.annotation.Implements +import org.robolectric.shadow.api.Shadow @Implements(Arguments::class) class ShadowArguments { + companion object { + @JvmStatic @Implementation fun createArray(): WritableArray = JavaOnlyArray() + @JvmStatic @Implementation fun createMap(): WritableMap = JavaOnlyMap() + + @JvmStatic + @Implementation + fun fromJavaArgs(args: Array): WritableNativeArray = + WritableNativeArray().apply { + (Shadow.extract(this) as ShadowNativeArray).contents = args.toList() + } } } diff --git a/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowNativeArray.kt b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowNativeArray.kt new file mode 100644 index 00000000000000..f77a3a33def2b1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/test/java/com/facebook/testutils/shadows/ShadowNativeArray.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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.testutils.shadows + +import com.facebook.react.bridge.NativeArray +import com.facebook.react.bridge.ReadableNativeArray +import com.facebook.react.bridge.WritableNativeArray +import org.robolectric.annotation.Implements +import org.robolectric.shadow.api.Shadow + +// Mockito can't mock native methods, so shadow the entire class instead +@Implements(NativeArray::class) +public open class ShadowNativeArray { + public var contents: List = mutableListOf() + + @Implements(ReadableNativeArray::class) public class Readable : ShadowNativeArray() {} + + @Implements(WritableNativeArray::class) public class Writable : ShadowNativeArray() {} + + public companion object { + public fun getContents(array: NativeArray): List = + (Shadow.extract(array) as ShadowNativeArray).contents + } +} From 1cc1673c3223784634308bea7a2453b864489547 Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Fri, 24 May 2024 04:35:42 -0700 Subject: [PATCH 05/67] xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java (#44656) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44656 ## Changelog [Android] [Changed] - Converted StatusBarModule to Kotlin Reviewed By: andrewdacenko Differential Revision: D57614041 fbshipit-source-id: 054b13cd286e9e9b7f870e66ff0e07def075a3c3 --- .../ReactAndroid/api/ReactAndroid.api | 7 +- .../modules/statusbar/StatusBarModule.java | 236 ------------------ .../modules/statusbar/StatusBarModule.kt | 185 ++++++++++++++ 3 files changed, 190 insertions(+), 238 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index e41508ed1ec2e0..474cc0588458bc 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3553,16 +3553,19 @@ public final class com/facebook/react/modules/sound/SoundManagerModule : com/fac public fun playTouchSound ()V } -public class com/facebook/react/modules/statusbar/StatusBarModule : com/facebook/fbreact/specs/NativeStatusBarManagerAndroidSpec { +public final class com/facebook/react/modules/statusbar/StatusBarModule : com/facebook/fbreact/specs/NativeStatusBarManagerAndroidSpec { + public static final field Companion Lcom/facebook/react/modules/statusbar/StatusBarModule$Companion; public static final field NAME Ljava/lang/String; public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V - public fun getTypedExportedConstants ()Ljava/util/Map; public fun setColor (DZ)V public fun setHidden (Z)V public fun setStyle (Ljava/lang/String;)V public fun setTranslucent (Z)V } +public final class com/facebook/react/modules/statusbar/StatusBarModule$Companion { +} + public class com/facebook/react/modules/systeminfo/AndroidInfoHelpers { public static final field DEVICE_LOCALHOST Ljava/lang/String; public static final field EMULATOR_LOCALHOST Ljava/lang/String; diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java deleted file mode 100644 index 3d17ab81af44fe..00000000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and 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.modules.statusbar; - -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.os.Build; -import android.view.View; -import android.view.Window; -import android.view.WindowInsets; -import android.view.WindowInsetsController; -import android.view.WindowManager; -import androidx.annotation.Nullable; -import androidx.core.view.ViewCompat; -import com.facebook.common.logging.FLog; -import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec; -import com.facebook.infer.annotation.Nullsafe; -import com.facebook.react.bridge.GuardedRunnable; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.common.ReactConstants; -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.uimanager.PixelUtil; -import java.util.Map; - -/** {@link NativeModule} that allows changing the appearance of the status bar. */ -@ReactModule(name = NativeStatusBarManagerAndroidSpec.NAME) -@Nullsafe(Nullsafe.Mode.LOCAL) -public class StatusBarModule extends NativeStatusBarManagerAndroidSpec { - - private static final String HEIGHT_KEY = "HEIGHT"; - private static final String DEFAULT_BACKGROUND_COLOR_KEY = "DEFAULT_BACKGROUND_COLOR"; - public static final String NAME = "StatusBarManager"; - - public StatusBarModule(ReactApplicationContext reactContext) { - super(reactContext); - } - - @Override - public Map getTypedExportedConstants() { - final Context context = getReactApplicationContext(); - final Activity activity = getCurrentActivity(); - - final int heightResId = - context.getResources().getIdentifier("status_bar_height", "dimen", "android"); - final float height = - heightResId > 0 - ? PixelUtil.toDIPFromPixel(context.getResources().getDimensionPixelSize(heightResId)) - : 0; - String statusBarColorString = "black"; - - if (activity != null) { - Window window = activity.getWindow(); - if (window != null) { - final int statusBarColor = window.getStatusBarColor(); - statusBarColorString = String.format("#%06X", (0xFFFFFF & statusBarColor)); - } - } - - return MapBuilder.of( - HEIGHT_KEY, height, DEFAULT_BACKGROUND_COLOR_KEY, statusBarColorString); - } - - @Override - public void setColor(final double colorDouble, final boolean animated) { - final int color = (int) colorDouble; - - final Activity activity = getCurrentActivity(); - if (activity == null) { - FLog.w( - ReactConstants.TAG, - "StatusBarModule: Ignored status bar change, current activity is null."); - return; - } - - UiThreadUtil.runOnUiThread( - new GuardedRunnable(getReactApplicationContext()) { - @Override - public void runGuarded() { - Window window = activity.getWindow(); - if (window == null) { - return; - } - window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); - if (animated) { - int curColor = window.getStatusBarColor(); - ValueAnimator colorAnimation = - ValueAnimator.ofObject(new ArgbEvaluator(), curColor, color); - - colorAnimation.addUpdateListener( - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animator) { - Window window = activity.getWindow(); - if (window != null) { - window.setStatusBarColor((Integer) animator.getAnimatedValue()); - } - } - }); - colorAnimation.setDuration(300).setStartDelay(0); - colorAnimation.start(); - } else { - window.setStatusBarColor(color); - } - } - }); - } - - @Override - public void setTranslucent(final boolean translucent) { - final Activity activity = getCurrentActivity(); - if (activity == null) { - FLog.w( - ReactConstants.TAG, - "StatusBarModule: Ignored status bar change, current activity is null."); - return; - } - - UiThreadUtil.runOnUiThread( - new GuardedRunnable(getReactApplicationContext()) { - @Override - public void runGuarded() { - // If the status bar is translucent hook into the window insets calculations - // and consume all the top insets so no padding will be added under the status bar. - Window window = activity.getWindow(); - if (window == null) { - return; - } - View decorView = window.getDecorView(); - if (translucent) { - decorView.setOnApplyWindowInsetsListener( - new View.OnApplyWindowInsetsListener() { - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - WindowInsets defaultInsets = v.onApplyWindowInsets(insets); - return defaultInsets.replaceSystemWindowInsets( - defaultInsets.getSystemWindowInsetLeft(), - 0, - defaultInsets.getSystemWindowInsetRight(), - defaultInsets.getSystemWindowInsetBottom()); - } - }); - } else { - decorView.setOnApplyWindowInsetsListener(null); - } - - ViewCompat.requestApplyInsets(decorView); - } - }); - } - - @Override - public void setHidden(final boolean hidden) { - final Activity activity = getCurrentActivity(); - if (activity == null) { - FLog.w( - ReactConstants.TAG, - "StatusBarModule: Ignored status bar change, current activity is null."); - return; - } - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - Window window = activity.getWindow(); - if (window == null) { - return; - } - if (hidden) { - window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); - } else { - window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); - window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - } - }); - } - - @Override - public void setStyle(@Nullable final String style) { - final Activity activity = getCurrentActivity(); - if (activity == null) { - FLog.w( - ReactConstants.TAG, - "StatusBarModule: Ignored status bar change, current activity is null."); - return; - } - - UiThreadUtil.runOnUiThread( - new Runnable() { - @TargetApi(Build.VERSION_CODES.R) - @Override - public void run() { - Window window = activity.getWindow(); - if (window == null) { - return; - } - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { - WindowInsetsController insetsController = window.getInsetsController(); - if (insetsController == null) { - return; - } - if ("dark-content".equals(style)) { - // dark-content means dark icons on a light status bar - insetsController.setSystemBarsAppearance( - WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, - WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); - } else { - insetsController.setSystemBarsAppearance( - 0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); - } - } else { - View decorView = window.getDecorView(); - int systemUiVisibilityFlags = decorView.getSystemUiVisibility(); - if ("dark-content".equals(style)) { - systemUiVisibilityFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } else { - systemUiVisibilityFlags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } - decorView.setSystemUiVisibility(systemUiVisibilityFlags); - } - } - }); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt new file mode 100644 index 00000000000000..ad6ec6197e2792 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/statusbar/StatusBarModule.kt @@ -0,0 +1,185 @@ +/* + * Copyright (c) Meta Platforms, Inc. and 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.modules.statusbar + +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator +import android.animation.ValueAnimator.AnimatorUpdateListener +import android.os.Build +import android.view.View +import android.view.WindowInsetsController +import android.view.WindowManager +import android.view.WindowManager.LayoutParams +import androidx.core.view.ViewCompat +import com.facebook.common.logging.FLog +import com.facebook.fbreact.specs.NativeStatusBarManagerAndroidSpec +import com.facebook.react.bridge.GuardedRunnable +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.UiThreadUtil +import com.facebook.react.common.ReactConstants +import com.facebook.react.module.annotations.ReactModule +import com.facebook.react.uimanager.PixelUtil + +/** [NativeModule] that allows changing the appearance of the status bar. */ +@ReactModule(name = NativeStatusBarManagerAndroidSpec.NAME) +public class StatusBarModule(reactContext: ReactApplicationContext?) : + NativeStatusBarManagerAndroidSpec(reactContext) { + + override fun getTypedExportedConstants(): Map { + val context = getReactApplicationContext() + val heightResId = context.resources.getIdentifier("status_bar_height", "dimen", "android") + val height = + heightResId + .takeIf { it > 0 } + ?.let { + PixelUtil.toDIPFromPixel(context.resources.getDimensionPixelSize(it).toFloat()) + } ?: 0 + + var statusBarColorString = "black" + val statusBarColor = getCurrentActivity()?.window?.statusBarColor + if (statusBarColor != null) { + statusBarColorString = String.format("#%06X", 0xFFFFFF and statusBarColor) + } + + return mapOf( + HEIGHT_KEY to height, + DEFAULT_BACKGROUND_COLOR_KEY to statusBarColorString, + ) + } + + override fun setColor(colorDouble: Double, animated: Boolean) { + val color = colorDouble.toInt() + val activity = getCurrentActivity() + if (activity == null) { + FLog.w( + ReactConstants.TAG, + "StatusBarModule: Ignored status bar change, current activity is null.") + return + } + UiThreadUtil.runOnUiThread( + object : GuardedRunnable(getReactApplicationContext()) { + override fun runGuarded() { + val window = activity.window ?: return + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) + if (animated) { + val curColor = window.statusBarColor + val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), curColor, color) + colorAnimation.addUpdateListener( + object : AnimatorUpdateListener { + override fun onAnimationUpdate(animator: ValueAnimator) { + activity.window?.statusBarColor = (animator.animatedValue as Int) + } + }) + colorAnimation.setDuration(300).startDelay = 0 + colorAnimation.start() + } else { + window.statusBarColor = color + } + } + }) + } + + @Suppress("DEPRECATION") + override fun setTranslucent(translucent: Boolean) { + val activity = getCurrentActivity() + if (activity == null) { + FLog.w( + ReactConstants.TAG, + "StatusBarModule: Ignored status bar change, current activity is null.") + return + } + UiThreadUtil.runOnUiThread( + object : GuardedRunnable(getReactApplicationContext()) { + override fun runGuarded() { + // If the status bar is translucent hook into the window insets calculations + // and consume all the top insets so no padding will be added under the status bar. + val window = activity.window ?: return + val decorView = window.decorView + if (translucent) { + decorView.setOnApplyWindowInsetsListener { v, insets -> + val defaultInsets = v.onApplyWindowInsets(insets) + defaultInsets.replaceSystemWindowInsets( + defaultInsets.systemWindowInsetLeft, + 0, + defaultInsets.systemWindowInsetRight, + defaultInsets.systemWindowInsetBottom) + } + } else { + decorView.setOnApplyWindowInsetsListener(null) + } + ViewCompat.requestApplyInsets(decorView) + } + }) + } + + @Suppress("DEPRECATION") + override fun setHidden(hidden: Boolean) { + val activity = getCurrentActivity() + if (activity == null) { + FLog.w( + ReactConstants.TAG, + "StatusBarModule: Ignored status bar change, current activity is null.") + return + } + UiThreadUtil.runOnUiThread( + Runnable { + val window = activity.window ?: return@Runnable + if (hidden) { + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + window.clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN) + window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) + } + }) + } + + @Suppress("DEPRECATION") + override fun setStyle(style: String?) { + val activity = getCurrentActivity() + if (activity == null) { + FLog.w( + ReactConstants.TAG, + "StatusBarModule: Ignored status bar change, current activity is null.") + return + } + UiThreadUtil.runOnUiThread( + Runnable { + val window = activity.window ?: return@Runnable + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) { + val insetsController = window.insetsController ?: return@Runnable + if ("dark-content" == style) { + // dark-content means dark icons on a light status bar + insetsController.setSystemBarsAppearance( + WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, + WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS) + } else { + insetsController.setSystemBarsAppearance( + 0, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS) + } + } else { + val decorView = window.decorView + var systemUiVisibilityFlags = decorView.systemUiVisibility + systemUiVisibilityFlags = + if ("dark-content" == style) { + systemUiVisibilityFlags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } else { + systemUiVisibilityFlags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + } + decorView.systemUiVisibility = systemUiVisibilityFlags + } + }) + } + + public companion object { + private const val HEIGHT_KEY = "HEIGHT" + private const val DEFAULT_BACKGROUND_COLOR_KEY = "DEFAULT_BACKGROUND_COLOR" + public const val NAME: String = NativeStatusBarManagerAndroidSpec.NAME + } +} From 4294b2446a6e328293cb67dcec6780ec2ffcb7f6 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Fri, 24 May 2024 04:42:27 -0700 Subject: [PATCH 06/67] Simplify ReactViewGroup clip to border (#44646) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44646 We can remove most of the code for clipping children to border radius, and recalculating paths, in ReactViewGroup, and rely on the padding box path/rect already set. I will move this to something more generic up the stack so other native components can reuse this logic. Changelog: [Internal] Reviewed By: javache Differential Revision: D57668976 fbshipit-source-id: 8b8cf956dc8689827bccba5e41751b465fd85eeb --- .../ReactAndroid/api/ReactAndroid.api | 6 +- .../uimanager/drawable/BoxShadowDrawable.kt | 2 +- .../drawable/CSSBackgroundDrawable.java | 23 +++- .../react/views/view/ReactViewGroup.java | 101 ++---------------- .../js/examples/Border/BorderExample.js | 64 +++++++++++ 5 files changed, 96 insertions(+), 100 deletions(-) diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 474cc0588458bc..2d93de893e7550 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -5557,21 +5557,21 @@ public abstract interface class com/facebook/react/uimanager/debug/NotThreadSafe public class com/facebook/react/uimanager/drawable/CSSBackgroundDrawable : android/graphics/drawable/Drawable { public fun (Landroid/content/Context;)V - public fun borderBoxPath ()Landroid/graphics/Path; public fun draw (Landroid/graphics/Canvas;)V public fun getAlpha ()I + public fun getBorderBoxPath ()Landroid/graphics/Path; public fun getBorderColor (I)I public fun getBorderRadius ()Lcom/facebook/react/uimanager/style/BorderRadiusStyle; public fun getBorderWidthOrDefaultTo (FI)F public fun getComputedBorderRadius ()Lcom/facebook/react/uimanager/style/ComputedBorderRadius; - public fun getDirectionAwareBorderInsets ()Landroid/graphics/RectF; public fun getFullBorderWidth ()F public fun getLayoutDirection ()I public fun getOpacity ()I public fun getOutline (Landroid/graphics/Outline;)V + public fun getPaddingBoxPath ()Landroid/graphics/Path; + public fun getPaddingBoxRect ()Landroid/graphics/RectF; public fun hasRoundedBorders ()Z protected fun onBoundsChange (Landroid/graphics/Rect;)V - public fun paddingBoxPath ()Landroid/graphics/Path; public fun setAlpha (I)V public fun setBorderColor (IFF)V public fun setBorderRadius (Lcom/facebook/react/uimanager/style/BorderRadiusProp;Lcom/facebook/react/uimanager/LengthPercentage;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BoxShadowDrawable.kt index 9f8f436265eeaf..25332053feb060 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/BoxShadowDrawable.kt @@ -81,7 +81,7 @@ internal class BoxShadowDrawable( } with(canvas) { - clipOutPath(background.borderBoxPath()) + clipOutPath(background.getBorderBoxPath()) drawRenderNode(renderNode) } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java index cd3e0dfed058e5..38bbd075d941af 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CSSBackgroundDrawable.java @@ -316,22 +316,35 @@ public int getColor() { return mColor; } - public Path borderBoxPath() { + public Path getBorderBoxPath() { updatePath(); return Preconditions.checkNotNull(mOuterClipPathForBorderRadius); } - public Path paddingBoxPath() { + public Path getPaddingBoxPath() { updatePath(); return Preconditions.checkNotNull(mInnerClipPathForBorderRadius); } + public RectF getPaddingBoxRect() { + RectF insets = getDirectionAwareBorderInsets(); + if (insets == null) { + return new RectF(0, 0, getBounds().width(), getBounds().height()); + } + + return new RectF( + insets.left, + insets.top, + getBounds().width() - insets.right, + getBounds().height() - insets.bottom); + } + private void drawRoundedBackgroundWithBorders(Canvas canvas) { updatePath(); canvas.save(); // Clip outer border - canvas.clipPath(borderBoxPath(), Region.Op.INTERSECT); + canvas.clipPath(getBorderBoxPath(), Region.Op.INTERSECT); // Draws the View without its border first (with background color fill) int useColor = ColorUtils.setAlphaComponent(mColor, getOpacity()); @@ -390,7 +403,7 @@ private void drawRoundedBackgroundWithBorders(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); // Clip inner border - canvas.clipPath(paddingBoxPath(), Region.Op.DIFFERENCE); + canvas.clipPath(getPaddingBoxPath(), Region.Op.DIFFERENCE); final boolean isRTL = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; int colorStart = getBorderColor(Spacing.START); @@ -1304,7 +1317,7 @@ public int getBorderColor(int position) { return CSSBackgroundDrawable.colorFromAlphaAndRGBComponents(alpha, rgb); } - public RectF getDirectionAwareBorderInsets() { + private RectF getDirectionAwareBorderInsets() { final float borderWidth = getBorderWidthOrDefaultTo(0, Spacing.ALL); final float borderTopWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.TOP); final float borderBottomWidth = getBorderWidthOrDefaultTo(borderWidth, Spacing.BOTTOM); diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java index 3114e2cfdc14e0..e785e56e266540 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java @@ -16,7 +16,6 @@ import android.graphics.Color; import android.graphics.Path; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.view.MotionEvent; @@ -27,7 +26,6 @@ import androidx.annotation.Nullable; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactNoCrashSoftException; import com.facebook.react.bridge.ReactSoftExceptionLogger; import com.facebook.react.bridge.UiThreadUtil; @@ -37,7 +35,6 @@ import com.facebook.react.touch.OnInterceptTouchEventListener; import com.facebook.react.touch.ReactHitSlopView; import com.facebook.react.touch.ReactInterceptingViewGroup; -import com.facebook.react.uimanager.IllegalViewOperationException; import com.facebook.react.uimanager.LengthPercentage; import com.facebook.react.uimanager.MeasureSpecAssertions; import com.facebook.react.uimanager.PointerEvents; @@ -47,15 +44,13 @@ import com.facebook.react.uimanager.ReactOverflowViewWithInset; import com.facebook.react.uimanager.ReactPointerEventsView; import com.facebook.react.uimanager.ReactZIndexedViewGroup; -import com.facebook.react.uimanager.RootView; -import com.facebook.react.uimanager.RootViewUtil; import com.facebook.react.uimanager.ViewGroupDrawingOrderHelper; import com.facebook.react.uimanager.ViewProps; import com.facebook.react.uimanager.common.UIManagerType; import com.facebook.react.uimanager.common.ViewUtil; import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable; import com.facebook.react.uimanager.style.BorderRadiusProp; -import com.facebook.react.uimanager.style.ComputedBorderRadius; +import java.util.Objects; /** * Backing for a React View. Has support for borders, but since borders aren't common, lazy @@ -129,7 +124,6 @@ public void onLayoutChange( private @Nullable OnInterceptTouchEventListener mOnInterceptTouchEventListener; private boolean mNeedsOffscreenAlphaCompositing; private @Nullable ViewGroupDrawingOrderHelper mDrawingOrderHelper; - private @Nullable Path mPath; private float mBackfaceOpacity; private String mBackfaceVisibility; @@ -158,7 +152,6 @@ private void initView() { mOnInterceptTouchEventListener = null; mNeedsOffscreenAlphaCompositing = false; mDrawingOrderHelper = null; - mPath = null; mBackfaceOpacity = 1.f; mBackfaceVisibility = "visible"; } @@ -850,25 +843,18 @@ public Rect getOverflowInset() { @Override protected void dispatchDraw(Canvas canvas) { - try { - dispatchOverflowDraw(canvas); - super.dispatchDraw(canvas); - } catch (NullPointerException | StackOverflowError e) { - // Adding special exception management for StackOverflowError for logging purposes. - // This will be removed in the future. - RootView rootView = RootViewUtil.getRootView(ReactViewGroup.this); - if (rootView != null) { - rootView.handleException(e); + if (mCSSBackgroundDrawable != null + && (Objects.equals(mOverflow, ViewProps.HIDDEN) + || Objects.equals(mOverflow, ViewProps.SCROLL))) { + @Nullable Path paddingBoxPath = mCSSBackgroundDrawable.getPaddingBoxPath(); + if (paddingBoxPath != null) { + canvas.clipPath(paddingBoxPath); } else { - if (getContext() instanceof ReactContext) { - ReactContext reactContext = (ReactContext) getContext(); - reactContext.handleException( - new IllegalViewOperationException("StackOverflowException", this, e)); - } else { - throw e; - } + canvas.clipRect(mCSSBackgroundDrawable.getPaddingBoxRect()); } } + + super.dispatchDraw(canvas); } @Override @@ -887,73 +873,6 @@ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return result; } - private void dispatchOverflowDraw(Canvas canvas) { - if (mOverflow != null) { - switch (mOverflow) { - case ViewProps.VISIBLE: - if (mPath != null) { - mPath.rewind(); - } - break; - case ViewProps.HIDDEN: - case ViewProps.SCROLL: - float left = 0f; - float top = 0f; - float right = getWidth(); - float bottom = getHeight(); - - boolean hasClipPath = false; - - if (mCSSBackgroundDrawable != null) { - final RectF borderWidth = mCSSBackgroundDrawable.getDirectionAwareBorderInsets(); - - if (borderWidth.top > 0 - || borderWidth.left > 0 - || borderWidth.bottom > 0 - || borderWidth.right > 0) { - left += borderWidth.left; - top += borderWidth.top; - right -= borderWidth.right; - bottom -= borderWidth.bottom; - } - - final ComputedBorderRadius borderRadius = - mCSSBackgroundDrawable.getComputedBorderRadius(); - - if (borderRadius.hasRoundedBorders()) { - if (mPath == null) { - mPath = new Path(); - } - - mPath.rewind(); - mPath.addRoundRect( - new RectF(left, top, right, bottom), - new float[] { - Math.max(borderRadius.getTopLeft() - borderWidth.left, 0), - Math.max(borderRadius.getTopLeft() - borderWidth.top, 0), - Math.max(borderRadius.getTopRight() - borderWidth.right, 0), - Math.max(borderRadius.getTopRight() - borderWidth.top, 0), - Math.max(borderRadius.getBottomRight() - borderWidth.right, 0), - Math.max(borderRadius.getBottomRight() - borderWidth.bottom, 0), - Math.max(borderRadius.getBottomLeft() - borderWidth.left, 0), - Math.max(borderRadius.getBottomLeft() - borderWidth.bottom, 0), - }, - Path.Direction.CW); - canvas.clipPath(mPath); - hasClipPath = true; - } - } - - if (!hasClipPath) { - canvas.clipRect(new RectF(left, top, right, bottom)); - } - break; - default: - break; - } - } - } - public void setOpacityIfPossible(float opacity) { mBackfaceOpacity = opacity; setBackfaceVisibilityDependantOpacity(); diff --git a/packages/rn-tester/js/examples/Border/BorderExample.js b/packages/rn-tester/js/examples/Border/BorderExample.js index 12e9a08c3e3422..e8a7a7e87bd82b 100644 --- a/packages/rn-tester/js/examples/Border/BorderExample.js +++ b/packages/rn-tester/js/examples/Border/BorderExample.js @@ -12,9 +12,11 @@ import type {RNTesterModule} from '../../types/RNTesterTypes'; +import hotdog from '../../assets/hotdog.jpg'; import * as React from 'react'; import { DynamicColorIOS, + Image, Platform, PlatformColor, StyleSheet, @@ -214,6 +216,23 @@ const styles = StyleSheet.create({ ? DynamicColorIOS({light: 'magenta', dark: 'cyan'}) : 'black', }, + borderWithoutClipping: { + borderWidth: 10, + overflow: 'visible', + }, + borderWithClipping: { + borderWidth: 10, + overflow: 'hidden', + }, + borderWithClippingAndRadius: { + borderWidth: 10, + borderRadius: 30, + overflow: 'hidden', + }, + hotdog: { + width: 100, + height: 100, + }, }); export default ({ @@ -477,5 +496,50 @@ export default ({ ); }, }, + { + title: 'Child without clipping', + name: 'child-no-clipping', + description: + '"overflow: visible" will cause child content to show above borders', + render: function (): React.Node { + return ( + + + + ); + }, + }, + { + title: 'Child clipping', + name: 'child-clipping', + description: + '"overflow: hidden" will cause child content to be clipped to borders', + render: function (): React.Node { + return ( + + + + ); + }, + }, + { + title: 'Child clipping with radius', + name: 'child-clipping-radius', + description: + '"overflow: hidden" will cause child content to be clipped to rounded corners', + render: function (): React.Node { + return ( + + + + ); + }, + }, ], }: RNTesterModule); From c13790ff1d11ef95ad04f7d7dc87f09a9cbf7025 Mon Sep 17 00:00:00 2001 From: Nishan Date: Fri, 24 May 2024 04:50:41 -0700 Subject: [PATCH 07/67] feat(android): percentage support in translate (#43193) Summary: This PR adds percentage support in translate properties for android. Isolating this PR for easier reviews. ## Changelog: [Android] [ADDED] - Percentage support in translate + + - `,this.contentElement,{host:this})}}var m=Object.freeze({__proto__:null,RNWelcomeImpl:d});export{m as RNWelcome}; + `,this.contentElement,{host:this})}}var m=Object.freeze({__proto__:null,RNWelcomeImpl:g});export{m as RNWelcome}; diff --git a/packages/debugger-frontend/dist/third-party/front_end/ui/legacy/legacy.js b/packages/debugger-frontend/dist/third-party/front_end/ui/legacy/legacy.js index e6fcab1b52fc6e..c9899941e5f8c9 100644 --- a/packages/debugger-frontend/dist/third-party/front_end/ui/legacy/legacy.js +++ b/packages/debugger-frontend/dist/third-party/front_end/ui/legacy/legacy.js @@ -1,3 +1,3 @@ -import*as e from"../../core/common/common.js";import*as t from"../../core/i18n/i18n.js";import*as i from"../../core/platform/platform.js";import*as n from"../../core/root/root.js";import*as s from"../../core/host/host.js";import*as o from"../visual_logging/visual_logging.js";import*as r from"../../models/text_utils/text_utils.js";import*as a from"../components/icon_button/icon_button.js";import*as l from"../components/adorners/adorners.js";import*as h from"../components/settings/settings.js";import*as d from"./utils/utils.js";export{d as Utils};import*as c from"../../core/dom_extension/dom_extension.js";import*as u from"../components/helpers/helpers.js";import*as m from"./theme_support/theme_support.js";import*as p from"../lit-html/lit-html.js";let g;class b{flavorsInternal;eventDispatchers;constructor(){this.flavorsInternal=new Map,this.eventDispatchers=new Map}static instance(e={forceNew:null}){const{forceNew:t}=e;return g&&!t||(g=new b),g}static removeInstance(){g=void 0}setFlavor(e,t){(this.flavorsInternal.get(e)||null)!==t&&(t?this.flavorsInternal.set(e,t):this.flavorsInternal.delete(e),this.dispatchFlavorChange(e,t))}dispatchFlavorChange(e,t){for(const i of f)i.contextTypes().includes(e)&&i.loadListener().then((e=>e.flavorChanged(t)));const i=this.eventDispatchers.get(e);i&&i.dispatchEventToListeners("FlavorChanged",t)}addFlavorChangeListener(t,i,n){let s=this.eventDispatchers.get(t);s||(s=new e.ObjectWrapper.ObjectWrapper,this.eventDispatchers.set(t,s)),s.addEventListener("FlavorChanged",i,n)}removeFlavorChangeListener(e,t,i){const n=this.eventDispatchers.get(e);n&&(n.removeEventListener("FlavorChanged",t,i),n.hasEventListeners("FlavorChanged")||this.eventDispatchers.delete(e))}flavor(e){return this.flavorsInternal.get(e)||null}flavors(){return new Set(this.flavorsInternal.keys())}}const f=[];var v=Object.freeze({__proto__:null,Context:b,registerListener:function(e){f.push(e)}});const w={elements:"Elements",screenshot:"Screenshot",network:"Network",memory:"Memory",javascript_profiler:"JavaScript Profiler",console:"Console",performance:"Performance",mobile:"Mobile",help:"Help",layers:"Layers",navigation:"Navigation",drawer:"Drawer",global:"Global",resources:"Resources",background_services:"Background Services",settings:"Settings",debugger:"Debugger",sources:"Sources",rendering:"Rendering",recorder:"Recorder",changes:"Changes"},x=t.i18n.registerUIStrings("ui/legacy/ActionRegistration.ts",w),E=t.i18n.getLocalizedString.bind(void 0,x);class I extends e.ObjectWrapper.ObjectWrapper{enabledInternal=!0;toggledInternal=!1;actionRegistration;constructor(e){super(),this.actionRegistration=e}id(){return this.actionRegistration.actionId}async execute(){if(!this.actionRegistration.loadActionDelegate)return!1;const e=await this.actionRegistration.loadActionDelegate(),t=this.id();return e.handleAction(b.instance(),t)}icon(){return this.actionRegistration.iconClass}toggledIcon(){return this.actionRegistration.toggledIconClass}toggleWithRedColor(){return Boolean(this.actionRegistration.toggleWithRedColor)}setEnabled(e){this.enabledInternal!==e&&(this.enabledInternal=e,this.dispatchEventToListeners("Enabled",e))}enabled(){return this.enabledInternal}category(){return this.actionRegistration.category}tags(){if(this.actionRegistration.tags)return this.actionRegistration.tags.map((e=>e())).join("\0")}toggleable(){return Boolean(this.actionRegistration.toggleable)}title(){let e=this.actionRegistration.title?this.actionRegistration.title():t.i18n.lockedString("");const i=this.actionRegistration.options;if(i)for(const t of i)t.value!==this.toggledInternal&&(e=t.title());return e}toggled(){return this.toggledInternal}setToggled(e){console.assert(this.toggleable(),"Shouldn't be toggling an untoggleable action",this.id()),this.toggledInternal!==e&&(this.toggledInternal=e,this.dispatchEventToListeners("Toggled",e))}options(){return this.actionRegistration.options}contextTypes(){if(this.actionRegistration.contextTypes)return this.actionRegistration.contextTypes()}canInstantiate(){return Boolean(this.actionRegistration.loadActionDelegate)}bindings(){return this.actionRegistration.bindings}experiment(){return this.actionRegistration.experiment}setting(){return this.actionRegistration.setting}condition(){return this.actionRegistration.condition}order(){return this.actionRegistration.order}}const y=new Map;function S(){y.clear()}function C(){return Array.from(y.values()).filter((t=>{const i=t.setting();try{if(i&&!e.Settings.moduleSetting(i).get())return!1}catch(e){if(e.message.startsWith("No setting registered"))return!1}return n.Runtime.Runtime.isDescriptorEnabled({experiment:t.experiment(),condition:t.condition()})})).sort(((e,t)=>(e.order()||0)-(t.order()||0)))}var T=Object.freeze({__proto__:null,Action:I,registerActionExtension:function(e){const t=e.actionId;if(y.has(t))throw new Error(`Duplicate action ID '${t}'`);if(!i.StringUtilities.isExtendedKebabCase(t))throw new Error(`Invalid action ID '${t}'`);y.set(t,new I(e))},reset:S,getRegisteredActionExtensions:C,maybeRemoveActionExtension:function(e){return y.delete(e)},getLocalizedActionCategory:function(e){switch(e){case"ELEMENTS":return E(w.elements);case"SCREENSHOT":return E(w.screenshot);case"NETWORK":return E(w.network);case"MEMORY":return E(w.memory);case"JAVASCRIPT_PROFILER":return E(w.javascript_profiler);case"CONSOLE":return E(w.console);case"PERFORMANCE":return E(w.performance);case"MOBILE":return E(w.mobile);case"HELP":return E(w.help);case"LAYERS":return E(w.layers);case"NAVIGATION":return E(w.navigation);case"DRAWER":return E(w.drawer);case"GLOBAL":return E(w.global);case"RESOURCES":return E(w.resources);case"BACKGROUND_SERVICES":return E(w.background_services);case"SETTINGS":return E(w.settings);case"DEBUGGER":return E(w.debugger);case"SOURCES":return E(w.sources);case"RENDERING":return E(w.rendering);case"RECORDER":return E(w.recorder);case"CHANGES":return E(w.changes);case"":return t.i18n.lockedString("")}return t.i18n.lockedString(e)}});let k;class M{actionsById;constructor(){this.actionsById=new Map,this.registerActions()}static instance(e={forceNew:null}){const{forceNew:t}=e;return k&&!t||(k=new M),k}static removeInstance(){k=void 0}static reset(){M.removeInstance(),S()}registerActions(){for(const e of C())this.actionsById.set(e.id(),e),e.canInstantiate()||e.setEnabled(!1)}availableActions(){return this.applicableActions([...this.actionsById.keys()],b.instance())}actions(){return[...this.actionsById.values()]}applicableActions(e,t){const i=[];for(const s of e){const e=this.actionsById.get(s);e&&e.enabled()&&n(e,t.flavors())&&i.push(e)}return i;function n(e,t){const i=e.contextTypes();if(!i)return!0;for(let e=0;e0?Math.PI/2:-Math.PI/2,n=0):e.m13>0?(t=Math.atan2(-e.m21,e.m22),i=Math.asin(e.m23),n=-Math.PI/2):(t=Math.atan2(e.m21,-e.m22),i=-Math.asin(e.m23),i+=i>0||Math.abs(i)0?(t=Math.atan2(-e.m21,e.m22),i=Math.asin(e.m23),n=Math.atan2(-e.m13,e.m33)):(t=Math.atan2(e.m21,-e.m22),i=-Math.asin(e.m23),i+=i>0||Math.abs(i)this.preferred.width||this.minimum.height>this.preferred.height)throw new Error("Minimum size is greater than preferred.")}isEqual(e){return null!==e&&this.minimum.isEqual(e.minimum)&&this.preferred.isEqual(e.preferred)}widthToMax(e){return"number"==typeof e?new je(this.minimum.widthToMax(e),this.preferred.widthToMax(e)):new je(this.minimum.widthToMax(e.minimum),this.preferred.widthToMax(e.preferred))}addWidth(e){return"number"==typeof e?new je(this.minimum.addWidth(e),this.preferred.addWidth(e)):new je(this.minimum.addWidth(e.minimum),this.preferred.addWidth(e.preferred))}heightToMax(e){return"number"==typeof e?new je(this.minimum.heightToMax(e),this.preferred.heightToMax(e)):new je(this.minimum.heightToMax(e.minimum),this.preferred.heightToMax(e.preferred))}addHeight(e){return"number"==typeof e?new je(this.minimum.addHeight(e),this.preferred.addHeight(e)):new je(this.minimum.addHeight(e.minimum),this.preferred.addHeight(e.preferred))}}var Ve=Object.freeze({__proto__:null,_Eps:Ae,Vector:Re,Point:Be,CubicBezier:Oe,LINEAR_BEZIER:Fe,EulerAngles:ze,scalarProduct:We,crossProduct:function(e,t){const i=e.y*t.z-e.z*t.y,n=e.z*t.x-e.x*t.z,s=e.x*t.y-e.y*t.x;return new Re(i,n,s)},subtract:function(e,t){const i=e.x-t.x,n=e.y-t.y,s=e.z-t.z;return new Re(i,n,s)},multiplyVectorByMatrixAndNormalize:He,calculateAngle:function(e,t){const i=e.length(),n=t.length();if(i<=Ae||n<=Ae)return 0;const s=We(e,t)/i/n;return Math.abs(s)>1?0:Ne(Math.acos(s))},degreesToRadians:function(e){return e*Math.PI/180},degreesToGradians:function(e){return e/9*10},degreesToTurns:function(e){return e/360},radiansToDegrees:Ne,radiansToGradians:function(e){return 200*e/Math.PI},radiansToTurns:function(e){return e/(2*Math.PI)},gradiansToRadians:function(e){return e*Math.PI/200},turnsToRadians:function(e){return 2*e*Math.PI},boundsForTransformedPoints:function(e,t,i){i||(i={minX:1/0,maxX:-1/0,minY:1/0,maxY:-1/0}),t.length%3&&console.warn("Invalid size of points array");for(let n=0;ne.name)).join(" ")}isDefault(){return"DefaultShortcut"===this.type||"DisabledDefault"===this.type||"KeybindSetShortcut"===this.type&&this.keybindSets.has(Hs)}changeType(e){return new Ke(this.descriptors,this.action,e)}changeKeys(e){return this.descriptors=e,this}descriptorsMatch(e){return e.length===this.descriptors.length&&e.every(((e,t)=>e.key===this.descriptors[t].key))}hasKeybindSet(e){return!this.keybindSets||this.keybindSets.has(e)}equals(e){return this.descriptorsMatch(e.descriptors)&&this.type===e.type&&this.action===e.action}static createShortcutFromSettingObject(e){return new Ke(e.descriptors,e.action,e.type)}static makeKey(e,t){return"string"==typeof e&&(e=e.charCodeAt(0)-(/^[a-z]/.test(e)?32:0)),t=t||qe.None,Ke.makeKeyFromCodeAndModifiers(e,t)}static makeKeyFromEvent(e){let t=qe.None;e.shiftKey&&(t|=qe.Shift),e.ctrlKey&&(t|=qe.Ctrl),e.altKey&&(t|=qe.Alt),e.metaKey&&(t|=qe.Meta);const i=e.keyCode||e.__keyCode;return Ke.makeKeyFromCodeAndModifiers(i,t)}static makeKeyFromEventIgnoringModifiers(e){const t=e.keyCode||e.__keyCode;return Ke.makeKeyFromCodeAndModifiers(t,qe.None)}static eventHasCtrlEquivalentKey(e){return s.Platform.isMac()?e.metaKey&&!e.ctrlKey:e.ctrlKey&&!e.metaKey}static eventHasEitherCtrlOrMeta(e){return e.metaKey||e.ctrlKey}static hasNoModifiers(e){const t=e;return!(t.ctrlKey||t.shiftKey||t.altKey||t.metaKey)}static makeDescriptor(e,t){return{key:Ke.makeKey("string"==typeof e?e:e.code,t),name:Ke.shortcutToString(e,t)}}static makeDescriptorFromBindingShortcut(e){const[t,...i]=e.split(/\+(?!$)/).reverse();let n=0;for(const t of i){const i=qe[t];console.assert(void 0!==i,`Only one key other than modifier is allowed in shortcut <${e}>`),n|=i}console.assert(t.length>0,`Modifiers-only shortcuts are not allowed (encountered <${e}>)`);const s=nt[t]||st[t];return s&&"shiftKey"in s&&s.shiftKey&&(n|=qe.Shift),Ke.makeDescriptor(s||t,n)}static shortcutToString(e,t){return"string"!=typeof e&&Ke.isModifier(e.code)?Ke.modifiersToString(t):Ke.modifiersToString(t)+Ke.keyName(e)}static keyName(e){return"string"==typeof e?e.toUpperCase():"string"==typeof e.name?e.name:e.name[s.Platform.platform()]||e.name.other||""}static makeKeyFromCodeAndModifiers(e,t){return 255&e|(t||0)<<8}static keyCodeAndModifiersFromKey(e){return{keyCode:255&e,modifiers:e>>8}}static isModifier(e){const{keyCode:t}=Ke.keyCodeAndModifiersFromKey(e);return t===nt.Shift.code||t===nt.Ctrl.code||t===nt.Alt.code||t===nt.Meta.code}static modifiersToString(e){const t=s.Platform.isMac(),i=qe,n=new Map([[i.Ctrl,t?"Ctrl ":"Ctrl + "],[i.Alt,t?"⌥ ":"Alt + "],[i.Shift,t?"⇧ ":"Shift + "],[i.Meta,t?"⌘ ":"Win + "]]);return[i.Meta,i.Ctrl,i.Alt,i.Shift].map((function(t){return(e||0)&t?n.get(t):""})).join("")}}const qe={None:0,Shift:1,Ctrl:2,Alt:4,Meta:8,CtrlOrMeta:s.Platform.isMac()?8:2,ShiftOrOption:s.Platform.isMac()?4:1},$e={code:37,name:"←"},Ge={code:38,name:"↑"},Xe={code:39,name:"→"},Ye={code:40,name:"↓"},Qe={code:17,name:"Ctrl"},Ze={code:27,name:"Esc"},Je={code:32,name:"Space"},et={code:187,name:"+"},tt={code:192,name:"`"},it={code:222,name:"'"},nt={Backspace:{code:8,name:"↤"},Tab:{code:9,name:{mac:"⇥",other:"Tab"}},Enter:{code:13,name:{mac:"↩",other:"Enter"}},Shift:{code:16,name:{mac:"⇧",other:"Shift"}},Ctrl:Qe,Control:Qe,Alt:{code:18,name:"Alt"},Esc:Ze,Escape:Ze,Space:Je," ":Je,PageUp:{code:33,name:{mac:"⇞",other:"PageUp"}},PageDown:{code:34,name:{mac:"⇟",other:"PageDown"}},End:{code:35,name:{mac:"↗",other:"End"}},Home:{code:36,name:{mac:"↖",other:"Home"}},Left:$e,Up:Ge,Right:Xe,Down:Ye,ArrowLeft:$e,ArrowUp:Ge,ArrowRight:Xe,ArrowDown:Ye,Delete:{code:46,name:"Del"},Zero:{code:48,name:"0"},H:{code:72,name:"H"},N:{code:78,name:"N"},P:{code:80,name:"P"},Meta:{code:91,name:"Meta"},F1:{code:112,name:"F1"},F2:{code:113,name:"F2"},F3:{code:114,name:"F3"},F4:{code:115,name:"F4"},F5:{code:116,name:"F5"},F6:{code:117,name:"F6"},F7:{code:118,name:"F7"},F8:{code:119,name:"F8"},F9:{code:120,name:"F9"},F10:{code:121,name:"F10"},F11:{code:122,name:"F11"},F12:{code:123,name:"F12"},Semicolon:{code:186,name:";"},NumpadPlus:{code:107,name:"Numpad +"},NumpadMinus:{code:109,name:"Numpad -"},Numpad0:{code:96,name:"Numpad 0"},Plus:et,Equal:et,Comma:{code:188,name:","},Minus:{code:189,name:"-"},Period:{code:190,name:"."},Slash:{code:191,name:"/"},QuestionMark:{code:191,name:"?"},Apostrophe:tt,Tilde:{code:192,name:"Tilde"},Backquote:tt,IntlBackslash:tt,LeftSquareBracket:{code:219,name:"["},RightSquareBracket:{code:221,name:"]"},Backslash:{code:220,name:"\\"},SingleQuote:it,Quote:it,get CtrlOrMeta(){return s.Platform.isMac()?this.Meta:this.Ctrl}},st={};!function(){for(const e in nt){const t=nt[e];if("object"==typeof t&&t.code){const i="string"==typeof t.name?t.name:e;st[i]=t}}}();var ot=Object.freeze({__proto__:null,KeyboardShortcut:Ke,Modifiers:qe,Keys:nt,KeyBindings:st}),rt={cssContent:"::slotted(input.dt-radio-button){height:17px;width:17px;min-width:17px;border-radius:8px;vertical-align:middle;margin:0 5px 5px 0;accent-color:var(--sys-color-primary-bright);color:var(--sys-color-on-primary)}::slotted(input.dt-radio-button:focus){box-shadow:var(--legacy-focus-ring-active-shadow)}@media (forced-colors: active){::slotted(input.dt-radio-button){--gradient-start:ButtonFace;--gradient-end:ButtonFace}::slotted(input.dt-radio-button:checked){--gradient-start:Highlight;--gradient-end:Highlight}}"},at={cssContent:".dt-range-input{appearance:none;margin:0;padding:0;height:10px;width:88px;outline:none;background:none}.dt-range-input::-webkit-slider-thumb,\n.-theme-preserve{appearance:none;margin:0;padding:0;border:0;width:12px;height:12px;margin-top:-5px;border-radius:50%;background-color:var(--sys-color-primary)}.dt-range-input::-webkit-slider-runnable-track{appearance:none;margin:0;padding:0;width:100%;height:2px;background-color:var(--sys-color-surface-variant)}.dt-range-input:focus::-webkit-slider-thumb{box-shadow:0 0 0 2px var(--sys-color-inverse-primary)}.dt-range-input:disabled::-webkit-slider-thumb{background-color:var(--sys-color-state-disabled)}@media (forced-colors: active){.dt-range-input{forced-color-adjust:none}}"},lt={cssContent:"div{display:inline-flex;height:14px;align-items:center;vertical-align:middle;white-space:nowrap;padding:1px 4px;text-align:left;font-size:11px;line-height:normal;font-weight:bold;text-shadow:none;color:var(--sys-color-inverse-on-surface);border-radius:7px}div.verbose{background-color:var(--sys-color-token-attribute-value)}:host-context(.-theme-with-dark-background) div.verbose{background-color:var(--sys-color-token-tag)}div.info{background-color:var(--sys-color-token-meta)}div.warning{background-color:var(--sys-color-token-attribute)}:host-context(.-theme-with-dark-background) div.warning{background-color:var(--sys-color-token-attribute-value)}div.error{background-color:var(--sys-color-error-bright)}"};const ht={close:"Close",dockToRight:"Dock to right",dockToBottom:"Dock to bottom",dockToLeft:"Dock to left",undockIntoSeparateWindow:"Undock into separate window",devtoolsUndocked:"DevTools is undocked",devToolsDockedTo:"DevTools is docked to {PH1}"},dt=t.i18n.registerUIStrings("ui/legacy/DockController.ts",ht),ct=t.i18n.getLocalizedString.bind(void 0,dt);let ut;class mt extends e.ObjectWrapper.ObjectWrapper{canDockInternal;closeButton;currentDockStateSetting;lastDockStateSetting;dockSideInternal=void 0;titles;savedFocus;constructor(t){if(super(),this.canDockInternal=t,this.closeButton=new wn(ct(ht.close),"cross"),this.closeButton.element.setAttribute("jslog",`${o.close().track({click:!0})}`),this.closeButton.element.classList.add("close-devtools"),this.closeButton.addEventListener("Click",s.InspectorFrontendHost.InspectorFrontendHostInstance.closeWindow.bind(s.InspectorFrontendHost.InspectorFrontendHostInstance)),this.currentDockStateSetting=e.Settings.Settings.instance().moduleSetting("currentDockState"),this.lastDockStateSetting=e.Settings.Settings.instance().createSetting("last-dock-state","bottom"),!t)return this.dockSideInternal="undocked",void this.closeButton.setVisible(!1);this.currentDockStateSetting.addChangeListener(this.dockSideChanged,this),-1===pt.indexOf(this.currentDockStateSetting.get())&&this.currentDockStateSetting.set("right"),-1===pt.indexOf(this.lastDockStateSetting.get())&&this.currentDockStateSetting.set("bottom")}static instance(e={forceNew:null,canDock:!1}){const{forceNew:t,canDock:i}=e;return ut&&!t||(ut=new mt(i)),ut}initialize(){this.canDockInternal&&(this.titles=[ct(ht.dockToRight),ct(ht.dockToBottom),ct(ht.dockToLeft),ct(ht.undockIntoSeparateWindow)],this.dockSideChanged())}dockSideChanged(){this.setDockSide(this.currentDockStateSetting.get()),setTimeout(this.announceDockLocation.bind(this),2e3)}dockSide(){return this.dockSideInternal}canDock(){return this.canDockInternal}isVertical(){return"right"===this.dockSideInternal||"left"===this.dockSideInternal}setDockSide(e){if(-1===pt.indexOf(e)&&(e=pt[0]),this.dockSideInternal===e)return;void 0!==this.dockSideInternal&&document.body.classList.remove(this.dockSideInternal),document.body.classList.add(e),this.dockSideInternal&&this.lastDockStateSetting.set(this.dockSideInternal),this.savedFocus=i.DOMUtilities.deepActiveElement(document);const t={from:this.dockSideInternal,to:e};this.dispatchEventToListeners("BeforeDockSideChanged",t),console.timeStamp("DockController.setIsDocked"),this.dockSideInternal=e,this.currentDockStateSetting.set(e),s.InspectorFrontendHost.InspectorFrontendHostInstance.setIsDocked("undocked"!==e,this.setIsDockedResponse.bind(this,t)),this.closeButton.setVisible("undocked"!==this.dockSideInternal),this.dispatchEventToListeners("DockSideChanged",t)}setIsDockedResponse(e){this.dispatchEventToListeners("AfterDockSideChanged",e),this.savedFocus&&(this.savedFocus.focus(),this.savedFocus=null)}toggleDockSide(){if(this.lastDockStateSetting.get()===this.currentDockStateSetting.get()){const e=pt.indexOf(this.currentDockStateSetting.get())||0;this.lastDockStateSetting.set(pt[(e+1)%pt.length])}this.setDockSide(this.lastDockStateSetting.get())}announceDockLocation(){"undocked"===this.dockSideInternal?Se(ct(ht.devtoolsUndocked)):Se(ct(ht.devToolsDockedTo,{PH1:this.dockSideInternal||""}))}}const pt=["right","bottom","left","undocked"];let gt;class bt{static instance(e={forceNew:null}){const{forceNew:t}=e;return gt&&!t||(gt=new bt),gt}item(){return mt.instance().closeButton}}var ft=Object.freeze({__proto__:null,DockController:mt,ToggleDockActionDelegate:class{handleAction(e,t){return mt.instance().toggleDockSide(),!0}},CloseButtonProvider:bt}),vt={cssContent:".infobar{color:var(--sys-color-on-surface);display:flex;flex:auto;flex-direction:column;position:relative;padding:6px;min-width:fit-content}.infobar:focus{outline:2px solid var(--sys-color-state-focus-ring);outline-offset:-2px}.infobar-warning{background-color:var(--sys-color-surface-yellow);color:var(--sys-color-on-surface-yellow)}.infobar-error{--override-infobar-error-background:var(--sys-color-surface-error);--override-infobar-error-text:var(--sys-color-on-surface-error);background-color:var(--override-infobar-error-background);color:var(--override-infobar-error-text)}.infobar-main-row{display:flex;flex-direction:row;justify-content:flex-start;min-height:25px}.infobar-info-container{display:flex;align-items:center;flex-grow:1;flex-wrap:wrap}.infobar-info-message{display:flex;margin:5px 0}.infobar-info-text{display:flex;align-items:center;margin:0 4px}.infobar-details-rows{padding:5px 5px 0}.infobar-details-row{display:flex;flex-direction:column;line-height:18px;padding-bottom:6px}.infobar-close-container{display:flex;flex-shrink:0;align-items:center}.infobar-close-container > .infobar-button.link-style{margin:4px}.infobar-selectable{user-select:text}.infobar-button{color:var(--sys-color-token-subtle);padding:0 4px}.info-icon{mask-image:var(--image-file-info);background-color:var(--icon-info)}.warning-icon{mask-image:var(--image-file-warning);background-color:var(--icon-warning)}.error-icon{mask-image:var(--image-file-cross-circle);background-color:var(--icon-error)}.issue-icon{mask-image:var(--image-file-issue-text-filled);background-color:var(--icon-info)}.icon{mask-size:20px 20px;width:20px;height:20px;flex-shrink:0}.devtools-link.text-button:hover,\n.devtools-link.text-button:focus,\n.devtools-link.text-button:active{background-color:transparent;box-shadow:none}"};const wt={dontShowAgain:"Don't show again",showMore:"Show more",close:"Close"},xt=t.i18n.registerUIStrings("ui/legacy/Infobar.ts",wt),Et=t.i18n.getLocalizedString.bind(void 0,xt);class It{element;shadowRoot;contentElement;mainRow;detailsRows;hasDetails;detailsMessage;infoContainer;infoMessage;infoText;actionContainer;disableSetting;closeContainer;toggleElement;closeButton;closeCallback;#e=null;parentView;constructor(e,t,i,n,s=!0,r){if(this.element=document.createElement("div"),r&&this.element.setAttribute("jslog",`${o.dialog(r).track({resize:!0})}`),this.element.classList.add("flex-none"),this.shadowRoot=d.createShadowRootWithCoreStyles(this.element,{cssFile:vt,delegatesFocus:void 0}),this.contentElement=this.shadowRoot.createChild("div","infobar infobar-"+e),this.mainRow=this.contentElement.createChild("div","infobar-main-row"),this.detailsRows=this.contentElement.createChild("div","infobar-details-rows hidden"),this.hasDetails=!1,this.detailsMessage="",this.infoContainer=this.mainRow.createChild("div","infobar-info-container"),this.infoMessage=this.infoContainer.createChild("div","infobar-info-message"),this.infoMessage.createChild("div",e+"-icon icon"),this.infoText=this.infoMessage.createChild("div","infobar-info-text"),this.infoText.textContent=t,O(this.infoText),this.actionContainer=this.infoContainer.createChild("div","infobar-info-actions"),i){this.contentElement.setAttribute("role","group");for(const e of i){const t=this.actionCallbackFactory(e);let i="infobar-button";e.highlight&&(i+=" primary-button");const n=os(e.text,t,{className:i,jslogContext:e.jslogContext});e.highlight&&!this.#e&&(this.#e=n),this.actionContainer.appendChild(n)}}if(this.disableSetting=n||null,n){const e=os(Et(wt.dontShowAgain),this.onDisable.bind(this),{className:"infobar-button"});this.actionContainer.appendChild(e)}this.closeContainer=this.mainRow.createChild("div","infobar-close-container"),this.toggleElement=os(Et(wt.showMore),this.onToggleDetails.bind(this),{className:"link-style devtools-link hidden",jslogContext:"show-more"}),this.toggleElement.setAttribute("role","link"),this.closeContainer.appendChild(this.toggleElement),this.closeButton=this.closeContainer.createChild("div","close-button","dt-close-button"),this.closeButton.hidden=!s,this.closeButton.setTabbable(!0),fe(this.closeButton,Et(wt.close)),self.onInvokeElement(this.closeButton,this.dispose.bind(this)),"issue"!==e&&(this.contentElement.tabIndex=0),be(this.contentElement,t),this.contentElement.addEventListener("keydown",(e=>e.keyCode===nt.Esc.code?(this.dispose(),void e.consume()):e.target===this.contentElement&&"Enter"===e.key&&this.hasDetails?(this.onToggleDetails(),void e.consume()):void 0)),this.closeCallback=null}static create(e,t,i,n,s){return n&&n.get()?null:new It(e,t,i,n,void 0,s)}dispose(){this.element.remove(),this.onResize(),this.closeCallback&&this.closeCallback.call(null)}setText(e){this.infoText.textContent=e,this.onResize()}setCloseCallback(e){this.closeCallback=e}setParentView(e){this.parentView=e}actionCallbackFactory(e){return e.delegate?e.dismiss?(()=>{e.delegate&&e.delegate(),this.dispose()}).bind(this):e.delegate:e.dismiss?this.dispose.bind(this):()=>{}}onResize(){this.parentView&&this.parentView.doResize()}onDisable(){this.disableSetting&&this.disableSetting.set(!0),this.dispose()}onToggleDetails(){this.detailsRows.classList.remove("hidden"),this.toggleElement.remove(),this.onResize(),Se("string"==typeof this.detailsMessage?this.detailsMessage:this.detailsMessage.textContent||""),this.#e?this.#e.focus():this.closeButton.focus()}createDetailsRowMessage(e){this.hasDetails=!0,this.detailsMessage=e,this.toggleElement.classList.remove("hidden");const t=this.detailsRows.createChild("div","infobar-details-row").createChild("span","infobar-row-message");return"string"==typeof e?t.textContent=e:t.appendChild(e),t}}var yt=Object.freeze({__proto__:null,Infobar:It}),St={cssContent:".tabbed-pane-header-tab{height:26px;margin:0;border:none;border-left:2px solid transparent;border-right:2px solid transparent;&.selected{border-width:0 2px}& > .tabbed-pane-header-tab-icon > devtools-icon{width:14px;height:14px;color:var(--icon-warning)}}.tabbed-pane-header-contents{margin-left:0;min-width:min-content}.tabbed-pane-left-toolbar{margin-right:0!important}"};class Ct extends e.ObjectWrapper.ObjectWrapper{isEnabledInternal;elementsInternal;installDragOnMouseDownBound;cursorInternal;startX;startY;constructor(){super(),this.isEnabledInternal=!0,this.elementsInternal=new Set,this.installDragOnMouseDownBound=this.installDragOnMouseDown.bind(this),this.cursorInternal="nwse-resize"}isEnabled(){return this.isEnabledInternal}setEnabled(e){this.isEnabledInternal=e,this.updateElementCursors()}elements(){return[...this.elementsInternal]}addElement(e){this.elementsInternal.has(e)||(this.elementsInternal.add(e),e.addEventListener("pointerdown",this.installDragOnMouseDownBound,!1),this.updateElementCursor(e))}removeElement(e){this.elementsInternal.has(e)&&(this.elementsInternal.delete(e),e.removeEventListener("pointerdown",this.installDragOnMouseDownBound,!1),e.style.removeProperty("cursor"))}updateElementCursors(){this.elementsInternal.forEach(this.updateElementCursor.bind(this))}updateElementCursor(e){this.isEnabledInternal?(e.style.setProperty("cursor",this.cursor()),e.style.setProperty("touch-action","none")):(e.style.removeProperty("cursor"),e.style.removeProperty("touch-action"))}cursor(){return this.cursorInternal}setCursor(e){this.cursorInternal=e,this.updateElementCursors()}installDragOnMouseDown(e){const t=e.target;if(!this.elementsInternal.has(t))return!1;Rn(t,this.dragStart.bind(this),(e=>{this.drag(e)}),this.dragEnd.bind(this),this.cursor(),e)}dragStart(e){return!!this.isEnabledInternal&&(this.startX=e.pageX,this.startY=e.pageY,this.sendDragStart(this.startX,this.startY),!0)}sendDragStart(e,t){this.dispatchEventToListeners("ResizeStart",{startX:e,currentX:e,startY:t,currentY:t})}drag(e){return this.isEnabledInternal?(this.sendDragMove(this.startX,e.pageX,this.startY,e.pageY,e.shiftKey),e.preventDefault(),!1):(this.dragEnd(e),!0)}sendDragMove(e,t,i,n,s){this.dispatchEventToListeners("ResizeUpdateXY",{startX:e,currentX:t,startY:i,currentY:n,shiftKey:s})}dragEnd(e){this.dispatchEventToListeners("ResizeEnd"),delete this.startX,delete this.startY}}class Tt extends Ct{isVerticalInternal;constructor(){super(),this.isVerticalInternal=!0}isVertical(){return this.isVerticalInternal}setVertical(e){this.isVerticalInternal=e,this.updateElementCursors()}cursor(){return this.isVerticalInternal?"ns-resize":"ew-resize"}sendDragStart(e,t){const i=this.isVerticalInternal?t:e;this.dispatchEventToListeners("ResizeStart",{startPosition:i,currentPosition:i})}sendDragMove(e,t,i,n,s){this.isVerticalInternal?this.dispatchEventToListeners("ResizeUpdatePosition",{startPosition:i,currentPosition:n,shiftKey:s}):this.dispatchEventToListeners("ResizeUpdatePosition",{startPosition:e,currentPosition:t,shiftKey:s})}}var kt=Object.freeze({__proto__:null,ResizerWidget:Ct,SimpleResizerWidget:Tt}),Mt={cssContent:".shadow-split-widget{display:flex;overflow:hidden}.shadow-split-widget-contents{display:flex;position:relative;flex-direction:column;contain:layout size style}.shadow-split-widget-sidebar{flex:none}.shadow-split-widget-main,\n.shadow-split-widget-sidebar.maximized{flex:auto}.shadow-split-widget.hbox > .shadow-split-widget-resizer{position:absolute;top:0;bottom:0;width:6px;z-index:4000}.shadow-split-widget.vbox > .shadow-split-widget-resizer{position:absolute;left:0;right:0;height:6px;z-index:4000}.shadow-split-widget.vbox > .shadow-split-widget-sidebar.no-default-splitter{border:0!important}.shadow-split-widget.vbox > .shadow-split-widget-sidebar:not(.maximized){border:0;border-top:1px solid var(--sys-color-divider)}.shadow-split-widget.hbox > .shadow-split-widget-sidebar:not(.maximized){border:0;border-left:1px solid var(--sys-color-divider)}.shadow-split-widget.vbox > .shadow-split-widget-sidebar:first-child:not(.maximized){border:0;border-bottom:1px solid var(--sys-color-divider)}.shadow-split-widget.hbox > .shadow-split-widget-sidebar:first-child:not(.maximized){border:0;border-right:1px solid var(--sys-color-divider)}:host-context(.disable-resizer-for-elements-hack) .shadow-split-widget-resizer{pointer-events:none}"};class Lt extends HTMLElement{static get observedAttributes(){return["flex","padding","padding-top","padding-bottom","padding-left","padding-right","margin","margin-top","margin-bottom","margin-left","margin-right","overflow","overflow-x","overflow-y","font-size","color","background","background-color","border","border-top","border-bottom","border-left","border-right","max-width","max-height"]}attributeChangedCallback(e,t,i){if("flex"!==e)if(null===i){if(this.style.removeProperty(e),e.startsWith("padding-")||e.startsWith("margin-")||e.startsWith("border-")||e.startsWith("background-")||e.startsWith("overflow-")){const t=e.substring(0,e.indexOf("-")),i=this.getAttribute(t);null!==i&&this.style.setProperty(t,i)}}else this.style.setProperty(e,i);else null===i?this.style.removeProperty("flex"):"initial"===i||"auto"===i||"none"===i||-1!==i.indexOf(" ")?this.style.setProperty("flex",i):this.style.setProperty("flex","0 0 "+i)}}class Pt extends Lt{constructor(e){super(),this.style.setProperty("display","flex"),this.style.setProperty("flex-direction",e),this.style.setProperty("justify-content","flex-start")}static get observedAttributes(){return super.observedAttributes.concat(["x-start","x-center","x-stretch","x-baseline","justify-content"])}attributeChangedCallback(e,t,i){"x-start"!==e&&"x-center"!==e&&"x-stretch"!==e&&"x-baseline"!==e?super.attributeChangedCallback(e,t,i):null===i?this.style.removeProperty("align-items"):this.style.setProperty("align-items","x-start"===e?"flex-start":e.substr(2))}}customElements.define("x-vbox",class extends Pt{constructor(){super("column")}}),customElements.define("x-hbox",class extends Pt{constructor(){super("row")}}),customElements.define("x-cbox",class extends Lt{constructor(){super(),this.style.setProperty("display","flex"),this.style.setProperty("flex-direction","column"),this.style.setProperty("justify-content","center"),this.style.setProperty("align-items","center")}}),customElements.define("x-div",class extends Lt{constructor(){super(),this.style.setProperty("display","block")}}),customElements.define("x-span",class extends Lt{constructor(){super(),this.style.setProperty("display","inline")}}),customElements.define("x-text",class extends Lt{constructor(){super(),this.style.setProperty("display","inline"),this.style.setProperty("white-space","pre")}});var Dt=Object.freeze({__proto__:null,XElement:Lt});let At=null;const Rt=new WeakMap;class Bt extends Lt{visible;shadowRootInternal;defaultFocusedElement;elementsToRestoreScrollPositionsFor;onShownCallback;onHiddenCallback;onResizedCallback;constructor(){super(),this.style.setProperty("display","flex"),this.style.setProperty("flex-direction","column"),this.style.setProperty("align-items","stretch"),this.style.setProperty("justify-content","flex-start"),this.style.setProperty("contain","layout style"),this.visible=!1,this.defaultFocusedElement=null,this.elementsToRestoreScrollPositionsFor=[],At||(At=new ResizeObserver((e=>{for(const t of e){const e=t.target;e.visible&&e.onResizedCallback&&e.onResizedCallback.call(null)}}))),At.observe(this),this.setElementsToRestoreScrollPositionsFor([this])}isShowing(){return this.visible}setOnShown(e){this.onShownCallback=e}setOnHidden(e){this.onHiddenCallback=e}setOnResized(e){this.onResizedCallback=e}setElementsToRestoreScrollPositionsFor(e){for(const e of this.elementsToRestoreScrollPositionsFor)e.removeEventListener("scroll",Bt.storeScrollPosition,{capture:!1});this.elementsToRestoreScrollPositionsFor=e;for(const e of this.elementsToRestoreScrollPositionsFor)e.addEventListener("scroll",Bt.storeScrollPosition,{passive:!0,capture:!1})}restoreScrollPositions(){for(const e of this.elementsToRestoreScrollPositionsFor){const t=Rt.get(e);t&&(e.scrollTop=t.scrollTop,e.scrollLeft=t.scrollLeft)}}static storeScrollPosition(e){const t=e.currentTarget;Rt.set(t,{scrollLeft:t.scrollLeft,scrollTop:t.scrollTop})}setDefaultFocusedElement(e){if(e&&!this.isSelfOrAncestor(e))throw new Error("Default focus must be descendant");this.defaultFocusedElement=e}focus(){if(!this.visible)return;let e;if(this.defaultFocusedElement&&this.isSelfOrAncestor(this.defaultFocusedElement))e=this.defaultFocusedElement;else if(-1!==this.tabIndex)e=this;else{let t=this.traverseNextNode(this);for(;t;){if(t instanceof Bt&&t.visible){e=t;break}t=t.traverseNextNode(this)}}e&&!e.hasFocus()&&(e===this?HTMLElement.prototype.focus.call(this):e.focus())}connectedCallback(){this.visible=!0,this.restoreScrollPositions(),this.onShownCallback&&this.onShownCallback.call(null)}disconnectedCallback(){this.visible=!1,this.onHiddenCallback&&this.onHiddenCallback.call(null)}}customElements.define("x-widget",Bt);var Ot=Object.freeze({__proto__:null,XWidget:Bt});class Ft extends HTMLDivElement{__widget;__widgetCounter;constructor(){super()}}function zt(e,t){if(!e)throw new Error(t)}class Wt{element;contentElement;shadowRoot;isWebComponent;visibleInternal;isRoot;isShowingInternal;childrenInternal;hideOnDetach;notificationDepth;invalidationsSuspended;defaultFocusedChild;parentWidgetInternal;registeredCSSFiles;defaultFocusedElement;cachedConstraints;constraintsInternal;invalidationsRequested;externallyManaged;constructor(e,t){this.contentElement=document.createElement("div"),this.contentElement.classList.add("widget"),e?(this.element=document.createElement("div"),this.element.classList.add("vbox"),this.element.classList.add("flex-auto"),this.shadowRoot=d.createShadowRootWithCoreStyles(this.element,{cssFile:void 0,delegatesFocus:t}),this.shadowRoot.appendChild(this.contentElement)):this.element=this.contentElement,this.isWebComponent=e,this.element.__widget=this,this.visibleInternal=!1,this.isRoot=!1,this.isShowingInternal=!1,this.childrenInternal=[],this.hideOnDetach=!1,this.notificationDepth=0,this.invalidationsSuspended=0,this.defaultFocusedChild=null,this.parentWidgetInternal=null,this.registeredCSSFiles=!1}static incrementWidgetCounter(e,t){const i=(t.__widgetCounter||0)+(t.__widget?1:0);if(!i)return;let n=e;for(;n;)n.__widgetCounter=(n.__widgetCounter||0)+i,n=Vt(n)}static decrementWidgetCounter(e,t){const i=(t.__widgetCounter||0)+(t.__widget?1:0);if(!i)return;let n=e;for(;n;)n.__widgetCounter&&(n.__widgetCounter-=i),n=Vt(n)}markAsRoot(){zt(!this.element.parentElement,"Attempt to mark as root attached node"),this.isRoot=!0}parentWidget(){return this.parentWidgetInternal}children(){return this.childrenInternal}childWasDetached(e){}isShowing(){return this.isShowingInternal}shouldHideOnDetach(){if(!this.element.parentElement)return!1;if(this.hideOnDetach)return!0;for(const e of this.childrenInternal)if(e.shouldHideOnDetach())return!0;return!1}setHideOnDetach(){this.hideOnDetach=!0}inNotification(){return Boolean(this.notificationDepth)||Boolean(this.parentWidgetInternal&&this.parentWidgetInternal.inNotification())}parentIsShowing(){return!!this.isRoot||null!==this.parentWidgetInternal&&this.parentWidgetInternal.isShowing()}callOnVisibleChildren(e){const t=this.childrenInternal.slice();for(let i=0;i