diff --git a/.circleci/config.yml b/.circleci/config.yml index 3265522d7a..82e26d4a43 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ defaults: &defaults working_directory: ~/code docker: - - image: cimg/node:14.17.6-browsers + - image: cimg/node:18.13.0-browsers version: 2 jobs: diff --git a/.github/workflows/android-ci.yml b/.github/workflows/android-ci.yml index fbaba471ac..c870001535 100644 --- a/.github/workflows/android-ci.yml +++ b/.github/workflows/android-ci.yml @@ -9,31 +9,28 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] + newArchEnabled: [false, true] runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Node.js - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v2 with: - node-version: 16 + node-version: 18 + cache: 'yarn' - name: Set up JDK - uses: actions/setup-java@v2.5.0 + uses: actions/setup-java@v3 with: distribution: temurin java-version: 11 - - name: Cache /node_modules - uses: actions/cache@v2 - with: - path: node_modules - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - name: Install npm dependencies run: yarn --frozen-lockfile shell: bash - name: Build Android test app - uses: gradle/gradle-build-action@v2.1.3 + uses: gradle/gradle-build-action@v2 with: gradle-version: wrapper - arguments: --no-daemon clean build check test + arguments: -PnewArchEnabled=${{matrix.newArchEnabled}} --no-daemon clean build check test build-root-directory: example/android timeout-minutes: 60 diff --git a/.github/workflows/ios-ci.yml b/.github/workflows/ios-ci.yml index 997e05d607..5e060c5a90 100644 --- a/.github/workflows/ios-ci.yml +++ b/.github/workflows/ios-ci.yml @@ -6,23 +6,22 @@ on: pull_request: jobs: build: + strategy: + matrix: + extraEnv: [FOO=BAR, RCT_NEW_ARCH_ENABLED=1] runs-on: macos-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Node.js - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v3 with: - node-version: 16 - - name: Cache /node_modules - uses: actions/cache@v2 - with: - path: node_modules - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} + node-version: 18 + cache: 'yarn' - name: Install npm dependencies run: yarn --frozen-lockfile - name: Install Pods - run: pod install + run: ${{matrix.extraEnv}} pod install working-directory: example/ios - name: Build iOS test app run: | diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml index d8f1c959ad..472f6f2153 100644 --- a/.github/workflows/macos-ci.yml +++ b/.github/workflows/macos-ci.yml @@ -21,6 +21,8 @@ jobs: key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - name: Install npm dependencies run: yarn --frozen-lockfile + - name: Install macos dependencies + run: yarn add:macos - name: Install Pods run: pod install working-directory: example/macos diff --git a/.github/workflows/windows-ci.yml b/.github/workflows/windows-ci.yml index d56326a0a4..9a02704b9c 100644 --- a/.github/workflows/windows-ci.yml +++ b/.github/workflows/windows-ci.yml @@ -4,35 +4,28 @@ on: [pull_request] jobs: run-windows-tests: name: Build & run tests - runs-on: windows-2019 + runs-on: windows-2022 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 name: Checkout Code - name: Setup Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v3 with: node-version: '^14' + cache: 'yarn' - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1.0.2 - - - name: Check node modules cache - uses: actions/cache@v1 - id: yarn-cache + uses: microsoft/setup-msbuild@v1.1.3 with: - path: ./node_modules - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + vs-version: '[17.0,)' + msbuild-architecture: x64 - name: Install node modules - if: steps.yarn-cache.outputs.cache-hit != 'true' run: yarn --pure-lockfile - name: yarn build - if: steps.yarn-cache.outputs.cache-hit == 'true' run: | yarn build yarn tsc diff --git a/README.md b/README.md index c38914f552..c0f3716a3c 100644 --- a/README.md +++ b/README.md @@ -1,109 +1,81 @@ -# React Native WebView - a Modern, Cross-Platform WebView for React Native +# React Native WebView -[![star this repo](https://img.shields.io/github/stars/react-native-webview/react-native-webview?style=flat-square) +![star this repo](https://img.shields.io/github/stars/react-native-webview/react-native-webview?style=flat-square) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors) -[![Known Vulnerabilities](https://snyk.io/test/github/react-native-webview/react-native-webview/badge.svg?style=flat-square)](https://snyk.io/test/github/react-native-webview/react-native-webview) [![NPM Version](https://img.shields.io/npm/v/react-native-webview.svg?style=flat-square)](https://www.npmjs.com/package/react-native-webview) -[![Lean Core Extracted](https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg?style=flat-square)][lean-core-issue] +![Npm Downloads](https://img.shields.io/npm/dm/react-native-webview.svg) -**React Native WebView** is a modern, well-supported, and cross-platform WebView for React Native. It is intended to be a replacement for the built-in WebView (which was [removed from core](https://github.com/react-native-community/discussions-and-proposals/pull/3)). +**React Native WebView** is a community maintained WebView component for React Native. It is intended to be a replacement for the built-in WebView (which was [removed from core](https://github.com/react-native-community/discussions-and-proposals/pull/3)). -## Core Maintainers - Sponsoring companies +### Maintainers -_This project is maintained for free by these people using both their free time and their company work time._ +**Many thanks to these companies** for providing us with time to work on open source. +Please note that maintainers spend a lot of free time working on this too so feel free to sponsor them, **it really makes a difference.** -- [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) from [Brigad](https://www.brigad.co/en-gb/about-us) -- [Jamon Holmgren](https://github.com/jamonholmgren) ([Twitter @jamonholmgren](https://twitter.com/jamonholmgren)) from [Infinite Red](https://infinite.red/react-native) -- [Alexander Sklar](https://github.com/asklar) ([Twitter @alexsklar](https://twitter.com/alexsklar)) from [React Native for Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) -- [Chiara Mooney](https://github.com/chiaramooney) from [React Native for Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) +- [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) from [Brigad](https://www.brigad.co/en-gb/about-us) +[*Sponsor me* ❤️ !](https://github.com/sponsors/Titozzz) -## Platforms Supported -- [x] iOS -- [x] Android -- [x] macOS -- [x] Windows -- [x] Expo (Android, iOS) +Windows and macOS are managed by Microsoft, notably: +- [Alexander Sklar](https://github.com/asklar) ([Twitter @alexsklar](https://twitter.com/alexsklar)) from [React Native for Windows](https://microsoft.github.io/react-native-windows/) +- [Chiara Mooney](https://github.com/chiaramooney) from [React Native for Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) -## Getting Started +Shout-out to [Jamon Holmgren](https://github.com/jamonholmgren) from [Infinite Red](https://infinite.red) for helping a lot with the repo when he had more available time. -Read our [Getting Started Guide](docs/Getting-Started.md). If any step seems unclear, please create a detailed issue. +### Disclaimer -## Versioning +Maintaining WebView is very complex, because it is often used for many different usecases (rendering svgs, pdfs, login flows, and much more). We also support many platforms and both architecture of react-native. -This project follows [semantic versioning](https://semver.org/). We do not hesitate to release breaking changes but they will be in a major version. +Since WebView was extracted from React Native core, nearly 500 pull requests have been merged. +Considering that we have limited time, issues will mostly serve as a discussion place for the community, while **we will prioritize reviewing and merging pull requests.** -**Breaking History:** +### Platform compatibility -Current Version: ![version](https://img.shields.io/npm/v/react-native-webview.svg) +This project is compatible with **iOS**, **Android**, **Windows** and **macOS**. +This project support both **the old** (paper) **and the new architecture** (fabric). +This project is compatible with [expo](https://docs.expo.dev/versions/latest/sdk/webview/). -- [11.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v11.0.0) - Android setSupportMultipleWindows. -- [10.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v10.0.0) - Android Gradle plugin is only required when opening the project stand-alone -- [9.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v9.0.0) - props updates to injectedJavaScript are no longer immutable. -- [8.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v8.0.0) - onNavigationStateChange now triggers with hash url changes -- [7.0.1](https://github.com/react-native-webview/react-native-webview/releases/tag/v7.0.1) - Removed UIWebView -- [6.0.**2**](https://github.com/react-native-webview/react-native-webview/releases/tag/v6.0.2) - Update to AndroidX. Make sure to enable it in your project's `android/gradle.properties`. See [Getting Started Guide](docs/Getting-Started.md). -- [5.0.**1**](https://github.com/react-native-webview/react-native-webview/releases/tag/v5.0.0) - Refactored the old postMessage implementation for communication from webview to native. -- [4.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v4.0.0) - Added cache (enabled by default). -- [3.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v3.0.0) - WKWebview: Add shared process pool so cookies and localStorage are shared across webviews in iOS (enabled by default). -- [2.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v2.0.0) - First release this is a replica of the core webview component +### Getting Started -**Upcoming:** +Read our [Getting Started Guide](docs/Getting-Started.md). If any step seems unclear, please create a pull request. -- this.webView.postMessage() removal (never documented and less flexible than injectJavascript) -> [how to migrate](https://github.com/react-native-webview/react-native-webview/issues/809) -- Kotlin rewrite -- Maybe Swift rewrite +### Versioning -## Usage +This project follows [semantic versioning](https://semver.org/). We do not hesitate to release breaking changes but they will be in a major version. + +### Usage Import the `WebView` component from `react-native-webview` and use it like so: -```jsx +```tsx import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { WebView } from 'react-native-webview'; // ... -class MyWebComponent extends Component { - render() { - return ; - } +const MyWebComponent = () => { + return ; } ``` For more, read the [API Reference](./docs/Reference.md) and [Guide](./docs/Guide.md). If you're interested in contributing, check out the [Contributing Guide](./docs/Contributing.md). -## Common issues +### Common issues - If you're getting `Invariant Violation: Native component for "RNCWebView does not exist"` it likely means you forgot to run `react-native link` or there was some error with the linking process - If you encounter a build error during the task `:app:mergeDexRelease`, you need to enable multidex support in `android/app/build.gradle` as discussed in [this issue](https://github.com/react-native-webview/react-native-webview/issues/1344#issuecomment-650544648) -## Contributing - -See [Contributing.md](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Contributing.md) +#### Contributing -## Contributors +Contributions are welcome, see [Contributing.md](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Contributing.md) -Thanks goes to these wonderful people ([emoji key](https://github.com/all-contributors/all-contributors#emoji-key-)): - - - -
Thibault Malbranche
Thibault Malbranche

💻 🤔 👀 📖 🚧 ⚠️ 🚇 💬
Jamon Holmgren
Jamon Holmgren

💻 🤔 👀 📖 🚧 ⚠️ 💡 💬
Andrei Pfeiffer
Andrei Pfeiffer

💻 👀 🤔
Michael Diarmid
Michael Diarmid

💻 👀 🤔 🔧
Scott Mathson
Scott Mathson

💻 📖
Margaret
Margaret

💻 📖
Jordan Sexton
Jordan Sexton

💻 📖
Malcolm Scruggs
Malcolm Scruggs

💻 🔧 ⚠️
Momazo7u7
Momazo7u7

📖
Marco
Marco

📖
Julien Eluard
Julien Eluard

📖
Jian Wei
Jian Wei

💻 📖
Sergei Butko
Sergei Butko

📖
TMomemt
TMomemt

💻
Eric Lewis
Eric Lewis

💻 📖
Daniel Vicory
Daniel Vicory

💻 📖
- - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! - -## License +### License MIT -## Translations +### Translations This readme is available in: - [Brazilian portuguese](docs/README.portuguese.md) - [French](docs/README.french.md) - -[lean-core-issue]: https://github.com/facebook/react-native/issues/23313 diff --git a/android/build.gradle b/android/build.gradle index fbede170cb..3e0dcbcb24 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,137 +1,95 @@ -buildscript { - ext.getExtOrDefault = {name -> - return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['ReactNativeWebView_' + name] - } +import java.nio.file.Paths - // The Android Gradle plugin is only required when opening the android folder stand-alone. - // This avoids unnecessary downloads and potential conflicts when the library is included as a - // module dependency in an application project. - if (project == rootProject) { - repositories { - mavenCentral() - google() - } - - dependencies { - classpath("com.android.tools.build:gradle:3.6.0") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}") +buildscript { + ext.safeExtGet = {prop -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : project.properties['ReactNativeWebView_' + prop] } - } else { repositories { - mavenCentral() + google() + gradlePluginPortal() } - dependencies { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion')}") + classpath("com.android.tools.build:gradle:7.0.4") } - } } -def getExtOrIntegerDefault(name) { - return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeWebView_' + name]).toInteger() +def getExtOrIntegerDefault(prop) { + return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : (project.properties['ReactNativeWebView_' + prop]).toInteger() } -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' - -android { - compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') - defaultConfig { - minSdkVersion getExtOrIntegerDefault('minSdkVersion') - targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') - versionCode 1 - versionName "1.0" - } - buildTypes { - release { - minifyEnabled false +static def findNodeModulePath(baseDir, packageName) { + def basePath = baseDir.toPath().normalize() + // Node's module resolution algorithm searches up to the root directory, + // after which the base path will be null + while (basePath) { + def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName) + if (candidatePath.toFile().exists()) { + return candidatePath.toString() + } + basePath = basePath.getParent() } - } - lintOptions { - disable 'GradleCompatible' - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } + return null } -repositories { - mavenCentral() - google() - - def found = false - def defaultDir = null - def androidSourcesName = 'React Native sources' - - if (rootProject.ext.has('reactNativeAndroidRoot')) { - defaultDir = rootProject.ext.get('reactNativeAndroidRoot') - } else { - defaultDir = new File( - projectDir, - '/../../../node_modules/react-native/android' - ) - } - - if (defaultDir.exists()) { - maven { - url defaultDir.toString() - name androidSourcesName - } - - logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}") - found = true - } else { - def parentDir = rootProject.projectDir +def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} - 1.upto(5, { - if (found) return true - parentDir = parentDir.parentFile - def androidSourcesDir = new File( - parentDir, - 'node_modules/react-native' - ) +apply plugin: 'com.android.library' +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' +} +apply plugin: 'kotlin-android' - def androidPrebuiltBinaryDir = new File( - parentDir, - 'node_modules/react-native/android' - ) +android { + compileSdkVersion getExtOrIntegerDefault('compileSdkVersion') - if (androidPrebuiltBinaryDir.exists()) { - maven { - url androidPrebuiltBinaryDir.toString() - name androidSourcesName - } + defaultConfig { + minSdkVersion getExtOrIntegerDefault('minSdkVersion') + targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } - logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}") - found = true - } else if (androidSourcesDir.exists()) { - maven { - url androidSourcesDir.toString() - name androidSourcesName + sourceSets { + main { + if (isNewArchitectureEnabled()) { + java.srcDirs += ['src/newarch'] + } else { + java.srcDirs += ['src/oldarch'] + } } + } +} - logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}") - found = true - } - }) - } - - if (!found) { - throw new GradleException( - "${project.name}: unable to locate React Native android sources. " + - "Ensure you have you installed React Native as a dependency in your project and try again." - ) - } +def reactNativePath = findNodeModulePath(projectDir, "react-native") +def codegenPath = findNodeModulePath(projectDir, "@react-native/codegen") +if (codegenPath == null) { + // Compat for 0.71 and lower (to be removed) + codegenPath = findNodeModulePath(projectDir, "react-native-codegen") } -def kotlin_version = getExtOrDefault('kotlinVersion') -def webkit_version = getExtOrDefault('webkitVersion') +repositories { + maven { + url "${reactNativePath}/android" + } + mavenCentral() + google() +} dependencies { - //noinspection GradleDynamicVersion - implementation 'com.facebook.react:react-native:+' - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "androidx.webkit:webkit:$webkit_version" + implementation 'com.facebook.react:react-native:+' + implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion')}" + implementation "androidx.webkit:webkit:${safeExtGet('webkitVersion')}" +} + +if (isNewArchitectureEnabled()) { + react { + jsRootDir = file("../src/") + libraryName = "rncwebview" + codegenJavaPackageName = "com.reactnativecommunity.webview" + codegenDir = new File(codegenPath) + reactNativeDir = new File(reactNativePath) + } } diff --git a/android/gradle.properties b/android/gradle.properties index e6f0f5eb08..c17e0668f7 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,6 +1,5 @@ ReactNativeWebView_kotlinVersion=1.6.0 ReactNativeWebView_webkitVersion=1.4.0 -ReactNativeWebView_compileSdkVersion=29 -ReactNativeWebView_buildToolsVersion=29.0.3 -ReactNativeWebView_targetSdkVersion=28 +ReactNativeWebView_compileSdkVersion=31 +ReactNativeWebView_targetSdkVersion=31 ReactNativeWebView_minSdkVersion=21 diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java b/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java new file mode 100644 index 0000000000..57587eef16 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCBasicAuthCredential.java @@ -0,0 +1,11 @@ +package com.reactnativecommunity.webview; + +class RNCBasicAuthCredential { + String username; + String password; + + RNCBasicAuthCredential(String username, String password) { + this.username = username; + this.password = password; + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java new file mode 100644 index 0000000000..56170220f8 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebChromeClient.java @@ -0,0 +1,346 @@ +package com.reactnativecommunity.webview; + +import android.Manifest; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Message; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; +import android.webkit.PermissionRequest; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.widget.FrameLayout; + +import androidx.annotation.RequiresApi; +import androidx.core.content.ContextCompat; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.common.build.ReactBuildConfig; +import com.facebook.react.modules.core.PermissionAwareActivity; +import com.facebook.react.modules.core.PermissionListener; +import com.facebook.react.uimanager.UIManagerHelper; +import com.reactnativecommunity.webview.events.TopLoadingProgressEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener { + protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); + + protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + + protected static final int COMMON_PERMISSION_REQUEST = 3; + + protected RNCWebView mWebView; + + protected View mVideoView; + protected WebChromeClient.CustomViewCallback mCustomViewCallback; + + /* + * - Permissions - + * As native permissions are asynchronously handled by the PermissionListener, many fields have + * to be stored to send permissions results to the webview + */ + + // Webview camera & audio permission callback + protected PermissionRequest permissionRequest; + // Webview camera & audio permission already granted + protected List grantedPermissions; + + // Webview geolocation permission callback + protected GeolocationPermissions.Callback geolocationPermissionCallback; + // Webview geolocation permission origin callback + protected String geolocationPermissionOrigin; + + // true if native permissions dialog is shown, false otherwise + protected boolean permissionsRequestShown = false; + // Pending Android permissions for the next request + protected List pendingPermissions = new ArrayList<>(); + + protected RNCWebView.ProgressChangedFilter progressChangedFilter = null; + protected boolean mAllowsProtectedMedia = false; + + public RNCWebChromeClient(RNCWebView webView) { + this.mWebView = webView; + } + + @Override + public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { + + final WebView newWebView = new WebView(view.getContext()); + final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; + transport.setWebView(newWebView); + resultMsg.sendToTarget(); + + return true; + } + + @Override + public boolean onConsoleMessage(ConsoleMessage message) { + if (ReactBuildConfig.DEBUG) { + return super.onConsoleMessage(message); + } + // Ignore console logs in non debug builds. + return true; + } + + @Override + public void onProgressChanged(WebView webView, int newProgress) { + super.onProgressChanged(webView, newProgress); + final String url = webView.getUrl(); + if (progressChangedFilter.isWaitingForCommandLoadUrl()) { + return; + } + WritableMap event = Arguments.createMap(); + event.putDouble("target", webView.getId()); + event.putString("title", webView.getTitle()); + event.putString("url", url); + event.putBoolean("canGoBack", webView.canGoBack()); + event.putBoolean("canGoForward", webView.canGoForward()); + event.putDouble("progress", (float) newProgress / 100); + + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag(this.mWebView.getThemedReactContext(), reactTag).dispatchEvent(new TopLoadingProgressEvent(reactTag, event)); + } + + @Override + public void onPermissionRequest(final PermissionRequest request) { + + grantedPermissions = new ArrayList<>(); + + ArrayList requestedAndroidPermissions = new ArrayList<>(); + for (String requestedResource : request.getResources()) { + String androidPermission = null; + + if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) { + androidPermission = Manifest.permission.RECORD_AUDIO; + } else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) { + androidPermission = Manifest.permission.CAMERA; + } else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) { + if (mAllowsProtectedMedia) { + grantedPermissions.add(requestedResource); + } else { + /** + * Legacy handling (Kept in case it was working under some conditions (given Android version or something)) + * + * Try to ask user to grant permission using Activity.requestPermissions + * + * Find more details here: https://github.com/react-native-webview/react-native-webview/pull/2732 + */ + androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID; + } } + // TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID. + if (androidPermission != null) { + if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), androidPermission) == PackageManager.PERMISSION_GRANTED) { + grantedPermissions.add(requestedResource); + } else { + requestedAndroidPermissions.add(androidPermission); + } + } + } + + // If all the permissions are already granted, send the response to the WebView synchronously + if (requestedAndroidPermissions.isEmpty()) { + request.grant(grantedPermissions.toArray(new String[0])); + grantedPermissions = null; + return; + } + + // Otherwise, ask to Android System for native permissions asynchronously + + this.permissionRequest = request; + + requestPermissions(requestedAndroidPermissions); + } + + + @Override + public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { + + if (ContextCompat.checkSelfPermission(this.mWebView.getThemedReactContext(), Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + + /* + * Keep the trace of callback and origin for the async permission request + */ + geolocationPermissionCallback = callback; + geolocationPermissionOrigin = origin; + + requestPermissions(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION)); + + } else { + callback.invoke(origin, true, false); + } + } + + private PermissionAwareActivity getPermissionAwareActivity() { + Activity activity = this.mWebView.getThemedReactContext().getCurrentActivity(); + if (activity == null) { + throw new IllegalStateException("Tried to use permissions API while not attached to an Activity."); + } else if (!(activity instanceof PermissionAwareActivity)) { + throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity."); + } + return (PermissionAwareActivity) activity; + } + + private synchronized void requestPermissions(List permissions) { + + /* + * If permissions request dialog is displayed on the screen and another request is sent to the + * activity, the last permission asked is skipped. As a work-around, we use pendingPermissions + * to store next required permissions. + */ + + if (permissionsRequestShown) { + pendingPermissions.addAll(permissions); + return; + } + + PermissionAwareActivity activity = getPermissionAwareActivity(); + permissionsRequestShown = true; + + activity.requestPermissions( + permissions.toArray(new String[0]), + COMMON_PERMISSION_REQUEST, + webviewPermissionsListener + ); + + // Pending permissions have been sent, the list can be cleared + pendingPermissions.clear(); + } + + + private PermissionListener webviewPermissionsListener = (requestCode, permissions, grantResults) -> { + + permissionsRequestShown = false; + + /* + * As a "pending requests" approach is used, requestCode cannot help to define if the request + * came from geolocation or camera/audio. This is why shouldAnswerToPermissionRequest is used + */ + boolean shouldAnswerToPermissionRequest = false; + + for (int i = 0; i < permissions.length; i++) { + + String permission = permissions[i]; + boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED; + + if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION) + && geolocationPermissionCallback != null + && geolocationPermissionOrigin != null) { + + if (granted) { + geolocationPermissionCallback.invoke(geolocationPermissionOrigin, true, false); + } else { + geolocationPermissionCallback.invoke(geolocationPermissionOrigin, false, false); + } + + geolocationPermissionCallback = null; + geolocationPermissionOrigin = null; + } + + if (permission.equals(Manifest.permission.RECORD_AUDIO)) { + if (granted && grantedPermissions != null) { + grantedPermissions.add(PermissionRequest.RESOURCE_AUDIO_CAPTURE); + } + shouldAnswerToPermissionRequest = true; + } + + if (permission.equals(Manifest.permission.CAMERA)) { + if (granted && grantedPermissions != null) { + grantedPermissions.add(PermissionRequest.RESOURCE_VIDEO_CAPTURE); + } + shouldAnswerToPermissionRequest = true; + } + + if (permission.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) { + if (granted && grantedPermissions != null) { + grantedPermissions.add(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID); + } + shouldAnswerToPermissionRequest = true; + } + } + + if (shouldAnswerToPermissionRequest + && permissionRequest != null + && grantedPermissions != null) { + permissionRequest.grant(grantedPermissions.toArray(new String[0])); + permissionRequest = null; + grantedPermissions = null; + } + + if (!pendingPermissions.isEmpty()) { + requestPermissions(pendingPermissions); + return false; + } + + return true; + }; + + protected void openFileChooser(ValueCallback filePathCallback, String acceptType) { + this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType); + } + + protected void openFileChooser(ValueCallback filePathCallback) { + this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, ""); + } + + protected void openFileChooser(ValueCallback filePathCallback, String acceptType, String capture) { + this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptType); + } + + @Override + public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { + String[] acceptTypes = fileChooserParams.getAcceptTypes(); + boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE; + + return this.mWebView.getThemedReactContext().getNativeModule(RNCWebViewModule.class).startPhotoPickerIntent(filePathCallback, acceptTypes, allowMultiple, fileChooserParams.isCaptureEnabled()); + } + + @Override + public void onHostResume() { + if (mVideoView != null && mVideoView.getSystemUiVisibility() != FULLSCREEN_SYSTEM_UI_VISIBILITY) { + mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY); + } + } + + @Override + public void onHostPause() { } + + @Override + public void onHostDestroy() { } + + protected ViewGroup getRootView() { + return this.mWebView.getThemedReactContext().getCurrentActivity().findViewById(android.R.id.content); + } + + public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) { + progressChangedFilter = filter; + } + + /** + * Set whether or not protected media should be allowed + * /!\ Setting this to false won't revoke permission already granted to the current webpage. + * In order to do so, you'd need to reload the page /!\ + */ + public void setAllowsProtectedMedia(boolean enabled) { + mAllowsProtectedMedia = enabled; + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java new file mode 100644 index 0000000000..9dbacb2797 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java @@ -0,0 +1,477 @@ +package com.reactnativecommunity.webview; + +import androidx.annotation.Nullable; +import androidx.webkit.WebViewAssetLoader; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Color; +import android.graphics.Rect; +import android.os.Build; +import android.text.TextUtils; +import android.util.AttributeSet; + +import android.view.ActionMode; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.webkit.JavascriptInterface; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.CatalystInstance; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeArray; +import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.UIManagerHelper; +import com.facebook.react.uimanager.UIManagerModule; +import com.facebook.react.uimanager.events.ContentSizeChangeEvent; +import com.facebook.react.uimanager.events.Event; +import com.facebook.react.uimanager.events.EventDispatcher; +import com.facebook.react.uimanager.events.RCTEventEmitter; +import com.facebook.react.views.scroll.OnScrollDispatchHelper; +import com.facebook.react.views.scroll.ScrollEvent; +import com.facebook.react.views.scroll.ScrollEventType; +import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent; +import com.reactnativecommunity.webview.events.TopLoadingProgressEvent; +import com.reactnativecommunity.webview.events.TopMessageEvent; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class RNCWebView extends WebView implements LifecycleEventListener { + protected @Nullable + String injectedJS; + protected @Nullable + String injectedJSBeforeContentLoaded; + protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView"; + + /** + * android.webkit.WebChromeClient fundamentally does not support JS injection into frames other + * than the main frame, so these two properties are mostly here just for parity with iOS & macOS. + */ + protected boolean injectedJavaScriptForMainFrameOnly = true; + protected boolean injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true; + + protected boolean messagingEnabled = false; + + protected @Nullable + String webViewKey; + + protected @Nullable + String messagingModuleName; + protected @Nullable + RNCWebViewClient mRNCWebViewClient; + protected @Nullable + CatalystInstance mCatalystInstance; + protected boolean sendContentSizeChangeEvents = false; + private OnScrollDispatchHelper mOnScrollDispatchHelper; + protected boolean hasScrollEvent = false; + protected boolean nestedScrollEnabled = false; + protected ProgressChangedFilter progressChangedFilter; + + protected ReadableMap source; + + /** + * WebView must be created with an context of the current activity + *

+ * Activity Context is required for creation of dialogs internally by WebView + * Reactive Native needed for access to ReactNative internal system functionality + */ + public RNCWebView(ThemedReactContext reactContext) { + super(reactContext); + this.createCatalystInstance(); + progressChangedFilter = new ProgressChangedFilter(); + + /** + * Default the background color to transparent to avoid flashing a white frame + * when initializing the WebView. The React CSS background color will get applied + * to the RNCWebViewContainer whose background should show behind this transparent + * background until the WebView has non-transparent content. + */ + setBackgroundColor(Color.TRANSPARENT); + } + + public void setIgnoreErrFailedForThisURL(String url) { + mRNCWebViewClient.setIgnoreErrFailedForThisURL(url); + } + + public void setBasicAuthCredential(RNCBasicAuthCredential credential) { + mRNCWebViewClient.setBasicAuthCredential(credential); + } + + public void setWebViewAssetLoader(WebViewAssetLoader webViewAssetLoader) { + mRNCWebViewClient.setWebViewAssetLoader(webViewAssetLoader); + } + + public void setSendContentSizeChangeEvents(boolean sendContentSizeChangeEvents) { + this.sendContentSizeChangeEvents = sendContentSizeChangeEvents; + } + + public void setHasScrollEvent(boolean hasScrollEvent) { + this.hasScrollEvent = hasScrollEvent; + } + + public void setNestedScrollEnabled(boolean nestedScrollEnabled) { + this.nestedScrollEnabled = nestedScrollEnabled; + } + + public void setSource(ReadableMap source) { + this.source = source; + } + + public boolean isNewSource(@Nullable ReadableMap newSource) { + if (source == null || newSource == null) { + return true; + } + + // Check if any of the following string values have changed + String[] sourceKeys = {"uri", "method", "body", "html", "baseUrl"}; + + for (String key : sourceKeys) { + String value = source.getString(key); + String newValue = newSource.getString(key); + if (newValue != null && !newValue.equals(value)) { + return true; + } + } + + // Check if headers changed + ReadableMap headersMap = source.getMap("headers"); + ReadableMap newHeadersMap = newSource.getMap("headers"); + Map headers = headersMap == null ? Collections.emptyMap() : headersMap.toHashMap(); + Map newHeaders = newHeadersMap == null ? Collections.emptyMap() : newHeadersMap.toHashMap(); + + return !headers.equals(newHeaders); + } + + @Override + public void onHostResume() { + // do nothing + } + + @Override + public void onHostPause() { + // do nothing + } + + @Override + public void onHostDestroy() { + cleanupCallbacksAndDestroy(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (this.nestedScrollEnabled) { + requestDisallowInterceptTouchEvent(true); + } + return super.onTouchEvent(event); + } + + @Override + protected void onSizeChanged(int w, int h, int ow, int oh) { + super.onSizeChanged(w, h, ow, oh); + + if (sendContentSizeChangeEvents) { + dispatchEvent( + this, + new ContentSizeChangeEvent( + this.getId(), + w, + h + ) + ); + } + } + + protected @Nullable + List> menuCustomItems; + + public void setMenuCustomItems(List> menuCustomItems) { + this.menuCustomItems = menuCustomItems; + } + + @Override + public ActionMode startActionMode(ActionMode.Callback callback, int type) { + if(menuCustomItems == null ){ + return super.startActionMode(callback, type); + } + + return super.startActionMode(new ActionMode.Callback2() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + for (int i = 0; i < menuCustomItems.size(); i++) { + menu.add(Menu.NONE, i, i, (menuCustomItems.get(i)).get("label")); + } + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + WritableMap wMap = Arguments.createMap(); + RNCWebView.this.evaluateJavascript( + "(function(){return {selection: window.getSelection().toString()} })()", + new ValueCallback() { + @Override + public void onReceiveValue(String selectionJson) { + Map menuItemMap = menuCustomItems.get(item.getItemId()); + wMap.putString("label", menuItemMap.get("label")); + wMap.putString("key", menuItemMap.get("key")); + String selectionText = ""; + try { + selectionText = new JSONObject(selectionJson).getString("selection"); + } catch (JSONException ignored) {} + wMap.putString("selectedText", selectionText); + dispatchEvent(RNCWebView.this, new TopCustomMenuSelectionEvent(RNCWebView.this.getId(), wMap)); + mode.finish(); + } + } + ); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + mode = null; + } + + @Override + public void onGetContentRect (ActionMode mode, + View view, + Rect outRect){ + if (callback instanceof ActionMode.Callback2) { + ((ActionMode.Callback2) callback).onGetContentRect(mode, view, outRect); + } else { + super.onGetContentRect(mode, view, outRect); + } + } + }, type); + } + + @Override + public void setWebViewClient(WebViewClient client) { + super.setWebViewClient(client); + if (client instanceof RNCWebViewClient) { + mRNCWebViewClient = (RNCWebViewClient) client; + mRNCWebViewClient.setProgressChangedFilter(progressChangedFilter); + } + } + + WebChromeClient mWebChromeClient; + @Override + public void setWebChromeClient(WebChromeClient client) { + this.mWebChromeClient = client; + super.setWebChromeClient(client); + if (client instanceof RNCWebChromeClient) { + ((RNCWebChromeClient) client).setProgressChangedFilter(progressChangedFilter); + } + } + + public WebChromeClient getWebChromeClient() { + return this.mWebChromeClient; + } + + public @Nullable + RNCWebViewClient getRNCWebViewClient() { + return mRNCWebViewClient; + } + + protected RNCWebViewBridge createRNCWebViewBridge(RNCWebView webView) { + return new RNCWebViewBridge(webView); + } + + public void setWebViewKey(String webViewKey) { + this.webViewKey = webViewKey; + } + + public @Nullable String getWebViewKey() { + return this.webViewKey; + } + + protected void createCatalystInstance() { + ThemedReactContext reactContext = (ThemedReactContext) this.getContext(); + + if (reactContext != null) { + mCatalystInstance = reactContext.getCatalystInstance(); + } + } + + @SuppressLint("AddJavascriptInterface") + public void setMessagingEnabled(boolean enabled) { + if (messagingEnabled == enabled) { + return; + } + + messagingEnabled = enabled; + + if (enabled) { + addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE); + } else { + removeJavascriptInterface(JAVASCRIPT_INTERFACE); + } + } + + protected void evaluateJavascriptWithFallback(String script) { + evaluateJavascript(script, null); + } + + public void callInjectedJavaScript() { + if (getSettings().getJavaScriptEnabled() && + injectedJS != null && + !TextUtils.isEmpty(injectedJS)) { + evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();"); + } + } + + public void callInjectedJavaScriptBeforeContentLoaded() { + if (getSettings().getJavaScriptEnabled() && + injectedJSBeforeContentLoaded != null && + !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { + evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); + } + } + + public void onMessage(String message) { + ThemedReactContext reactContext = getThemedReactContext(); + RNCWebView mWebView = this; + + if (mRNCWebViewClient != null) { + WebView webView = this; + webView.post(new Runnable() { + @Override + public void run() { + if (mRNCWebViewClient == null) { + return; + } + WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, webView.getUrl()); + data.putString("data", message); + + if (mCatalystInstance != null) { + mWebView.sendDirectMessage("onMessage", data); + } else { + dispatchEvent(webView, new TopMessageEvent(webView.getId(), data)); + } + } + }); + } else { + WritableMap eventData = Arguments.createMap(); + eventData.putString("data", message); + + if (mCatalystInstance != null) { + this.sendDirectMessage("onMessage", eventData); + } else { + dispatchEvent(this, new TopMessageEvent(this.getId(), eventData)); + } + } + } + + protected void sendDirectMessage(final String method, WritableMap data) { + WritableNativeMap event = new WritableNativeMap(); + event.putMap("nativeEvent", data); + + WritableNativeArray params = new WritableNativeArray(); + params.pushMap(event); + + mCatalystInstance.callFunction(messagingModuleName, method, params); + } + + protected void onScrollChanged(int x, int y, int oldX, int oldY) { + super.onScrollChanged(x, y, oldX, oldY); + + if (!hasScrollEvent) { + return; + } + + if (mOnScrollDispatchHelper == null) { + mOnScrollDispatchHelper = new OnScrollDispatchHelper(); + } + + if (mOnScrollDispatchHelper.onScrollChanged(x, y)) { + ScrollEvent event = ScrollEvent.obtain( + this.getId(), + ScrollEventType.SCROLL, + x, + y, + mOnScrollDispatchHelper.getXFlingVelocity(), + mOnScrollDispatchHelper.getYFlingVelocity(), + this.computeHorizontalScrollRange(), + this.computeVerticalScrollRange(), + this.getWidth(), + this.getHeight()); + + dispatchEvent(this, event); + } + } + + protected void dispatchEvent(WebView webView, Event event) { + ThemedReactContext reactContext = getThemedReactContext(); + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag(reactContext, reactTag).dispatchEvent(event); + } + + protected void cleanupCallbacksAndDestroy() { + setWebViewClient(null); + destroy(); + } + + @Override + public void destroy() { + if (mWebChromeClient != null) { + mWebChromeClient.onHideCustomView(); + } + super.destroy(); + } + + public ThemedReactContext getThemedReactContext() { + return (ThemedReactContext) this.getContext(); + } + + protected class RNCWebViewBridge { + RNCWebView mWebView; + + RNCWebViewBridge(RNCWebView c) { + mWebView = c; + } + + /** + * This method is called whenever JavaScript running within the web view calls: + * - window[JAVASCRIPT_INTERFACE].postMessage + */ + @JavascriptInterface + public void postMessage(String message) { + mWebView.onMessage(message); + } + } + + + protected static class ProgressChangedFilter { + private boolean waitingForCommandLoadUrl = false; + + public void setWaitingForCommandLoadUrl(boolean isWaiting) { + waitingForCommandLoadUrl = isWaiting; + } + + public boolean isWaitingForCommandLoadUrl() { + return waitingForCommandLoadUrl; + } + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java new file mode 100644 index 0000000000..c5f4c7bc40 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java @@ -0,0 +1,333 @@ +package com.reactnativecommunity.webview; + +import android.annotation.TargetApi; +import android.graphics.Bitmap; +import android.net.http.SslError; +import android.os.Build; +import android.os.SystemClock; +import android.util.Log; +import android.webkit.HttpAuthHandler; +import android.webkit.RenderProcessGoneDetail; +import android.webkit.SslErrorHandler; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; +import androidx.core.util.Pair; +import androidx.webkit.WebViewAssetLoader; + +import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.uimanager.UIManagerHelper; +import com.reactnativecommunity.webview.events.TopHttpErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingFinishEvent; +import com.reactnativecommunity.webview.events.TopLoadingStartEvent; +import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; +import com.reactnativecommunity.webview.events.TopShouldStartLoadWithRequestEvent; + +import java.util.concurrent.atomic.AtomicReference; + +public class RNCWebViewClient extends WebViewClient { + private static String TAG = "RNCWebViewClient"; + protected static final int SHOULD_OVERRIDE_URL_LOADING_TIMEOUT = 250; + + protected boolean mLastLoadFailed = false; + protected RNCWebView.ProgressChangedFilter progressChangedFilter = null; + protected @Nullable String ignoreErrFailedForThisURL = null; + protected @Nullable RNCBasicAuthCredential basicAuthCredential = null; + + protected @Nullable WebViewAssetLoader webViewAssetLoader; + + public void setWebViewAssetLoader(@Nullable WebViewAssetLoader assetLoader) { + webViewAssetLoader = assetLoader; + } + + public void setIgnoreErrFailedForThisURL(@Nullable String url) { + ignoreErrFailedForThisURL = url; + } + + public void setBasicAuthCredential(@Nullable RNCBasicAuthCredential credential) { + basicAuthCredential = credential; + } + + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + if (webViewAssetLoader == null) { + return super.shouldInterceptRequest(view, request); + } + + return webViewAssetLoader.shouldInterceptRequest(request.getUrl()); + } + + @Override + public void onPageFinished(WebView webView, String url) { + super.onPageFinished(webView, url); + + if (!mLastLoadFailed) { + RNCWebView reactWebView = (RNCWebView) webView; + + reactWebView.callInjectedJavaScript(); + + emitFinishEvent(webView, url); + } + } + + @Override + public void doUpdateVisitedHistory (WebView webView, String url, boolean isReload) { + super.doUpdateVisitedHistory(webView, url, isReload); + + ((RNCWebView) webView).dispatchEvent( + webView, + new TopLoadingStartEvent( + webView.getId(), + createWebViewEvent(webView, url))); + } + + @Override + public void onPageStarted(WebView webView, String url, Bitmap favicon) { + super.onPageStarted(webView, url, favicon); + mLastLoadFailed = false; + + RNCWebView reactWebView = (RNCWebView) webView; + reactWebView.callInjectedJavaScriptBeforeContentLoaded(); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + final RNCWebView rncWebView = (RNCWebView) view; + final boolean isJsDebugging = ((ReactContext) view.getContext()).getJavaScriptContextHolder().get() == 0; + + if (!isJsDebugging && rncWebView.mCatalystInstance != null) { + final Pair> lock = RNCWebViewModuleImpl.shouldOverrideUrlLoadingLock.getNewLock(); + final double lockIdentifier = lock.first; + final AtomicReference lockObject = lock.second; + + final WritableMap event = createWebViewEvent(view, url); + event.putDouble("lockIdentifier", lockIdentifier); + rncWebView.sendDirectMessage("onShouldStartLoadWithRequest", event); + + try { + assert lockObject != null; + synchronized (lockObject) { + final long startTime = SystemClock.elapsedRealtime(); + while (lockObject.get() == RNCWebViewModuleImpl.ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.UNDECIDED) { + if (SystemClock.elapsedRealtime() - startTime > SHOULD_OVERRIDE_URL_LOADING_TIMEOUT) { + FLog.w(TAG, "Did not receive response to shouldOverrideUrlLoading in time, defaulting to allow loading."); + RNCWebViewModuleImpl.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); + return false; + } + lockObject.wait(SHOULD_OVERRIDE_URL_LOADING_TIMEOUT); + } + } + } catch (InterruptedException e) { + FLog.e(TAG, "shouldOverrideUrlLoading was interrupted while waiting for result.", e); + RNCWebViewModuleImpl.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); + return false; + } + + final boolean shouldOverride = lockObject.get() == RNCWebViewModuleImpl.ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.SHOULD_OVERRIDE; + RNCWebViewModuleImpl.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); + + return shouldOverride; + } else { + FLog.w(TAG, "Couldn't use blocking synchronous call for onShouldStartLoadWithRequest due to debugging or missing Catalyst instance, falling back to old event-and-load."); + progressChangedFilter.setWaitingForCommandLoadUrl(true); + + int reactTag = view.getId(); + UIManagerHelper.getEventDispatcherForReactTag((ReactContext) view.getContext(), reactTag).dispatchEvent(new TopShouldStartLoadWithRequestEvent( + reactTag, + createWebViewEvent(view, url))); + return true; + } + } + + @TargetApi(Build.VERSION_CODES.N) + @Override + public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { + final String url = request.getUrl().toString(); + return this.shouldOverrideUrlLoading(view, url); + } + + @Override + public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { + if (basicAuthCredential != null) { + handler.proceed(basicAuthCredential.username, basicAuthCredential.password); + return; + } + super.onReceivedHttpAuthRequest(view, handler, host, realm); + } + + @Override + public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { + // onReceivedSslError is called for most requests, per Android docs: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%2520android.webkit.SslErrorHandler,%2520android.net.http.SslError) + // WebView.getUrl() will return the top-level window URL. + // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the URL of the currently-rendered page). + // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. + String topWindowUrl = webView.getUrl(); + String failingUrl = error.getUrl(); + + // Cancel request after obtaining top-level URL. + // If request is cancelled before obtaining top-level URL, undesired behavior may occur. + // Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL. + handler.cancel(); + + if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { + // If error is not due to top-level navigation, then do not call onReceivedError() + Log.w(TAG, "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl); + return; + } + + int code = error.getPrimaryError(); + String description = ""; + String descriptionPrefix = "SSL error: "; + + // https://developer.android.com/reference/android/net/http/SslError.html + switch (code) { + case SslError.SSL_DATE_INVALID: + description = "The date of the certificate is invalid"; + break; + case SslError.SSL_EXPIRED: + description = "The certificate has expired"; + break; + case SslError.SSL_IDMISMATCH: + description = "Hostname mismatch"; + break; + case SslError.SSL_INVALID: + description = "A generic error occurred"; + break; + case SslError.SSL_NOTYETVALID: + description = "The certificate is not yet valid"; + break; + case SslError.SSL_UNTRUSTED: + description = "The certificate authority is not trusted"; + break; + default: + description = "Unknown SSL Error"; + break; + } + + description = descriptionPrefix + description; + + this.onReceivedError( + webView, + code, + description, + failingUrl + ); + } + + @Override + public void onReceivedError( + WebView webView, + int errorCode, + String description, + String failingUrl) { + + if (ignoreErrFailedForThisURL != null + && failingUrl.equals(ignoreErrFailedForThisURL) + && errorCode == -1 + && description.equals("net::ERR_FAILED")) { + + // This is a workaround for a bug in the WebView. + // See these chromium issues for more context: + // https://bugs.chromium.org/p/chromium/issues/detail?id=1023678 + // https://bugs.chromium.org/p/chromium/issues/detail?id=1050635 + // This entire commit should be reverted once this bug is resolved in chromium. + setIgnoreErrFailedForThisURL(null); + return; + } + + super.onReceivedError(webView, errorCode, description, failingUrl); + mLastLoadFailed = true; + + // In case of an error JS side expect to get a finish event first, and then get an error event + // Android WebView does it in the opposite way, so we need to simulate that behavior + emitFinishEvent(webView, failingUrl); + + WritableMap eventData = createWebViewEvent(webView, failingUrl); + eventData.putDouble("code", errorCode); + eventData.putString("description", description); + + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingErrorEvent(webView.getId(), eventData)); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + @Override + public void onReceivedHttpError( + WebView webView, + WebResourceRequest request, + WebResourceResponse errorResponse) { + super.onReceivedHttpError(webView, request, errorResponse); + + if (request.isForMainFrame()) { + WritableMap eventData = createWebViewEvent(webView, request.getUrl().toString()); + eventData.putInt("statusCode", errorResponse.getStatusCode()); + eventData.putString("description", errorResponse.getReasonPhrase()); + + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopHttpErrorEvent(webView.getId(), eventData)); + } + } + + @TargetApi(Build.VERSION_CODES.O) + @Override + public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) { + // WebViewClient.onRenderProcessGone was added in O. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return false; + } + super.onRenderProcessGone(webView, detail); + + if(detail.didCrash()){ + Log.e(TAG, "The WebView rendering process crashed."); + } + else{ + Log.w(TAG, "The WebView rendering process was killed by the system."); + } + + // if webView is null, we cannot return any event + // since the view is already dead/disposed + // still prevent the app crash by returning true. + if(webView == null){ + return true; + } + + WritableMap event = createWebViewEvent(webView, webView.getUrl()); + event.putBoolean("didCrash", detail.didCrash()); + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopRenderProcessGoneEvent(webView.getId(), event)); + + // returning false would crash the app. + return true; + } + + protected void emitFinishEvent(WebView webView, String url) { + int reactTag = webView.getId(); + UIManagerHelper.getEventDispatcherForReactTag((ReactContext) webView.getContext(), reactTag).dispatchEvent(new TopLoadingFinishEvent(webView.getId(), createWebViewEvent(webView, url))); + } + + protected WritableMap createWebViewEvent(WebView webView, String url) { + WritableMap event = Arguments.createMap(); + event.putDouble("target", webView.getId()); + // Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks + // like onPageFinished + event.putString("url", url); + event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100); + event.putString("title", webView.getTitle()); + event.putBoolean("canGoBack", webView.canGoBack()); + event.putBoolean("canGoForward", webView.canGoForward()); + return event; + } + + public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) { + progressChangedFilter = filter; + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/WebViewConfig.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java similarity index 77% rename from android/src/main/java/com/reactnativecommunity/webview/WebViewConfig.java rename to android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java index ac917db26c..eea047d2b8 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/WebViewConfig.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewConfig.java @@ -6,7 +6,6 @@ * Implement this interface in order to config your {@link WebView}. An instance of that * implementation will have to be given as a constructor argument to {@link RNCWebViewManager}. */ -public interface WebViewConfig { - - void configWebView(WebView webView); -} +public interface RNCWebViewConfig { + void configWebView(WebView webView); +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewContainer.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewContainer.java index 3eb777050f..f1a82c0272 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewContainer.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewContainer.java @@ -1,6 +1,7 @@ package com.reactnativecommunity.webview; import android.view.View; +import android.view.ViewGroup; import android.webkit.WebView; import android.widget.FrameLayout; @@ -14,7 +15,7 @@ public class RNCWebViewContainer extends FrameLayout { public static final int INVALID_VIEW_ID = -1; public int temporaryParentNodeTag = 0; - private RNCWebViewManager.RNCWebView RNCWebView; + private RNCWebView RNCWebView; public RNCWebViewContainer(ThemedReactContext reactContext) { super(reactContext); @@ -43,22 +44,22 @@ public void onChildViewRemoved(View parent, View child) {} } public interface Action { - void apply(RNCWebViewManager.RNCWebView webView); + void apply(RNCWebView webView); } /** - * Attaches a {@link RNCWebViewManager.RNCWebView} to the RNCWebView parent + * Attaches a {@link RNCWebView} to the RNCWebView parent * Throws an exception if the provided internal webView is already attached to a parent * @param webView */ - public void attachWebView(RNCWebViewManager.RNCWebView webView) { + public void attachWebView(RNCWebView webView) { this.RNCWebView = webView; // Only re-attach the WebView if parent is null if (webView.getParent() != null) { throw new IllegalArgumentException("WebView with key: " + webView.webViewKey + " parent is non null. Cannot re-attach webview."); } - + // Fixes broken full-screen modals/galleries due to body height being 0. addView(webView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } @@ -67,13 +68,13 @@ public void attachWebView(RNCWebViewManager.RNCWebView webView) { * Detaches the RNCWebView from the RNCWebViewContainer parent and returns a reference to it * @return RNCWebView */ - public RNCWebViewManager.RNCWebView detachWebView() { + public RNCWebView detachWebView() { if (RNCWebView == null) { throw new IllegalStateException("Webview is null"); } removeWebViewFromParent(); - RNCWebViewManager.RNCWebView webView = RNCWebView; + RNCWebView webView = RNCWebView; this.RNCWebView = null; return webView; } @@ -86,7 +87,7 @@ public void removeWebViewFromParent() { } @Nullable - public RNCWebViewManager.RNCWebView getWebView() { + public RNCWebView getWebView() { return RNCWebView; } diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java index cadd8ed50d..919b3ad508 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewFileProvider.java @@ -11,4 +11,4 @@ public class RNCWebViewFileProvider extends FileProvider { // This class intentionally left blank. -} +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java deleted file mode 100644 index 5ff42c5b46..0000000000 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ /dev/null @@ -1,2106 +0,0 @@ -package com.reactnativecommunity.webview; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.DownloadManager; -import android.content.pm.ActivityInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.net.Uri; -import android.net.http.SslError; -import android.os.Build; -import android.os.Environment; -import android.os.Message; -import android.os.SystemClock; -import android.text.TextUtils; -import android.util.Log; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.WindowManager; -import android.webkit.ConsoleMessage; -import android.webkit.CookieManager; -import android.webkit.DownloadListener; -import android.webkit.GeolocationPermissions; -import android.webkit.HttpAuthHandler; -import android.webkit.JavascriptInterface; -import android.webkit.PermissionRequest; -import android.webkit.RenderProcessGoneDetail; -import android.webkit.SslErrorHandler; -import android.webkit.URLUtil; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; -import android.webkit.WebResourceRequest; -import android.webkit.WebResourceResponse; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.core.content.ContextCompat; -import androidx.core.util.Pair; -import androidx.webkit.WebSettingsCompat; -import androidx.webkit.WebViewAssetLoader; -import androidx.webkit.WebViewFeature; - -import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.CatalystInstance; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableMapKeySetIterator; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeArray; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.common.MapBuilder; -import com.facebook.react.common.build.ReactBuildConfig; -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.facebook.react.modules.core.PermissionAwareActivity; -import com.facebook.react.modules.core.PermissionListener; -import com.facebook.react.uimanager.SimpleViewManager; -import com.facebook.react.uimanager.ThemedReactContext; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.facebook.react.uimanager.events.ContentSizeChangeEvent; -import com.facebook.react.uimanager.events.Event; -import com.facebook.react.uimanager.events.EventDispatcher; -import com.facebook.react.views.scroll.OnScrollDispatchHelper; -import com.facebook.react.views.scroll.ScrollEvent; -import com.facebook.react.views.scroll.ScrollEventType; -import com.reactnativecommunity.webview.RNCWebViewModule.ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState; -import com.reactnativecommunity.webview.events.TopHttpErrorEvent; -import com.reactnativecommunity.webview.events.TopLoadingErrorEvent; -import com.reactnativecommunity.webview.events.TopLoadingFinishEvent; -import com.reactnativecommunity.webview.events.TopLoadingProgressEvent; -import com.reactnativecommunity.webview.events.TopLoadingStartEvent; -import com.reactnativecommunity.webview.events.TopMessageEvent; -import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; -import com.reactnativecommunity.webview.events.TopShouldStartLoadWithRequestEvent; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Manages instances of {@link WebView} - *

- * Can accept following commands: - * - GO_BACK - * - GO_FORWARD - * - RELOAD - * - LOAD_URL - *

- * {@link WebView} instances could emit following direct events: - * - topLoadingFinish - * - topLoadingStart - * - topLoadingStart - * - topLoadingProgress - * - topShouldStartLoadWithRequest - *

- * Each event will carry the following properties: - * - target - view's react tag - * - url - url set for the webview - * - loading - whether webview is in a loading state - * - title - title of the current page - * - canGoBack - boolean, whether there is anything on a history stack to go back - * - canGoForward - boolean, whether it is possible to request GO_FORWARD command - */ -@ReactModule(name = RNCWebViewManager.REACT_CLASS) -public class RNCWebViewManager extends SimpleViewManager { - private static final String TAG = "RNCWebViewManager"; - - public static final int COMMAND_GO_BACK = 1; - public static final int COMMAND_GO_FORWARD = 2; - public static final int COMMAND_RELOAD = 3; - public static final int COMMAND_STOP_LOADING = 4; - public static final int COMMAND_POST_MESSAGE = 5; - public static final int COMMAND_INJECT_JAVASCRIPT = 6; - public static final int COMMAND_LOAD_URL = 7; - public static final int COMMAND_FOCUS = 8; - - // commands added by Discord - public static final int COMMAND_RELEASE = 4001; - - // android commands - public static final int COMMAND_CLEAR_FORM_DATA = 1000; - public static final int COMMAND_CLEAR_CACHE = 1001; - public static final int COMMAND_CLEAR_HISTORY = 1002; - - protected static final String REACT_CLASS = "RNCWebViewContainer"; - protected static final String HTML_ENCODING = "UTF-8"; - protected static final String HTML_MIME_TYPE = "text/html"; - protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView"; - protected static final String HTTP_METHOD_POST = "POST"; - // Use `webView.loadUrl("about:blank")` to reliably reset the view - // state and release page resources (including any running JavaScript). - protected static final String BLANK_URL = "about:blank"; - protected static final int SHOULD_OVERRIDE_URL_LOADING_TIMEOUT = 250; - protected static final String DEFAULT_DOWNLOADING_MESSAGE = "Downloading"; - protected static final String DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE = - "Cannot download files as permission was denied. Please provide permission to write to storage, in order to download files."; - protected WebViewConfig mWebViewConfig; - - protected RNCWebChromeClient mWebChromeClient = null; - protected boolean mAllowsFullscreenVideo = false; - protected boolean mAllowsProtectedMedia = false; - protected @Nullable String mUserAgent = null; - protected @Nullable String mUserAgentWithApplicationName = null; - protected @Nullable String mDownloadingMessage = null; - protected @Nullable String mLackPermissionToDownloadMessage = null; - - Set assetLoaderHandlerTypes = new HashSet<>(Arrays.asList("assets", "internal", "resources")); - - public RNCWebViewManager() { - mWebViewConfig = new WebViewConfig() { - public void configWebView(WebView webView) { - } - }; - } - - public RNCWebViewManager(WebViewConfig webViewConfig) { - mWebViewConfig = webViewConfig; - } - - @Override - public String getName() { - return REACT_CLASS; - } - - protected RNCWebView createRNCWebViewInstance(ThemedReactContext reactContext) { - return new RNCWebView(reactContext); - } - - @Override - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - protected RNCWebViewContainer createViewInstance(ThemedReactContext reactContext) { - RNCWebViewContainer wrapper = new RNCWebViewContainer(reactContext); - RNCWebView webView = createRNCWebViewInstance(reactContext); - wrapper.attachWebView(webView); - RNCWebViewMapManager.INSTANCE.getViewIdMap().put(webView.getId(), wrapper.getId()); - - setupWebChromeClient(reactContext, webView); - reactContext.addLifecycleEventListener(webView); - mWebViewConfig.configWebView(webView); - WebSettings settings = webView.getSettings(); - settings.setBuiltInZoomControls(true); - settings.setDisplayZoomControls(false); - settings.setDomStorageEnabled(true); - settings.setSupportMultipleWindows(true); - - settings.setAllowFileAccess(false); - settings.setAllowContentAccess(false); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - settings.setAllowFileAccessFromFileURLs(false); - setAllowUniversalAccessFromFileURLs(wrapper, false); - } - setMixedContentMode(wrapper, "never"); - - boolean isDebug = ((reactContext.getApplicationInfo().flags & - ApplicationInfo.FLAG_DEBUGGABLE) != 0); - - if (isDebug && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - WebView.setWebContentsDebuggingEnabled(true); - } - - webView.setDownloadListener(new DownloadListener() { - public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { - webView.setIgnoreErrFailedForThisURL(url); - - RNCWebViewModule module = getModule(reactContext); - - DownloadManager.Request request; - try { - request = new DownloadManager.Request(Uri.parse(url)); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Unsupported URI, aborting download", e); - return; - } - - String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); - String downloadMessage = "Downloading " + fileName; - - //Attempt to add cookie, if it exists - URL urlObj = null; - try { - urlObj = new URL(url); - String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost(); - String cookie = CookieManager.getInstance().getCookie(baseUrl); - request.addRequestHeader("Cookie", cookie); - } catch (MalformedURLException e) { - Log.w(TAG, "Error getting cookie for DownloadManager", e); - } - - //Finish setting up request - request.addRequestHeader("User-Agent", userAgent); - request.setTitle(fileName); - request.setDescription(downloadMessage); - request.allowScanningByMediaScanner(); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); - - module.setDownloadRequest(request); - - if (module.grantFileDownloaderPermissions(getDownloadingMessage(), getLackPermissionToDownloadMessage())) { - module.downloadFile(getDownloadingMessage()); - } - } - }); - - return wrapper; - } - - private String getDownloadingMessage() { - return mDownloadingMessage == null ? DEFAULT_DOWNLOADING_MESSAGE : mDownloadingMessage; - } - - private String getLackPermissionToDownloadMessage() { - return mDownloadingMessage == null ? DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE : mLackPermissionToDownloadMessage; - } - - @ReactProp(name = "javaScriptEnabled") - public void setJavaScriptEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setJavaScriptEnabled(enabled)); - } - - @ReactProp(name = "setBuiltInZoomControls") - public void setBuiltInZoomControls(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setBuiltInZoomControls(enabled)); - } - - @ReactProp(name = "setDisplayZoomControls") - public void setDisplayZoomControls(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setDisplayZoomControls(enabled)); - } - - @ReactProp(name = "setSupportMultipleWindows") - public void setSupportMultipleWindows(RNCWebViewContainer view, boolean enabled){ - view.ifHasRNCWebView(webView -> webView.getSettings().setSupportMultipleWindows(enabled)); - } - - @ReactProp(name = "webViewKey") - public void setWebViewKey(RNCWebViewContainer view, String webViewKey) { - Map rncWebViewMap = RNCWebViewMapManager.INSTANCE.getRncWebViewMap(); - - if (rncWebViewMap.containsKey(webViewKey)) { - RNCWebView webView = (RNCWebView) rncWebViewMap.get(webViewKey); - - ViewGroup webViewParent = (ViewGroup)webView.getParent(); - - // If the RNCWebView is attached to an existing RNCWebViewContainer, first detach - // it from the existing RNCWebViewContainer. - if (webViewParent != null && webViewParent instanceof RNCWebViewContainer) { - RNCWebViewContainer existingRncWebViewContainer = (RNCWebViewContainer) webView.getParent(); - existingRncWebViewContainer.detachWebView(); - - // The chrome client was originally setup on instance creation but might be pointing to the wrong webview - // so it's reset here. - // Not entirely sure why there is a single instance of the webchrome client for all webviews? - setupWebChromeClient((ThemedReactContext) existingRncWebViewContainer.getContext(), webView); - } - - // The webview might be attached to the temporary parent; if so, remove it first. - if (webViewParent != null) { - webViewParent.removeView(webView); - } - - view.attachWebView(webView); - } - - // Update all maps with the view + set/update key - // This means an existing webview can update it's own key - view.ifHasRNCWebView(webView -> { - webView.setWebViewKey(webViewKey); - RNCWebViewMapManager.INSTANCE.getViewIdMap().put(webView.getId(), view.getId()); - rncWebViewMap.put(webViewKey, webView); - }); - } - - @ReactProp(name = "temporaryParentNodeTag") - public void setTemporaryParentNodeTag(RNCWebViewContainer view, int nodeTag) { - view.temporaryParentNodeTag = nodeTag; - } - - @ReactProp(name = "showsHorizontalScrollIndicator") - public void setShowsHorizontalScrollIndicator(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setHorizontalScrollBarEnabled(enabled)); - } - - @ReactProp(name = "showsVerticalScrollIndicator") - public void setShowsVerticalScrollIndicator(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setVerticalScrollBarEnabled(enabled)); - } - - @ReactProp(name = "downloadingMessage") - public void setDownloadingMessage(WebView view, String message) { - mDownloadingMessage = message; - } - - @ReactProp(name = "lackPermissionToDownloadMessage") - public void setLackPermissionToDownlaodMessage(WebView view, String message) { - mLackPermissionToDownloadMessage = message; - } - - @ReactProp(name = "cacheEnabled") - public void setCacheEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> { - webView.getSettings().setCacheMode(enabled ? WebSettings.LOAD_DEFAULT : WebSettings.LOAD_NO_CACHE); - }); - } - - @ReactProp(name = "cacheMode") - public void setCacheMode(RNCWebViewContainer view, String cacheModeString) { - Integer cacheMode; - switch (cacheModeString) { - case "LOAD_CACHE_ONLY": - cacheMode = WebSettings.LOAD_CACHE_ONLY; - break; - case "LOAD_CACHE_ELSE_NETWORK": - cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK; - break; - case "LOAD_NO_CACHE": - cacheMode = WebSettings.LOAD_NO_CACHE; - break; - case "LOAD_DEFAULT": - default: - cacheMode = WebSettings.LOAD_DEFAULT; - break; - } - view.ifHasRNCWebView(webView -> webView.getSettings().setCacheMode(cacheMode)); - } - - @ReactProp(name = "androidHardwareAccelerationDisabled") - public void setHardwareAccelerationDisabled(RNCWebViewContainer view, boolean disabled) { - if (disabled) { - view.ifHasRNCWebView(webView -> webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)); - } - } - - @ReactProp(name = "androidLayerType") - public void setLayerType(RNCWebViewContainer view, String layerTypeString) { - final int layerType; - switch (layerTypeString) { - case "hardware": - layerType = View.LAYER_TYPE_HARDWARE; - break; - case "software": - layerType = View.LAYER_TYPE_SOFTWARE; - break; - default: - layerType = View.LAYER_TYPE_NONE; - } - - view.ifHasRNCWebView(webView -> webView.setLayerType(layerType, null)); - } - - @ReactProp(name = "androidAssetLoaderConfig") - public void setAssetLoaderConfig(RNCWebViewContainer view, @Nullable ReadableMap config) { - WebViewAssetLoader.Builder builder = new WebViewAssetLoader.Builder(); - - String domain = config.getString("domain"); - if (domain != null) { - builder.setDomain(domain); - } - - if (config.hasKey("httpAllowed")) { - builder.setHttpAllowed(config.getBoolean("httpAllowed")); - } - - ReadableArray handlers = config.getArray("pathHandlers"); - if (handlers != null && handlers.size() > 0) { - for (int i = 0; i < handlers.size(); i++) { - final ReadableMap handler = handlers.getMap(i); - String handlerType = handler.getString("type"); - - if (handlerType == null) { - FLog.w(TAG, "WebViewAssetLoader error. Path Handler type is null."); - continue; - } - - if (!assetLoaderHandlerTypes.contains(handlerType)) { - FLog.w(TAG, "WebViewAssetLoader error. Skipping Path Handler. Unexpected handler type: " + handlerType + ". Path Handler type must be one of " + assetLoaderHandlerTypes); - continue; - } - - String handlerPath = handler.getString("path"); - - if (handlerPath == null) { - FLog.w(TAG, "WebViewAssetLoader error. Skipping Path Handler. Handler path is missing"); - continue; - } - - if (handlerType.equals("resources")) { - builder.addPathHandler(handlerPath, new WebViewAssetLoader.ResourcesPathHandler(view.getContext())); - } else if (handlerType.equals("assets")) { - builder.addPathHandler(handlerPath, new WebViewAssetLoader.AssetsPathHandler(view.getContext())); - } else if (handlerType.equals("internal")) { - String directory = handler.getString("directory"); - if (directory == null) { - FLog.w(TAG, "WebViewAssetLoader error. Skipping Path Handler. Directory is missing for internal handler path"); - continue; - } - builder.addPathHandler(handlerPath, new WebViewAssetLoader.InternalStoragePathHandler(view.getContext(), new File(directory))); - } - } - } else { - FLog.w(TAG, "WebViewAssetLoader error. No Path Handlers found."); - } - - WebViewAssetLoader assetLoader = builder.build(); - view.ifHasRNCWebView(webView -> webView.setWebViewAssetLoader(assetLoader)); - } - - - @ReactProp(name = "overScrollMode") - public void setOverScrollMode(RNCWebViewContainer view, String overScrollModeString) { - final Integer overScrollMode; - switch (overScrollModeString) { - case "never": - overScrollMode = View.OVER_SCROLL_NEVER; - break; - case "content": - overScrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS; - break; - case "always": - default: - overScrollMode = View.OVER_SCROLL_ALWAYS; - break; - } - view.ifHasRNCWebView(webView -> webView.setOverScrollMode(overScrollMode)); - } - - @ReactProp(name = "nestedScrollEnabled") - public void setNestedScrollEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setNestedScrollEnabled(enabled)); - } - - @ReactProp(name = "thirdPartyCookiesEnabled") - public void setThirdPartyCookiesEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().setAcceptThirdPartyCookies(webView, enabled); - } - }); - } - - @ReactProp(name = "textZoom") - public void setTextZoom(RNCWebViewContainer view, int value) { - view.ifHasRNCWebView(webView -> webView.getSettings().setTextZoom(value)); - } - - @ReactProp(name = "scalesPageToFit") - public void setScalesPageToFit(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> { - webView.getSettings().setLoadWithOverviewMode(enabled); - webView.getSettings().setUseWideViewPort(enabled); - }); - } - - @ReactProp(name = "domStorageEnabled") - public void setDomStorageEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setDomStorageEnabled(enabled)); - } - - @ReactProp(name = "userAgent") - public void setUserAgent(RNCWebViewContainer view, @Nullable String userAgent) { - if (userAgent != null) { - mUserAgent = userAgent; - } else { - mUserAgent = null; - } - view.ifHasRNCWebView(this::setUserAgentString); - } - - @ReactProp(name = "applicationNameForUserAgent") - public void setApplicationNameForUserAgent(RNCWebViewContainer view, @Nullable String applicationName) { - if(applicationName != null) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - String defaultUserAgent = WebSettings.getDefaultUserAgent(view.getContext()); - mUserAgentWithApplicationName = defaultUserAgent + " " + applicationName; - } - } else { - mUserAgentWithApplicationName = null; - } - view.ifHasRNCWebView(this::setUserAgentString); - } - - protected void setUserAgentString(WebView view) { - if(mUserAgent != null) { - view.getSettings().setUserAgentString(mUserAgent); - } else if(mUserAgentWithApplicationName != null) { - view.getSettings().setUserAgentString(mUserAgentWithApplicationName); - } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - // handle unsets of `userAgent` prop as long as device is >= API 17 - view.getSettings().setUserAgentString(WebSettings.getDefaultUserAgent(view.getContext())); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - @ReactProp(name = "mediaPlaybackRequiresUserAction") - public void setMediaPlaybackRequiresUserAction(RNCWebViewContainer view, boolean requires) { - view.ifHasRNCWebView(webView -> webView.getSettings().setMediaPlaybackRequiresUserGesture(requires)); - } - - @ReactProp(name = "javaScriptCanOpenWindowsAutomatically") - public void setJavaScriptCanOpenWindowsAutomatically(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(enabled)); - } - - @ReactProp(name = "allowFileAccessFromFileURLs") - public void setAllowFileAccessFromFileURLs(RNCWebViewContainer view, boolean allow) { - view.ifHasRNCWebView(webView -> webView.getSettings().setAllowFileAccessFromFileURLs(allow)); - } - - @ReactProp(name = "allowUniversalAccessFromFileURLs") - public void setAllowUniversalAccessFromFileURLs(RNCWebViewContainer view, boolean allow) { - view.ifHasRNCWebView(webView -> webView.getSettings().setAllowUniversalAccessFromFileURLs(allow)); - } - - @ReactProp(name = "saveFormDataDisabled") - public void setSaveFormDataDisabled(RNCWebViewContainer view, boolean disable) { - view.ifHasRNCWebView(webView -> webView.getSettings().setSaveFormData(!disable)); - } - - @ReactProp(name = "injectedJavaScript") - public void setInjectedJavaScript(RNCWebViewContainer view, @Nullable String injectedJavaScript) { - view.ifHasRNCWebView(webView -> webView.setInjectedJavaScript(injectedJavaScript)); - } - - @ReactProp(name = "injectedJavaScriptBeforeContentLoaded") - public void setInjectedJavaScriptBeforeContentLoaded(RNCWebViewContainer view, @Nullable String injectedJavaScriptBeforeContentLoaded) { - view.ifHasRNCWebView(webView -> webView.setInjectedJavaScriptBeforeContentLoaded(injectedJavaScriptBeforeContentLoaded)); - } - - @ReactProp(name = "injectedJavaScriptForMainFrameOnly") - public void setInjectedJavaScriptForMainFrameOnly(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setInjectedJavaScriptForMainFrameOnly(enabled)); - } - - @ReactProp(name = "injectedJavaScriptBeforeContentLoadedForMainFrameOnly") - public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(enabled)); - } - - @ReactProp(name = "messagingEnabled") - public void setMessagingEnabled(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> webView.setMessagingEnabled(enabled)); - } - - @ReactProp(name = "messagingModuleName") - public void setMessagingModuleName(RNCWebViewContainer view, String moduleName) { - view.ifHasRNCWebView(webView -> webView.setMessagingModuleName(moduleName)); - } - - @ReactProp(name = "incognito") - public void setIncognito(RNCWebViewContainer view, boolean enabled) { - // Don't do anything when incognito is disabled - if (!enabled) { - return; - } - - // Remove all previous cookies - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - CookieManager.getInstance().removeAllCookies(null); - } else { - CookieManager.getInstance().removeAllCookie(); - } - - view.ifHasRNCWebView(webView -> { - // Disable caching - webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); - webView.clearHistory(); - webView.clearCache(true); - - // No form data or autofill enabled - webView.clearFormData(); - webView.getSettings().setSavePassword(false); - webView.getSettings().setSaveFormData(false); - }); - } - - @ReactProp(name = "source") - public void setSource(RNCWebViewContainer view, @Nullable ReadableMap source) { - view.ifHasRNCWebView(webView -> { - - // Do not reload reload webview if the source prop has not changed - if (webView.webViewKey != null && !webView.isNewSource(source)) { - return; - } - - webView.setSource(source); - - if (source != null) { - if (source.hasKey("html")) { - String html = source.getString("html"); - String baseUrl = source.hasKey("baseUrl") ? source.getString("baseUrl") : ""; - webView.loadDataWithBaseURL(baseUrl, html, HTML_MIME_TYPE, HTML_ENCODING, null); - return; - } - if (source.hasKey("uri")) { - String url = source.getString("uri"); - String previousUrl = webView.getUrl(); - if (previousUrl != null && previousUrl.equals(url)) { - return; - } - if (source.hasKey("method")) { - String method = source.getString("method"); - if (method.equalsIgnoreCase(HTTP_METHOD_POST)) { - byte[] postData = null; - if (source.hasKey("body")) { - String body = source.getString("body"); - try { - postData = body.getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - postData = body.getBytes(); - } - } - if (postData == null) { - postData = new byte[0]; - } - webView.postUrl(url, postData); - return; - } - } - HashMap headerMap = new HashMap<>(); - if (source.hasKey("headers")) { - ReadableMap headers = source.getMap("headers"); - ReadableMapKeySetIterator iter = headers.keySetIterator(); - while (iter.hasNextKey()) { - String key = iter.nextKey(); - if ("user-agent".equals(key.toLowerCase(Locale.ENGLISH))) { - if (webView.getSettings() != null) { - webView.getSettings().setUserAgentString(headers.getString(key)); - } - } else { - headerMap.put(key, headers.getString(key)); - } - } - } - webView.loadUrl(url, headerMap); - return; - } - } - webView.loadUrl(BLANK_URL); - }); - } - - @ReactProp(name = "basicAuthCredential") - public void setBasicAuthCredential(RNCWebViewContainer view, @Nullable ReadableMap credential) { - view.ifHasRNCWebView(webView -> { - @Nullable BasicAuthCredential basicAuthCredential = null; - if (credential != null) { - if (credential.hasKey("username") && credential.hasKey("password")) { - String username = credential.getString("username"); - String password = credential.getString("password"); - basicAuthCredential = new BasicAuthCredential(username, password); - } - } - webView.setBasicAuthCredential(basicAuthCredential); - }); - } - - @ReactProp(name = "onContentSizeChange") - public void setOnContentSizeChange(RNCWebViewContainer view, boolean sendContentSizeChangeEvents) { - view.ifHasRNCWebView(webView -> webView.setSendContentSizeChangeEvents(sendContentSizeChangeEvents)); - } - - @ReactProp(name = "mixedContentMode") - public void setMixedContentMode(RNCWebViewContainer view, @Nullable String mixedContentMode) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (mixedContentMode == null || "never".equals(mixedContentMode)) { - view.ifHasRNCWebView(webView -> webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW)); - } else if ("always".equals(mixedContentMode)) { - view.ifHasRNCWebView(webView -> webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW)); - } else if ("compatibility".equals(mixedContentMode)) { - view.ifHasRNCWebView(webView -> webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE)); - } - } - } - - @ReactProp(name = "urlPrefixesForDefaultIntent") - public void setUrlPrefixesForDefaultIntent( - RNCWebViewContainer view, - @Nullable ReadableArray urlPrefixesForDefaultIntent) { - view.ifHasRNCWebView(webView -> { - RNCWebViewClient client = webView.getRNCWebViewClient(); - if (client != null && urlPrefixesForDefaultIntent != null) { - client.setUrlPrefixesForDefaultIntent(urlPrefixesForDefaultIntent); - } - }); - } - - @ReactProp(name = "allowsFullscreenVideo") - public void setAllowsFullscreenVideo( - RNCWebViewContainer view, - @Nullable Boolean allowsFullscreenVideo) { - mAllowsFullscreenVideo = allowsFullscreenVideo != null && allowsFullscreenVideo; - view.ifHasRNCWebView(webView -> setupWebChromeClient((ReactContext)view.getContext(), webView)); - } - - @ReactProp(name = "allowFileAccess") - public void setAllowFileAccess( - RNCWebViewContainer view, - @Nullable Boolean allowFileAccess) { - view.ifHasRNCWebView(webView -> webView.getSettings().setAllowFileAccess(allowFileAccess != null && allowFileAccess)); - } - - @ReactProp(name = "geolocationEnabled") - public void setGeolocationEnabled( - RNCWebViewContainer view, - @Nullable Boolean isGeolocationEnabled) { - view.ifHasRNCWebView(webView -> webView.getSettings().setGeolocationEnabled(isGeolocationEnabled != null && isGeolocationEnabled)); - } - - @ReactProp(name = "onScroll") - public void setOnScroll(RNCWebViewContainer view, boolean hasScrollEvent) { - view.ifHasRNCWebView(webView -> webView.setHasScrollEvent(hasScrollEvent)); - } - - @ReactProp(name = "forceDarkOn") - public void setForceDarkOn(RNCWebViewContainer view, boolean enabled) { - view.ifHasRNCWebView(webView -> { - // Only Android 10+ support dark mode - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - // Switch WebView dark mode - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { - int forceDarkMode = enabled ? WebSettingsCompat.FORCE_DARK_ON : WebSettingsCompat.FORCE_DARK_OFF; - WebSettingsCompat.setForceDark(webView.getSettings(), forceDarkMode); - } - - // Set how WebView content should be darkened. - // PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING: checks for the "color-scheme" tag. - // If present, it uses media queries. If absent, it applies user-agent (automatic) - // More information about Force Dark Strategy can be found here: - // https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setForceDarkStrategy(android.webkit.WebSettings) - if (enabled && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { - WebSettingsCompat.setForceDarkStrategy(webView.getSettings(), WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING); - } - } - }); - } - - @ReactProp(name = "minimumFontSize") - public void setMinimumFontSize(RNCWebViewContainer view, int fontSize) { - view.ifHasRNCWebView(webView -> webView.getSettings().setMinimumFontSize(fontSize)); - } - - @ReactProp(name = "allowsProtectedMedia") - public void setAllowsProtectedMedia(WebView view, boolean enabled) { - // This variable is used to keep consistency - // in case a new WebChromeClient is created - // (eg. when mAllowsFullScreenVideo changes) - mAllowsProtectedMedia = enabled; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - WebChromeClient client = view.getWebChromeClient(); - if (client != null && client instanceof RNCWebChromeClient) { - ((RNCWebChromeClient) client).setAllowsProtectedMedia(enabled); - } - } - } - - @Override - protected void addEventEmitters(ThemedReactContext reactContext, RNCWebViewContainer view) { - // Do not register default touch emitter and let WebView implementation handle touches - view.ifHasRNCWebView(webView -> webView.setWebViewClient(new RNCWebViewClient())); - } - - @Override - public Map getExportedCustomDirectEventTypeConstants() { - Map export = super.getExportedCustomDirectEventTypeConstants(); - if (export == null) { - export = MapBuilder.newHashMap(); - } - // Default events but adding them here explicitly for clarity - export.put(TopLoadingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingStart")); - export.put(TopLoadingFinishEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingFinish")); - export.put(TopLoadingErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingError")); - export.put(TopMessageEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMessage")); - // !Default events but adding them here explicitly for clarity - - export.put(TopLoadingProgressEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingProgress")); - export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest")); - export.put(ScrollEventType.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll")); - export.put(TopHttpErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onHttpError")); - export.put(TopRenderProcessGoneEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRenderProcessGone")); - return export; - } - - @Override - public @Nullable - Map getCommandsMap() { - return MapBuilder.builder() - .put("goBack", COMMAND_GO_BACK) - .put("goForward", COMMAND_GO_FORWARD) - .put("reload", COMMAND_RELOAD) - .put("stopLoading", COMMAND_STOP_LOADING) - .put("postMessage", COMMAND_POST_MESSAGE) - .put("injectJavaScript", COMMAND_INJECT_JAVASCRIPT) - .put("loadUrl", COMMAND_LOAD_URL) - .put("requestFocus", COMMAND_FOCUS) - .put("clearFormData", COMMAND_CLEAR_FORM_DATA) - .put("clearCache", COMMAND_CLEAR_CACHE) - .put("clearHistory", COMMAND_CLEAR_HISTORY) - .put("release", COMMAND_RELEASE) - .build(); - } - - @Override - public void receiveCommand(@NonNull RNCWebViewContainer view, String commandId, @Nullable ReadableArray args) { - view.ifHasRNCWebView(root -> { - switch (commandId) { - case "goBack": - root.goBack(); - break; - case "goForward": - root.goForward(); - break; - case "reload": - root.reload(); - break; - case "stopLoading": - root.stopLoading(); - break; - case "postMessage": - try { - RNCWebView reactWebView = (RNCWebView) root; - JSONObject eventInitDict = new JSONObject(); - eventInitDict.put("data", args.getString(0)); - reactWebView.evaluateJavascriptWithFallback("(function () {" + - "var event;" + - "var data = " + eventInitDict.toString() + ";" + - "try {" + - "event = new MessageEvent('message', data);" + - "} catch (e) {" + - "event = document.createEvent('MessageEvent');" + - "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + - "}" + - "document.dispatchEvent(event);" + - "})();"); - } catch (JSONException e) { - throw new RuntimeException(e); - } - break; - case "injectJavaScript": - RNCWebView reactWebView = (RNCWebView) root; - reactWebView.evaluateJavascriptWithFallback(args.getString(0)); - break; - case "loadUrl": - if (args == null) { - throw new RuntimeException("Arguments for loading an url are null!"); - } - ((RNCWebView) root).progressChangedFilter.setWaitingForCommandLoadUrl(false); - root.loadUrl(args.getString(0)); - break; - case "requestFocus": - root.requestFocus(); - break; - case "clearFormData": - root.clearFormData(); - break; - case "clearCache": - boolean includeDiskFiles = args != null && args.getBoolean(0); - root.clearCache(includeDiskFiles); - break; - case "clearHistory": - root.clearHistory(); - break; - case "release": - // no-op for now - break; - } - }); - super.receiveCommand(view, commandId, args); - } - - @Override - public void onDropViewInstance(RNCWebViewContainer view) { - super.onDropViewInstance(view); - - // The internal webview can be null since the view may have been already reattached - if (view.getWebView() == null) { - return; - } - - view.ifHasRNCWebView(webView -> { - if (webView.webViewKey == null) { - ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener(webView); - webView.cleanupCallbacksAndDestroy(); - mWebChromeClient = null; - } else { - view.removeWebViewFromParent(); - RNCWebViewMapManager.INSTANCE.getViewIdMap().remove(webView.getId()); - - if (view.temporaryParentNodeTag != 0) { - // Re-attach the internal webview to the temporary parent. - UIManagerModule uiManagerModule = ((ReactContext) view.getContext()).getNativeModule(UIManagerModule.class); - ViewGroup temporaryParentView = (ViewGroup)uiManagerModule.resolveView(view.temporaryParentNodeTag); - temporaryParentView.addView(webView); - - // Resize view to match parent - webView.measure( - View.MeasureSpec.makeMeasureSpec(temporaryParentView.getMeasuredWidth(), View.MeasureSpec.EXACTLY), - View.MeasureSpec.makeMeasureSpec(temporaryParentView.getMeasuredHeight(), View.MeasureSpec.EXACTLY) - ); - - webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight()); - } - } - }); - } - - public static RNCWebViewModule getModule(ReactContext reactContext) { - return reactContext.getNativeModule(RNCWebViewModule.class); - } - - protected void setupWebChromeClient(ReactContext reactContext, WebView webView) { - Activity activity = reactContext.getCurrentActivity(); - - if (mAllowsFullscreenVideo && activity != null) { - int initialRequestedOrientation = activity.getRequestedOrientation(); - - mWebChromeClient = new RNCWebChromeClient(reactContext, webView) { - @Override - public Bitmap getDefaultVideoPoster() { - return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); - } - - @Override - public void onShowCustomView(View view, CustomViewCallback callback) { - if (mVideoView != null) { - callback.onCustomViewHidden(); - return; - } - - mVideoView = view; - mCustomViewCallback = callback; - - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY); - activity.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, - WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS - ); - } - - mVideoView.setBackgroundColor(Color.BLACK); - - // Since RN's Modals interfere with the View hierarchy - // we will decide which View to hide if the hierarchy - // does not match (i.e., the WebView is within a Modal) - // NOTE: We could use `mWebView.getRootView()` instead of `getRootView()` - // but that breaks the Modal's styles and layout, so we need this to render - // in the main View hierarchy regardless - ViewGroup rootView = getRootView(); - rootView.addView(mVideoView, FULLSCREEN_LAYOUT_PARAMS); - - // Different root views, we are in a Modal - if (rootView.getRootView() != mWebView.getRootView()) { - mWebView.getRootView().setVisibility(View.GONE); - } else { - // Same view hierarchy (no Modal), just hide the WebView then - mWebView.setVisibility(View.GONE); - } - - mReactContext.addLifecycleEventListener(this); - } - - @Override - public void onHideCustomView() { - if (mVideoView == null) { - return; - } - - // Same logic as above - ViewGroup rootView = getRootView(); - - if (rootView.getRootView() != mWebView.getRootView()) { - mWebView.getRootView().setVisibility(View.VISIBLE); - } else { - // Same view hierarchy (no Modal) - mWebView.setVisibility(View.VISIBLE); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); - } - - rootView.removeView(mVideoView); - mCustomViewCallback.onCustomViewHidden(); - - mVideoView = null; - mCustomViewCallback = null; - - activity.setRequestedOrientation(initialRequestedOrientation); - - mReactContext.removeLifecycleEventListener(this); - } - }; - } else { - if (mWebChromeClient != null) { - mWebChromeClient.onHideCustomView(); - } - - mWebChromeClient = new RNCWebChromeClient(reactContext, webView) { - @Override - public Bitmap getDefaultVideoPoster() { - return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888); - } - }; - } - mWebChromeClient.setAllowsProtectedMedia(mAllowsProtectedMedia); - webView.setWebChromeClient(mWebChromeClient); - } - - protected static class RNCWebViewClient extends WebViewClient { - - protected boolean mLastLoadFailed = false; - protected @Nullable - ReadableArray mUrlPrefixesForDefaultIntent; - protected RNCWebView.ProgressChangedFilter progressChangedFilter = null; - protected @Nullable String ignoreErrFailedForThisURL = null; - protected @Nullable BasicAuthCredential basicAuthCredential = null; - protected @Nullable WebViewAssetLoader webViewAssetLoader; - - public void setWebViewAssetLoader(@Nullable WebViewAssetLoader assetLoader) { - webViewAssetLoader = assetLoader; - } - - public void setIgnoreErrFailedForThisURL(@Nullable String url) { - ignoreErrFailedForThisURL = url; - } - - public void setBasicAuthCredential(@Nullable BasicAuthCredential credential) { - basicAuthCredential = credential; - } - - @Nullable - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - if (webViewAssetLoader == null) { - return super.shouldInterceptRequest(view, request); - } - - return webViewAssetLoader.shouldInterceptRequest(request.getUrl()); - } - - @Override - public void onPageFinished(WebView webView, String url) { - super.onPageFinished(webView, url); - - if (!mLastLoadFailed) { - RNCWebView reactWebView = (RNCWebView) webView; - - reactWebView.callInjectedJavaScript(); - - emitFinishEvent(webView, url); - } - } - - @Override - public void onPageStarted(WebView webView, String url, Bitmap favicon) { - super.onPageStarted(webView, url, favicon); - mLastLoadFailed = false; - - RNCWebView reactWebView = (RNCWebView) webView; - reactWebView.callInjectedJavaScriptBeforeContentLoaded(); - - ((RNCWebView) webView).dispatchEvent( - webView, - new TopLoadingStartEvent( - RNCWebViewContainer.getRNCWebViewId(webView), - createWebViewEvent(webView, url))); - } - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - final RNCWebView RNCWebView = (RNCWebView) view; - final boolean isJsDebugging = ((ReactContext) view.getContext()).getJavaScriptContextHolder().get() == 0; - - if (!isJsDebugging && RNCWebView.mCatalystInstance != null) { - final Pair> lock = RNCWebViewModule.shouldOverrideUrlLoadingLock.getNewLock(); - final int lockIdentifier = lock.first; - final AtomicReference lockObject = lock.second; - - final WritableMap event = createWebViewEvent(view, url); - event.putInt("lockIdentifier", lockIdentifier); - RNCWebView.sendDirectMessage("onShouldStartLoadWithRequest", event); - - try { - assert lockObject != null; - synchronized (lockObject) { - final long startTime = SystemClock.elapsedRealtime(); - while (lockObject.get() == ShouldOverrideCallbackState.UNDECIDED) { - if (SystemClock.elapsedRealtime() - startTime > SHOULD_OVERRIDE_URL_LOADING_TIMEOUT) { - FLog.w(TAG, "Did not receive response to shouldOverrideUrlLoading in time, defaulting to allow loading."); - RNCWebViewModule.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); - return false; - } - lockObject.wait(SHOULD_OVERRIDE_URL_LOADING_TIMEOUT); - } - } - } catch (InterruptedException e) { - FLog.e(TAG, "shouldOverrideUrlLoading was interrupted while waiting for result.", e); - RNCWebViewModule.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); - return false; - } - - final boolean shouldOverride = lockObject.get() == ShouldOverrideCallbackState.SHOULD_OVERRIDE; - RNCWebViewModule.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); - - return shouldOverride; - } else { - FLog.w(TAG, "Couldn't use blocking synchronous call for onShouldStartLoadWithRequest due to debugging or missing Catalyst instance, falling back to old event-and-load."); - progressChangedFilter.setWaitingForCommandLoadUrl(true); - ((RNCWebView) view).dispatchEvent( - view, - new TopShouldStartLoadWithRequestEvent( - RNCWebViewContainer.getRNCWebViewId(view), - createWebViewEvent(view, url))); - return true; - } - } - - @TargetApi(Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { - final String url = request.getUrl().toString(); - return this.shouldOverrideUrlLoading(view, url); - } - - @Override - public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { - if (basicAuthCredential != null) { - handler.proceed(basicAuthCredential.username, basicAuthCredential.password); - return; - } - super.onReceivedHttpAuthRequest(view, handler, host, realm); - } - - @Override - public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { - // onReceivedSslError is called for most requests, per Android docs: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%2520android.webkit.SslErrorHandler,%2520android.net.http.SslError) - // WebView.getUrl() will return the top-level window URL. - // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the URL of the currently-rendered page). - // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. - String topWindowUrl = webView.getUrl(); - String failingUrl = error.getUrl(); - - // Cancel request after obtaining top-level URL. - // If request is cancelled before obtaining top-level URL, undesired behavior may occur. - // Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL. - handler.cancel(); - - if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { - // If error is not due to top-level navigation, then do not call onReceivedError() - Log.w(TAG, "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl); - return; - } - - int code = error.getPrimaryError(); - String description = ""; - String descriptionPrefix = "SSL error: "; - - // https://developer.android.com/reference/android/net/http/SslError.html - switch (code) { - case SslError.SSL_DATE_INVALID: - description = "The date of the certificate is invalid"; - break; - case SslError.SSL_EXPIRED: - description = "The certificate has expired"; - break; - case SslError.SSL_IDMISMATCH: - description = "Hostname mismatch"; - break; - case SslError.SSL_INVALID: - description = "A generic error occurred"; - break; - case SslError.SSL_NOTYETVALID: - description = "The certificate is not yet valid"; - break; - case SslError.SSL_UNTRUSTED: - description = "The certificate authority is not trusted"; - break; - default: - description = "Unknown SSL Error"; - break; - } - - description = descriptionPrefix + description; - - this.onReceivedError( - webView, - code, - description, - failingUrl - ); - } - - @Override - public void onReceivedError( - WebView webView, - int errorCode, - String description, - String failingUrl) { - - if (ignoreErrFailedForThisURL != null - && failingUrl.equals(ignoreErrFailedForThisURL) - && errorCode == -1 - && description.equals("net::ERR_FAILED")) { - - // This is a workaround for a bug in the WebView. - // See these chromium issues for more context: - // https://bugs.chromium.org/p/chromium/issues/detail?id=1023678 - // https://bugs.chromium.org/p/chromium/issues/detail?id=1050635 - // This entire commit should be reverted once this bug is resolved in chromium. - setIgnoreErrFailedForThisURL(null); - return; - } - - super.onReceivedError(webView, errorCode, description, failingUrl); - mLastLoadFailed = true; - - // In case of an error JS side expect to get a finish event first, and then get an error event - // Android WebView does it in the opposite way, so we need to simulate that behavior - emitFinishEvent(webView, failingUrl); - - WritableMap eventData = createWebViewEvent(webView, failingUrl); - eventData.putDouble("code", errorCode); - eventData.putString("description", description); - - ((RNCWebView) webView).dispatchEvent( - webView, - new TopLoadingErrorEvent(RNCWebViewContainer.getRNCWebViewId(webView), eventData)); - } - - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedHttpError( - WebView webView, - WebResourceRequest request, - WebResourceResponse errorResponse) { - super.onReceivedHttpError(webView, request, errorResponse); - - if (request.isForMainFrame()) { - WritableMap eventData = createWebViewEvent(webView, request.getUrl().toString()); - eventData.putInt("statusCode", errorResponse.getStatusCode()); - eventData.putString("description", errorResponse.getReasonPhrase()); - - ((RNCWebView) webView).dispatchEvent( - webView, - new TopHttpErrorEvent(RNCWebViewContainer.getRNCWebViewId(webView), eventData)); - } - } - - @TargetApi(Build.VERSION_CODES.O) - @Override - public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) { - // WebViewClient.onRenderProcessGone was added in O. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { - return false; - } - super.onRenderProcessGone(webView, detail); - - if(detail.didCrash()){ - Log.e(TAG, "The WebView rendering process crashed."); - } - else{ - Log.w(TAG, "The WebView rendering process was killed by the system."); - } - - // if webView is null, we cannot return any event - // since the view is already dead/disposed - // still prevent the app crash by returning true. - if(webView == null){ - return true; - } - - WritableMap event = createWebViewEvent(webView, webView.getUrl()); - event.putBoolean("didCrash", detail.didCrash()); - - ((RNCWebView) webView).dispatchEvent( - webView, - new TopRenderProcessGoneEvent(RNCWebViewContainer.getRNCWebViewId(webView), event) - ); - - // returning false would crash the app. - return true; - } - - protected void emitFinishEvent(WebView webView, String url) { - ((RNCWebView) webView).dispatchEvent( - webView, - new TopLoadingFinishEvent( - RNCWebViewContainer.getRNCWebViewId(webView), - createWebViewEvent(webView, url))); - } - - protected WritableMap createWebViewEvent(WebView webView, String url) { - WritableMap event = Arguments.createMap(); - event.putDouble("target", RNCWebViewContainer.getRNCWebViewId(webView)); - // Don't use webView.getUrl() here, the URL isn't updated to the new value yet in callbacks - // like onPageFinished - event.putString("url", url); - event.putBoolean("loading", !mLastLoadFailed && webView.getProgress() != 100); - event.putString("title", webView.getTitle()); - event.putBoolean("canGoBack", webView.canGoBack()); - event.putBoolean("canGoForward", webView.canGoForward()); - return event; - } - - public void setUrlPrefixesForDefaultIntent(ReadableArray specialUrls) { - mUrlPrefixesForDefaultIntent = specialUrls; - } - - public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) { - progressChangedFilter = filter; - } - } - - protected static class RNCWebChromeClient extends WebChromeClient implements LifecycleEventListener { - protected static final FrameLayout.LayoutParams FULLSCREEN_LAYOUT_PARAMS = new FrameLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER); - - @RequiresApi(api = Build.VERSION_CODES.KITKAT) - protected static final int FULLSCREEN_SYSTEM_UI_VISIBILITY = View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - - protected static final int COMMON_PERMISSION_REQUEST = 3; - - protected ReactContext mReactContext; - protected View mWebView; - - protected View mVideoView; - protected WebChromeClient.CustomViewCallback mCustomViewCallback; - - /* - * - Permissions - - * As native permissions are asynchronously handled by the PermissionListener, many fields have - * to be stored to send permissions results to the webview - */ - - // Webview camera & audio permission callback - protected PermissionRequest permissionRequest; - // Webview camera & audio permission already granted - protected List grantedPermissions; - - // Webview geolocation permission callback - protected GeolocationPermissions.Callback geolocationPermissionCallback; - // Webview geolocation permission origin callback - protected String geolocationPermissionOrigin; - - // true if native permissions dialog is shown, false otherwise - protected boolean permissionsRequestShown = false; - // Pending Android permissions for the next request - protected List pendingPermissions = new ArrayList<>(); - - protected RNCWebView.ProgressChangedFilter progressChangedFilter = null; - - // True if protected media should be allowed, false otherwise - protected boolean mAllowsProtectedMedia = false; - - public RNCWebChromeClient(ReactContext reactContext, WebView webView) { - this.mReactContext = reactContext; - this.mWebView = webView; - } - - @Override - public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) { - - final WebView newWebView = new WebView(view.getContext()); - final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj; - transport.setWebView(newWebView); - resultMsg.sendToTarget(); - - return true; - } - - @Override - public boolean onConsoleMessage(ConsoleMessage message) { - if (ReactBuildConfig.DEBUG) { - return super.onConsoleMessage(message); - } - // Ignore console logs in non debug builds. - return true; - } - - @Override - public void onProgressChanged(WebView webView, int newProgress) { - super.onProgressChanged(webView, newProgress); - final String url = webView.getUrl(); - if (progressChangedFilter.isWaitingForCommandLoadUrl()) { - return; - } - WritableMap event = Arguments.createMap(); - event.putDouble("target", RNCWebViewContainer.getRNCWebViewId(webView)); - event.putString("title", webView.getTitle()); - event.putString("url", url); - event.putBoolean("canGoBack", webView.canGoBack()); - event.putBoolean("canGoForward", webView.canGoForward()); - event.putDouble("progress", (float) newProgress / 100); - ((RNCWebView) webView).dispatchEvent( - webView, - new TopLoadingProgressEvent( - RNCWebViewContainer.getRNCWebViewId(webView), - event)); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public void onPermissionRequest(final PermissionRequest request) { - - grantedPermissions = new ArrayList<>(); - - ArrayList requestedAndroidPermissions = new ArrayList<>(); - for (String requestedResource : request.getResources()) { - String androidPermission = null; - - if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) { - androidPermission = Manifest.permission.RECORD_AUDIO; - } else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) { - androidPermission = Manifest.permission.CAMERA; - } else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) { - if (mAllowsProtectedMedia) { - grantedPermissions.add(requestedResource); - } else { - /** - * Legacy handling (Kept in case it was working under some conditions (given Android version or something)) - * - * Try to ask user to grant permission using Activity.requestPermissions - * - * Find more details here: https://github.com/react-native-webview/react-native-webview/pull/2732 - */ - androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID; - } - } - // TODO: RESOURCE_MIDI_SYSEX. - - if (androidPermission != null) { - if (ContextCompat.checkSelfPermission(mReactContext, androidPermission) == PackageManager.PERMISSION_GRANTED) { - grantedPermissions.add(requestedResource); - } else { - requestedAndroidPermissions.add(androidPermission); - } - } - } - - // If all the permissions are already granted, send the response to the WebView synchronously - if (requestedAndroidPermissions.isEmpty()) { - request.grant(grantedPermissions.toArray(new String[0])); - grantedPermissions = null; - return; - } - - // Otherwise, ask to Android System for native permissions asynchronously - - this.permissionRequest = request; - - requestPermissions(requestedAndroidPermissions); - } - - - @Override - public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { - - if (ContextCompat.checkSelfPermission(mReactContext, Manifest.permission.ACCESS_FINE_LOCATION) - != PackageManager.PERMISSION_GRANTED) { - - /* - * Keep the trace of callback and origin for the async permission request - */ - geolocationPermissionCallback = callback; - geolocationPermissionOrigin = origin; - - requestPermissions(Collections.singletonList(Manifest.permission.ACCESS_FINE_LOCATION)); - - } else { - callback.invoke(origin, true, false); - } - } - - private PermissionAwareActivity getPermissionAwareActivity() { - Activity activity = mReactContext.getCurrentActivity(); - if (activity == null) { - throw new IllegalStateException("Tried to use permissions API while not attached to an Activity."); - } else if (!(activity instanceof PermissionAwareActivity)) { - throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity."); - } - return (PermissionAwareActivity) activity; - } - - private synchronized void requestPermissions(List permissions) { - - /* - * If permissions request dialog is displayed on the screen and another request is sent to the - * activity, the last permission asked is skipped. As a work-around, we use pendingPermissions - * to store next required permissions. - */ - - if (permissionsRequestShown) { - pendingPermissions.addAll(permissions); - return; - } - - PermissionAwareActivity activity = getPermissionAwareActivity(); - permissionsRequestShown = true; - - activity.requestPermissions( - permissions.toArray(new String[0]), - COMMON_PERMISSION_REQUEST, - webviewPermissionsListener - ); - - // Pending permissions have been sent, the list can be cleared - pendingPermissions.clear(); - } - - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private PermissionListener webviewPermissionsListener = (requestCode, permissions, grantResults) -> { - - permissionsRequestShown = false; - - /* - * As a "pending requests" approach is used, requestCode cannot help to define if the request - * came from geolocation or camera/audio. This is why shouldAnswerToPermissionRequest is used - */ - boolean shouldAnswerToPermissionRequest = false; - - for (int i = 0; i < permissions.length; i++) { - - String permission = permissions[i]; - boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED; - - if (permission.equals(Manifest.permission.ACCESS_FINE_LOCATION) - && geolocationPermissionCallback != null - && geolocationPermissionOrigin != null) { - - if (granted) { - geolocationPermissionCallback.invoke(geolocationPermissionOrigin, true, false); - } else { - geolocationPermissionCallback.invoke(geolocationPermissionOrigin, false, false); - } - - geolocationPermissionCallback = null; - geolocationPermissionOrigin = null; - } - - if (permission.equals(Manifest.permission.RECORD_AUDIO)) { - if (granted && grantedPermissions != null) { - grantedPermissions.add(PermissionRequest.RESOURCE_AUDIO_CAPTURE); - } - shouldAnswerToPermissionRequest = true; - } - - if (permission.equals(Manifest.permission.CAMERA)) { - if (granted && grantedPermissions != null) { - grantedPermissions.add(PermissionRequest.RESOURCE_VIDEO_CAPTURE); - } - shouldAnswerToPermissionRequest = true; - } - - if (permission.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) { - if (granted && grantedPermissions != null) { - grantedPermissions.add(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID); - } - shouldAnswerToPermissionRequest = true; - } - } - - if (shouldAnswerToPermissionRequest - && permissionRequest != null - && grantedPermissions != null) { - permissionRequest.grant(grantedPermissions.toArray(new String[0])); - permissionRequest = null; - grantedPermissions = null; - } - - if (!pendingPermissions.isEmpty()) { - requestPermissions(pendingPermissions); - return false; - } - - return true; - }; - - protected void openFileChooser(ValueCallback filePathCallback, String acceptType) { - getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptType); - } - - protected void openFileChooser(ValueCallback filePathCallback) { - getModule(mReactContext).startPhotoPickerIntent(filePathCallback, ""); - } - - protected void openFileChooser(ValueCallback filePathCallback, String acceptType, String capture) { - getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptType); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, FileChooserParams fileChooserParams) { - String[] acceptTypes = fileChooserParams.getAcceptTypes(); - boolean allowMultiple = fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE; - return getModule(mReactContext).startPhotoPickerIntent(filePathCallback, acceptTypes, allowMultiple); - } - - @Override - public void onHostResume() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && mVideoView != null && mVideoView.getSystemUiVisibility() != FULLSCREEN_SYSTEM_UI_VISIBILITY) { - mVideoView.setSystemUiVisibility(FULLSCREEN_SYSTEM_UI_VISIBILITY); - } - } - - @Override - public void onHostPause() { } - - @Override - public void onHostDestroy() { } - - protected ViewGroup getRootView() { - return (ViewGroup) mReactContext.getCurrentActivity().findViewById(android.R.id.content); - } - - public void setProgressChangedFilter(RNCWebView.ProgressChangedFilter filter) { - progressChangedFilter = filter; - } - - /** - * Set whether or not protected media should be allowed - * /!\ Setting this to false won't revoke permission already granted to the current webpage. - * In order to do so, you'd need to reload the page /!\ - */ - public void setAllowsProtectedMedia(boolean enabled) { - mAllowsProtectedMedia = enabled; - } - } - - /** - * Subclass of {@link WebView} that implements {@link LifecycleEventListener} interface in order - * to call {@link WebView#destroy} on activity destroy event and also to clear the client - */ - protected static class RNCWebView extends WebView implements LifecycleEventListener { - protected @Nullable - String injectedJS; - protected @Nullable - String injectedJSBeforeContentLoaded; - - /** - * android.webkit.WebChromeClient fundamentally does not support JS injection into frames other - * than the main frame, so these two properties are mostly here just for parity with iOS & macOS. - */ - protected boolean injectedJavaScriptForMainFrameOnly = true; - protected boolean injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true; - - protected boolean messagingEnabled = false; - - protected @Nullable - String webViewKey; - - - protected @Nullable - String messagingModuleName; - protected @Nullable - RNCWebViewClient mRNCWebViewClient; - protected @Nullable - CatalystInstance mCatalystInstance; - protected boolean sendContentSizeChangeEvents = false; - private OnScrollDispatchHelper mOnScrollDispatchHelper; - protected boolean hasScrollEvent = false; - protected boolean nestedScrollEnabled = false; - protected ProgressChangedFilter progressChangedFilter; - - protected ReadableMap source; - - /** - * WebView must be created with an context of the current activity - *

- * Activity Context is required for creation of dialogs internally by WebView - * Reactive Native needed for access to ReactNative internal system functionality - */ - public RNCWebView(ThemedReactContext reactContext) { - super(reactContext); - this.createCatalystInstance(); - progressChangedFilter = new ProgressChangedFilter(); - - /** - * Default the background color to transparent to avoid flashing a white frame - * when initializing the WebView. The React CSS background color will get applied - * to the RNCWebView whose background should show behind this transparent background - * until the WebView has non-transparent content. - */ - setBackgroundColor(Color.TRANSPARENT); - } - - public void setIgnoreErrFailedForThisURL(String url) { - mRNCWebViewClient.setIgnoreErrFailedForThisURL(url); - } - - public void setBasicAuthCredential(BasicAuthCredential credential) { - mRNCWebViewClient.setBasicAuthCredential(credential); - } - - public void setWebViewAssetLoader(WebViewAssetLoader webViewAssetLoader) { - mRNCWebViewClient.setWebViewAssetLoader(webViewAssetLoader); - } - - public void setSendContentSizeChangeEvents(boolean sendContentSizeChangeEvents) { - this.sendContentSizeChangeEvents = sendContentSizeChangeEvents; - } - - public void setHasScrollEvent(boolean hasScrollEvent) { - this.hasScrollEvent = hasScrollEvent; - } - - public void setNestedScrollEnabled(boolean nestedScrollEnabled) { - this.nestedScrollEnabled = nestedScrollEnabled; - } - - public void setSource(ReadableMap source) { - this.source = source; - } - - public boolean isNewSource(@Nullable ReadableMap newSource) { - if (source == null || newSource == null) { - return true; - } - - // Check if any of the following string values have changed - String[] sourceKeys = {"uri", "method", "body", "html", "baseUrl"}; - - for (String key : sourceKeys) { - String value = source.getString(key); - String newValue = newSource.getString(key); - if (newValue != null && !newValue.equals(value)) { - return true; - } - } - - // Check if headers changed - ReadableMap headersMap = source.getMap("headers"); - ReadableMap newHeadersMap = newSource.getMap("headers"); - Map headers = headersMap == null ? Collections.emptyMap() : headersMap.toHashMap(); - Map newHeaders = newHeadersMap == null ? Collections.emptyMap() : newHeadersMap.toHashMap(); - - return !headers.equals(newHeaders); - } - - @Override - public void onHostResume() { - // do nothing - } - - @Override - public void onHostPause() { - // do nothing - } - - @Override - public void onHostDestroy() { - cleanupCallbacksAndDestroy(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (this.nestedScrollEnabled) { - requestDisallowInterceptTouchEvent(true); - } - return super.onTouchEvent(event); - } - - @Override - protected void onSizeChanged(int w, int h, int ow, int oh) { - super.onSizeChanged(w, h, ow, oh); - - if (sendContentSizeChangeEvents) { - dispatchEvent( - this, - new ContentSizeChangeEvent( - RNCWebViewContainer.getRNCWebViewId(this), - w, - h - ) - ); - } - } - - @Override - public void setWebViewClient(WebViewClient client) { - super.setWebViewClient(client); - if (client instanceof RNCWebViewClient) { - mRNCWebViewClient = (RNCWebViewClient) client; - mRNCWebViewClient.setProgressChangedFilter(progressChangedFilter); - } - } - - WebChromeClient mWebChromeClient; - @Override - public void setWebChromeClient(WebChromeClient client) { - this.mWebChromeClient = client; - super.setWebChromeClient(client); - if (client instanceof RNCWebChromeClient) { - ((RNCWebChromeClient) client).setProgressChangedFilter(progressChangedFilter); - } - } - - public @Nullable - RNCWebViewClient getRNCWebViewClient() { - return mRNCWebViewClient; - } - - public void setInjectedJavaScript(@Nullable String js) { - injectedJS = js; - } - - public void setInjectedJavaScriptBeforeContentLoaded(@Nullable String js) { - injectedJSBeforeContentLoaded = js; - } - - public void setInjectedJavaScriptForMainFrameOnly(boolean enabled) { - injectedJavaScriptForMainFrameOnly = enabled; - } - - public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(boolean enabled) { - injectedJavaScriptBeforeContentLoadedForMainFrameOnly = enabled; - } - - public void setWebViewKey(String webViewKey) { - this.webViewKey = webViewKey; - } - - protected RNCWebViewBridge createRNCWebViewBridge(RNCWebView webView) { - return new RNCWebViewBridge(webView); - } - - protected void createCatalystInstance() { - ReactContext reactContext = (ReactContext) this.getContext(); - - if (reactContext != null) { - mCatalystInstance = reactContext.getCatalystInstance(); - } - } - - @SuppressLint("AddJavascriptInterface") - public void setMessagingEnabled(boolean enabled) { - if (messagingEnabled == enabled) { - return; - } - - messagingEnabled = enabled; - - if (enabled) { - addJavascriptInterface(createRNCWebViewBridge(this), JAVASCRIPT_INTERFACE); - } else { - removeJavascriptInterface(JAVASCRIPT_INTERFACE); - } - } - - public void setMessagingModuleName(String moduleName) { - messagingModuleName = moduleName; - } - - protected void evaluateJavascriptWithFallback(String script) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - evaluateJavascript(script, null); - return; - } - - try { - loadUrl("javascript:" + URLEncoder.encode(script, "UTF-8")); - } catch (UnsupportedEncodingException e) { - // UTF-8 should always be supported - throw new RuntimeException(e); - } - } - - public void callInjectedJavaScript() { - if (getSettings().getJavaScriptEnabled() && - injectedJS != null && - !TextUtils.isEmpty(injectedJS)) { - evaluateJavascriptWithFallback("(function() {\n" + injectedJS + ";\n})();"); - } - } - - public void callInjectedJavaScriptBeforeContentLoaded() { - if (getSettings().getJavaScriptEnabled() && - injectedJSBeforeContentLoaded != null && - !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { - evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); - } - } - - public void onMessage(String message) { - ReactContext reactContext = (ReactContext) this.getContext(); - RNCWebView mContext = this; - WebView webView = this; - - if (webViewKey != null && mRNCWebViewClient != null) { - reactContext.runOnUiQueueThread(() -> { - WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, webView.getUrl()); - data.putString("webViewKey", webViewKey); - data.putString("data", message); - reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("ReactNativeWebViewOnMessageWithWebViewKey", data); - }); - } else if (mRNCWebViewClient != null) { - webView.post(new Runnable() { - @Override - public void run() { - if (mRNCWebViewClient == null) { - return; - } - WritableMap data = mRNCWebViewClient.createWebViewEvent(webView, webView.getUrl()); - data.putString("data", message); - - if (mCatalystInstance != null) { - mContext.sendDirectMessage("onMessage", data); - } else { - dispatchEvent(webView, new TopMessageEvent(RNCWebViewContainer.getRNCWebViewId(webView), data)); - } - } - }); - } else { - WritableMap eventData = Arguments.createMap(); - eventData.putString("data", message); - - if (mCatalystInstance != null) { - this.sendDirectMessage("onMessage", eventData); - } else { - dispatchEvent(this, new TopMessageEvent(RNCWebViewContainer.getRNCWebViewId(webView), eventData)); - } - } - } - - protected void sendDirectMessage(final String method, WritableMap data) { - WritableNativeMap event = new WritableNativeMap(); - event.putMap("nativeEvent", data); - - WritableNativeArray params = new WritableNativeArray(); - params.pushMap(event); - - mCatalystInstance.callFunction(messagingModuleName, method, params); - } - - protected void onScrollChanged(int x, int y, int oldX, int oldY) { - super.onScrollChanged(x, y, oldX, oldY); - - if (!hasScrollEvent) { - return; - } - - if (mOnScrollDispatchHelper == null) { - mOnScrollDispatchHelper = new OnScrollDispatchHelper(); - } - - if (mOnScrollDispatchHelper.onScrollChanged(x, y)) { - ScrollEvent event = ScrollEvent.obtain( - RNCWebViewContainer.getRNCWebViewId(this), - ScrollEventType.SCROLL, - x, - y, - mOnScrollDispatchHelper.getXFlingVelocity(), - mOnScrollDispatchHelper.getYFlingVelocity(), - this.computeHorizontalScrollRange(), - this.computeVerticalScrollRange(), - this.getWidth(), - this.getHeight()); - - dispatchEvent(this, event); - } - } - - protected void dispatchEvent(WebView webView, Event event) { - if (event.getViewTag() == RNCWebViewContainer.INVALID_VIEW_ID) { - FLog.w(TAG, "Unable to dispatch event: ", event.getEventName() + "due to RNCWebView not being attached."); - return; - } - - ReactContext reactContext = (ReactContext) webView.getContext(); - EventDispatcher eventDispatcher = - reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher(); - eventDispatcher.dispatchEvent(event); - } - - protected void cleanupCallbacksAndDestroy() { - setWebViewClient(null); - destroy(); - } - - @Override - public void destroy() { - if (mWebChromeClient != null) { - mWebChromeClient.onHideCustomView(); - } - super.destroy(); - } - - protected class RNCWebViewBridge { - RNCWebView mContext; - - RNCWebViewBridge(RNCWebView c) { - mContext = c; - } - - /** - * This method is called whenever JavaScript running within the web view calls: - * - window[JAVASCRIPT_INTERFACE].postMessage - */ - @JavascriptInterface - public void postMessage(String message) { - mContext.onMessage(message); - } - } - - protected static class ProgressChangedFilter { - private boolean waitingForCommandLoadUrl = false; - - public void setWaitingForCommandLoadUrl(boolean isWaiting) { - waitingForCommandLoadUrl = isWaiting; - } - - public boolean isWaitingForCommandLoadUrl() { - return waitingForCommandLoadUrl; - } - } - } -} - -class BasicAuthCredential { - String username; - String password; - - BasicAuthCredential(String username, String password) { - this.username = username; - this.password = password; - } -} diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt new file mode 100644 index 0000000000..ab9add3375 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt @@ -0,0 +1,883 @@ +package com.reactnativecommunity.webview + +import android.app.DownloadManager +import android.content.pm.ActivityInfo +import android.graphics.Bitmap +import android.graphics.Color +import android.net.Uri +import android.os.Build +import android.os.Environment +import android.util.Log +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.webkit.CookieManager +import android.webkit.DownloadListener +import android.webkit.WebSettings +import android.webkit.WebView +import androidx.webkit.WebSettingsCompat +import androidx.webkit.WebViewAssetLoader +import androidx.webkit.WebViewFeature +import com.facebook.common.logging.FLog +import com.facebook.react.bridge.ReactContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.common.MapBuilder +import com.facebook.react.common.build.ReactBuildConfig +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerModule +import com.reactnativecommunity.webview.RNCWebViewMapManager.rncWebViewMap +import com.reactnativecommunity.webview.RNCWebViewMapManager.viewIdMap +import org.json.JSONException +import org.json.JSONObject +import java.io.File +import java.io.UnsupportedEncodingException +import java.net.MalformedURLException +import java.net.URL +import java.util.* + + +val invalidCharRegex = "[\\\\/%\"]".toRegex() + +class RNCWebViewManagerImpl { + companion object { + const val NAME = "RNCWebView" + } + + private val TAG = "RNCWebViewManagerImpl" + private var mWebViewConfig: RNCWebViewConfig = RNCWebViewConfig { webView: WebView? -> } + private var mAllowsFullscreenVideo = false + private var mAllowsProtectedMedia = false + private var mDownloadingMessage: String? = null + private var mLackPermissionToDownloadMessage: String? = null + + private var mUserAgent: String? = null + private var mUserAgentWithApplicationName: String? = null + private var assetLoaderHandlerTypes: Set = + HashSet(listOf("assets", "internal", "resources")) + private val HTML_ENCODING = "UTF-8" + private val HTML_MIME_TYPE = "text/html" + private val HTTP_METHOD_POST = "POST" + + // Use `webView.loadUrl("about:blank")` to reliably reset the view + // state and release page resources (including any running JavaScript). + private val BLANK_URL = "about:blank" + + private val DEFAULT_DOWNLOADING_MESSAGE = "Downloading" + private val DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE = + "Cannot download files as permission was denied. Please provide permission to write to storage, in order to download files." + + fun createRNCWebViewInstance(context: ThemedReactContext): RNCWebView { + return RNCWebView(context) + } + + fun createViewInstance(context: ThemedReactContext): RNCWebViewContainer { + val webView = createRNCWebViewInstance(context) + return createViewInstance(context, webView); + } + + fun createViewInstance(context: ThemedReactContext, webView: RNCWebView): RNCWebViewContainer { + val wrapper = RNCWebViewContainer(context) + wrapper.attachWebView(webView) + RNCWebViewMapManager.viewIdMap[webView.id] = wrapper.id + + setupWebChromeClient(webView) + context.addLifecycleEventListener(webView) + mWebViewConfig.configWebView(webView) + val settings = webView.settings + settings.builtInZoomControls = true + settings.displayZoomControls = false + settings.domStorageEnabled = true + settings.setSupportMultipleWindows(true) + settings.allowFileAccess = false + settings.allowContentAccess = false + settings.allowFileAccessFromFileURLs = false + webView.settings.allowUniversalAccessFromFileURLs = false + setMixedContentMode(wrapper, "never") + + // Fixes broken full-screen modals/galleries due to body height being 0. + webView.layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + if (ReactBuildConfig.DEBUG) { + WebView.setWebContentsDebuggingEnabled(true) + } + webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength -> + webView.setIgnoreErrFailedForThisURL(url) + val module = webView.themedReactContext.getNativeModule(RNCWebViewModule::class.java) ?: return@DownloadListener + val request: DownloadManager.Request = try { + DownloadManager.Request(Uri.parse(url)) + } catch (e: IllegalArgumentException) { + Log.w(TAG, "Unsupported URI, aborting download", e) + return@DownloadListener + } + var fileName = URLUtil.guessFileName(url, contentDisposition, mimetype) + + // Sanitize filename by replacing invalid characters with "_" + fileName = fileName.replace(invalidCharRegex, "_") + + val downloadMessage = "Downloading $fileName" + + //Attempt to add cookie, if it exists + var urlObj: URL? = null + try { + urlObj = URL(url) + val baseUrl = urlObj.protocol + "://" + urlObj.host + val cookie = CookieManager.getInstance().getCookie(baseUrl) + request.addRequestHeader("Cookie", cookie) + } catch (e: MalformedURLException) { + Log.w(TAG, "Error getting cookie for DownloadManager", e) + } + + //Finish setting up request + request.addRequestHeader("User-Agent", userAgent) + request.setTitle(fileName) + request.setDescription(downloadMessage) + request.allowScanningByMediaScanner() + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) + request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName) + module.setDownloadRequest(request) + if (module.grantFileDownloaderPermissions( + getDownloadingMessageOrDefault(), + getLackPermissionToDownloadMessageOrDefault() + ) + ) { + module.downloadFile( + getDownloadingMessageOrDefault() + ) + } + }) + return wrapper + } + + private fun setupWebChromeClient( + webView: RNCWebView, + ) { + val activity = webView.themedReactContext.currentActivity + if (mAllowsFullscreenVideo && activity != null) { + val initialRequestedOrientation = activity.requestedOrientation + val webChromeClient: RNCWebChromeClient = + object : RNCWebChromeClient(webView) { + override fun getDefaultVideoPoster(): Bitmap? { + return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888) + } + + override fun onShowCustomView(view: View, callback: CustomViewCallback) { + if (mVideoView != null) { + callback.onCustomViewHidden() + return + } + mVideoView = view + mCustomViewCallback = callback + activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + mVideoView.systemUiVisibility = FULLSCREEN_SYSTEM_UI_VISIBILITY + activity.window.setFlags( + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + ) + mVideoView.setBackgroundColor(Color.BLACK) + + // Since RN's Modals interfere with the View hierarchy + // we will decide which View to hide if the hierarchy + // does not match (i.e., the WebView is within a Modal) + // NOTE: We could use `mWebView.getRootView()` instead of `getRootView()` + // but that breaks the Modal's styles and layout, so we need this to render + // in the main View hierarchy regardless + val rootView = rootView + rootView.addView(mVideoView, FULLSCREEN_LAYOUT_PARAMS) + + // Different root views, we are in a Modal + if (rootView.rootView !== mWebView.rootView) { + mWebView.rootView.visibility = View.GONE + } else { + // Same view hierarchy (no Modal), just hide the WebView then + mWebView.visibility = View.GONE + } + mWebView.themedReactContext.addLifecycleEventListener(this) + } + + override fun onHideCustomView() { + if (mVideoView == null) { + return + } + + // Same logic as above + val rootView = rootView + if (rootView.rootView !== mWebView.rootView) { + mWebView.rootView.visibility = View.VISIBLE + } else { + // Same view hierarchy (no Modal) + mWebView.visibility = View.VISIBLE + } + activity.window.clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) + rootView.removeView(mVideoView) + mCustomViewCallback.onCustomViewHidden() + mVideoView = null + mCustomViewCallback = null + activity.requestedOrientation = initialRequestedOrientation + mWebView.themedReactContext.removeLifecycleEventListener(this) + } + } + webChromeClient.setAllowsProtectedMedia(mAllowsProtectedMedia); + webView.webChromeClient = webChromeClient + } else { + var webChromeClient = webView.webChromeClient as RNCWebChromeClient? + webChromeClient?.onHideCustomView() + webChromeClient = object : RNCWebChromeClient(webView) { + override fun getDefaultVideoPoster(): Bitmap? { + return Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888) + } + } + webChromeClient.setAllowsProtectedMedia(mAllowsProtectedMedia); + webView.webChromeClient = webChromeClient + } + } + + fun setUserAgent(container: RNCWebViewContainer, userAgent: String?) { + container.ifHasRNCWebView { view -> + mUserAgent = userAgent + setUserAgentString(view) + } + } + + fun setApplicationNameForUserAgent(container: RNCWebViewContainer, applicationName: String?) { + container.ifHasRNCWebView { view -> + when { + applicationName != null -> { + val defaultUserAgent = WebSettings.getDefaultUserAgent(view.context) + mUserAgentWithApplicationName = "$defaultUserAgent $applicationName" + } + else -> { + mUserAgentWithApplicationName = null + } + } + setUserAgentString(view) + } + } + + private fun setUserAgentString(view: WebView) { + when { + mUserAgent != null -> { + view.settings.userAgentString = mUserAgent + } + mUserAgentWithApplicationName != null -> { + view.settings.userAgentString = mUserAgentWithApplicationName + } + else -> { + view.settings.userAgentString = WebSettings.getDefaultUserAgent(view.context) + } + } + } + + fun setBasicAuthCredential(container: RNCWebViewContainer, credential: ReadableMap?) { + container.ifHasRNCWebView { view -> + var basicAuthCredential: RNCBasicAuthCredential? = null + if (credential != null) { + if (credential.hasKey("username") && credential.hasKey("password")) { + val username = credential.getString("username") + val password = credential.getString("password") + basicAuthCredential = RNCBasicAuthCredential(username, password) + } + } + view.setBasicAuthCredential(basicAuthCredential) + } + } + + fun onDropViewInstance(view: RNCWebViewContainer) { + + // The internal webview can be null since the view may have been already reattached + if (view.webView == null) { + return + } + + view.ifHasRNCWebView { webView -> + if (webView.webViewKey == null) { + (webView.context as ThemedReactContext).removeLifecycleEventListener(webView) + webView.cleanupCallbacksAndDestroy() + webView.webChromeClient = null + } else { + view.removeWebViewFromParent() + viewIdMap.remove(webView.id) + if (view.temporaryParentNodeTag !== 0) { + // Re-attach the internal webview to the temporary parent. + val uiManagerModule = + (view.context as ReactContext).getNativeModule( + UIManagerModule::class.java + ) + val temporaryParentView = + uiManagerModule!!.resolveView(view.temporaryParentNodeTag) as ViewGroup + temporaryParentView.addView(webView) + + // Resize view to match parent + webView.measure( + View.MeasureSpec.makeMeasureSpec( + temporaryParentView.measuredWidth, + View.MeasureSpec.EXACTLY + ), + View.MeasureSpec.makeMeasureSpec( + temporaryParentView.measuredHeight, + View.MeasureSpec.EXACTLY + ) + ) + webView.layout(0, 0, webView.measuredWidth, webView.measuredHeight) + } + } + } + } + + val COMMAND_GO_BACK = 1 + val COMMAND_GO_FORWARD = 2 + val COMMAND_RELOAD = 3 + val COMMAND_STOP_LOADING = 4 + val COMMAND_POST_MESSAGE = 5 + val COMMAND_INJECT_JAVASCRIPT = 6 + val COMMAND_LOAD_URL = 7 + val COMMAND_FOCUS = 8 + val COMMAND_RELEASE = 9 + + // android commands + val COMMAND_CLEAR_FORM_DATA = 1000 + val COMMAND_CLEAR_CACHE = 1001 + val COMMAND_CLEAR_HISTORY = 1002 + + fun getCommandsMap(): Map? { + return MapBuilder.builder() + .put("goBack", COMMAND_GO_BACK) + .put("goForward", COMMAND_GO_FORWARD) + .put("reload", COMMAND_RELOAD) + .put("stopLoading", COMMAND_STOP_LOADING) + .put("postMessage", COMMAND_POST_MESSAGE) + .put("injectJavaScript", COMMAND_INJECT_JAVASCRIPT) + .put("loadUrl", COMMAND_LOAD_URL) + .put("requestFocus", COMMAND_FOCUS) + .put("clearFormData", COMMAND_CLEAR_FORM_DATA) + .put("clearCache", COMMAND_CLEAR_CACHE) + .put("clearHistory", COMMAND_CLEAR_HISTORY) + .put("release", COMMAND_RELEASE) + .build() + } + + fun receiveCommand(webView: RNCWebView, commandId: String, args: ReadableArray) { + when (commandId) { + "goBack" -> webView.goBack() + "goForward" -> webView.goForward() + "reload" -> webView.reload() + "stopLoading" -> webView.stopLoading() + "postMessage" -> try { + val eventInitDict = JSONObject() + eventInitDict.put("data", args.getString(0)) + webView.evaluateJavascriptWithFallback( + "(function () {" + + "var event;" + + "var data = " + eventInitDict.toString() + ";" + + "try {" + + "event = new MessageEvent('message', data);" + + "} catch (e) {" + + "event = document.createEvent('MessageEvent');" + + "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + + "}" + + "document.dispatchEvent(event);" + + "})();" + ) + } catch (e: JSONException) { + throw RuntimeException(e) + } + "injectJavaScript" -> webView.evaluateJavascriptWithFallback(args.getString(0)) + "loadUrl" -> { + if (args == null) { + throw RuntimeException("Arguments for loading an url are null!") + } + webView.progressChangedFilter.setWaitingForCommandLoadUrl(false) + webView.loadUrl(args.getString(0)) + } + "requestFocus" -> webView.requestFocus() + "clearFormData" -> webView.clearFormData() + "clearCache" -> { + val includeDiskFiles = args != null && args.getBoolean(0) + webView.clearCache(includeDiskFiles) + } + "clearHistory" -> webView.clearHistory() + } + } + + fun setMixedContentMode(container: RNCWebViewContainer, mixedContentMode: String?) { + container.ifHasRNCWebView { view -> + if (mixedContentMode == null || "never" == mixedContentMode) { + view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW + } else if ("always" == mixedContentMode) { + view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW + } else if ("compatibility" == mixedContentMode) { + view.settings.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE + } + } + } + + fun setAllowUniversalAccessFromFileURLs(container: RNCWebViewContainer, allow: Boolean) { + container.ifHasRNCWebView { view -> + view.settings.allowUniversalAccessFromFileURLs = allow + } + } + + private fun getDownloadingMessageOrDefault(): String? { + return mDownloadingMessage ?: DEFAULT_DOWNLOADING_MESSAGE + } + + private fun getLackPermissionToDownloadMessageOrDefault(): String? { + return mLackPermissionToDownloadMessage + ?: DEFAULT_LACK_PERMISSION_TO_DOWNLOAD_MESSAGE + } + + fun setSource(view: RNCWebViewContainer, source: ReadableMap?, newArch: Boolean = true) { + view.ifHasRNCWebView { webView -> + if (source != null) { + if (source.hasKey("html")) { + val html = source.getString("html") + val baseUrl = if (source.hasKey("baseUrl")) source.getString("baseUrl") else "" + webView.loadDataWithBaseURL( + baseUrl, + html!!, + HTML_MIME_TYPE, + HTML_ENCODING, + null + ) + return@ifHasRNCWebView + } + if (source.hasKey("uri")) { + val url = source.getString("uri") + val previousUrl = webView.url + if (previousUrl != null && previousUrl == url) { + return@ifHasRNCWebView + } + if (source.hasKey("method")) { + val method = source.getString("method") + if (method.equals(HTTP_METHOD_POST, ignoreCase = true)) { + var postData: ByteArray? = null + if (source.hasKey("body")) { + val body = source.getString("body") + postData = try { + body!!.toByteArray(charset("UTF-8")) + } catch (e: UnsupportedEncodingException) { + body!!.toByteArray() + } + } + if (postData == null) { + postData = ByteArray(0) + } + webView.postUrl(url!!, postData) + return@ifHasRNCWebView + } + } + val headerMap = HashMap() + if (source.hasKey("headers")) { + if (newArch) { + val headerArray = source.getArray("headers"); + for (header in headerArray!!.toArrayList()) { + val headerCasted = header as HashMap + val name = headerCasted.get("name") ?: "" + val value = headerCasted.get("value") ?: "" + if ("user-agent" == name.lowercase(Locale.ENGLISH)) { + webView.settings.userAgentString = value + } else { + headerMap[name] = value + } + } + } else { + val headers = source.getMap("headers") + val iter = headers!!.keySetIterator() + while (iter.hasNextKey()) { + val key = iter.nextKey() + if ("user-agent" == key.lowercase(Locale.ENGLISH)) { + webView.settings.userAgentString = headers.getString(key) + } else { + headerMap[key] = headers.getString(key) + } + } + } + } + webView.loadUrl(url!!, headerMap) + return@ifHasRNCWebView + } + } + webView.loadUrl(BLANK_URL) + } + } + + fun setMessagingModuleName(view: RNCWebViewContainer, value: String?) { + view.ifHasRNCWebView { webView -> + webView.messagingModuleName = value + } + } + + fun setCacheEnabled(view: RNCWebViewContainer, enabled: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.cacheMode = if (enabled) WebSettings.LOAD_DEFAULT else WebSettings.LOAD_NO_CACHE + } + } + + fun setIncognito(view: RNCWebViewContainer, enabled: Boolean) { + // Don't do anything when incognito is disabled + if (!enabled) { + return; + } + + // Remove all previous cookies + CookieManager.getInstance().removeAllCookies(null); + + view.ifHasRNCWebView { webView -> + // Disable caching + webView.settings.cacheMode = WebSettings.LOAD_NO_CACHE + webView.clearHistory(); + webView.clearCache(true); + + // No form data or autofill enabled + webView.clearFormData(); + webView.settings.savePassword = false; + webView.settings.saveFormData = false; + } + } + + fun setInjectedJavaScript(view: RNCWebViewContainer, injectedJavaScript: String?) { + view.ifHasRNCWebView { webView -> + webView.injectedJS = injectedJavaScript + } + } + + fun setInjectedJavaScriptBeforeContentLoaded(view: RNCWebViewContainer, value: String?) { + view.ifHasRNCWebView { webView -> + webView.injectedJSBeforeContentLoaded = value + } + } + + fun setInjectedJavaScriptForMainFrameOnly(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.injectedJavaScriptForMainFrameOnly = value + } + } + + fun setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.injectedJavaScriptBeforeContentLoadedForMainFrameOnly = value + } + } + + fun setJavaScriptCanOpenWindowsAutomatically(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.javaScriptCanOpenWindowsAutomatically = value + } + } + + fun setShowsVerticalScrollIndicator(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.isVerticalScrollBarEnabled = value + } + } + + fun setShowsHorizontalScrollIndicator(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.isHorizontalScrollBarEnabled = value + } + } + + fun setMessagingEnabled(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.setMessagingEnabled(value) + } + } + + fun setMediaPlaybackRequiresUserAction(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.mediaPlaybackRequiresUserGesture = value + } + } + + fun setHasOnScroll(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.setHasScrollEvent(value) + } + } + + fun setJavaScriptEnabled(view: RNCWebViewContainer, enabled: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.javaScriptEnabled = enabled + } + } + + fun setAllowFileAccess(view: RNCWebViewContainer, allowFileAccess: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.allowFileAccess = allowFileAccess; + } + } + + fun setAllowFileAccessFromFileURLs(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.allowFileAccessFromFileURLs = value; + } + } + + fun setAllowsFullscreenVideo(view: RNCWebViewContainer, value: Boolean) { + mAllowsFullscreenVideo = value + view.ifHasRNCWebView { webView -> + setupWebChromeClient(webView) + } + } + + fun setAndroidLayerType(view: RNCWebViewContainer, layerTypeString: String?) { + view.ifHasRNCWebView { webView -> + val layerType = when (layerTypeString) { + "hardware" -> View.LAYER_TYPE_HARDWARE + "software" -> View.LAYER_TYPE_SOFTWARE + else -> View.LAYER_TYPE_NONE + } + webView.setLayerType(layerType, null) + } + } + + fun setAssetLoaderConfig(view: RNCWebViewContainer, config: ReadableMap?) { + val builder: WebViewAssetLoader.Builder = WebViewAssetLoader.Builder() + + if (config == null) { + return + } + + val domain = config?.getString("domain") + if (domain != null) { + builder.setDomain(domain) + } + + if (config?.hasKey("httpAllowed") == true) { + builder.setHttpAllowed(config.getBoolean("httpAllowed")) + } + + val handlers = config.getArray("pathHandlers") + if (handlers != null && handlers.size() > 0) { + for (i in 0 until handlers.size()) { + val handler: ReadableMap = handlers.getMap(i) + val handlerType = handler.getString("type") + if (handlerType == null) { + FLog.w(TAG, "WebViewAssetLoader error. Path Handler type is null.") + continue + } + if (!assetLoaderHandlerTypes.contains(handlerType)) { + FLog.w( + TAG, + "WebViewAssetLoader error. Skipping Path Handler. Unexpected handler type: $handlerType. Path Handler type must be one of $assetLoaderHandlerTypes" + ) + continue + } + val handlerPath = handler.getString("path") + if (handlerPath == null) { + FLog.w(TAG, "WebViewAssetLoader error. Skipping Path Handler. Handler path is missing") + continue + } + if (handlerType == "resources") { + builder.addPathHandler(handlerPath, WebViewAssetLoader.ResourcesPathHandler(view.context)) + } else if (handlerType == "assets") { + builder.addPathHandler(handlerPath, WebViewAssetLoader.AssetsPathHandler(view.context)) + } else if (handlerType == "internal") { + val directory = handler.getString("directory") + if (directory == null) { + FLog.w( + TAG, + "WebViewAssetLoader error. Skipping Path Handler. Directory is missing for internal handler path" + ) + continue + } + builder.addPathHandler( + handlerPath, + WebViewAssetLoader.InternalStoragePathHandler(view.context, File(directory)) + ) + } + } + } else { + FLog.w(TAG, "WebViewAssetLoader error. No Path Handlers found.") + } + + val assetLoader: WebViewAssetLoader = builder.build() + view.ifHasRNCWebView { webView -> webView.setWebViewAssetLoader(assetLoader) } + } + + fun setTemporaryParentNodeTag(container: RNCWebViewContainer, temporaryParentNodeTag: Int) { + container.temporaryParentNodeTag = temporaryParentNodeTag + } + + fun setCacheMode(view: RNCWebViewContainer, cacheModeString: String?) { + view.ifHasRNCWebView { webView -> + webView.settings.cacheMode = when (cacheModeString) { + "LOAD_CACHE_ONLY" -> WebSettings.LOAD_CACHE_ONLY + "LOAD_CACHE_ELSE_NETWORK" -> WebSettings.LOAD_CACHE_ELSE_NETWORK + "LOAD_NO_CACHE" -> WebSettings.LOAD_NO_CACHE + "LOAD_DEFAULT" -> WebSettings.LOAD_DEFAULT + else -> WebSettings.LOAD_DEFAULT + } + } + } + + fun setDomStorageEnabled(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.domStorageEnabled = value + } + } + + fun setDownloadingMessage(value: String?) { + mDownloadingMessage = value + } + + fun setForceDarkOn(view: RNCWebViewContainer, enabled: Boolean) { + view.ifHasRNCWebView { webView -> + // Only Android 10+ support dark mode + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { + val forceDarkMode = + if (enabled) WebSettingsCompat.FORCE_DARK_ON else WebSettingsCompat.FORCE_DARK_OFF + WebSettingsCompat.setForceDark(webView.settings, forceDarkMode) + } + + // Set how WebView content should be darkened. + // PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING: checks for the "color-scheme" tag. + // If present, it uses media queries. If absent, it applies user-agent (automatic) + // More information about Force Dark Strategy can be found here: + // https://developer.android.com/reference/androidx/webkit/WebSettingsCompat#setForceDarkStrategy(android.webkit.WebSettings) + if (enabled && WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK_STRATEGY)) { + WebSettingsCompat.setForceDarkStrategy( + webView.settings, + WebSettingsCompat.DARK_STRATEGY_PREFER_WEB_THEME_OVER_USER_AGENT_DARKENING + ) + } + } + } + } + + fun setGeolocationEnabled(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.setGeolocationEnabled(value) + } + } + + fun setLackPermissionToDownloadMessage(value: String?) { + mLackPermissionToDownloadMessage = value + } + + fun setMinimumFontSize(view: RNCWebViewContainer, value: Int) { + view.ifHasRNCWebView { webView -> + webView.settings.minimumFontSize = value + } + } + + fun setAllowsProtectedMedia(view: RNCWebViewContainer, enabled: Boolean) { + // This variable is used to keep consistency + // in case a new WebChromeClient is created + // (eg. when mAllowsFullScreenVideo changes) + mAllowsProtectedMedia = enabled + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + view.ifHasRNCWebView { webView -> + val client = webView.webChromeClient + if (client != null && client is RNCWebChromeClient) { + client.setAllowsProtectedMedia(enabled) + } + } + } + } + + fun setMenuCustomItems(view: RNCWebViewContainer, value: ReadableArray) { + view.ifHasRNCWebView { webView -> + webView.setMenuCustomItems(value.toArrayList() as List>) + } + } + + fun setNestedScrollEnabled(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.nestedScrollEnabled = value + } + } + + fun setOverScrollMode(view: RNCWebViewContainer, overScrollModeString: String?) { + view.ifHasRNCWebView { webView -> + webView.overScrollMode = when (overScrollModeString) { + "never" -> View.OVER_SCROLL_NEVER + "content" -> View.OVER_SCROLL_IF_CONTENT_SCROLLS + "always" -> View.OVER_SCROLL_ALWAYS + else -> View.OVER_SCROLL_ALWAYS + } + } + } + + fun setSaveFormDataDisabled(view: RNCWebViewContainer, disabled: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.saveFormData = !disabled + } + } + + fun setScalesPageToFit(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.loadWithOverviewMode = value + webView.settings.useWideViewPort = value + } + } + + fun setSetBuiltInZoomControls(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.builtInZoomControls = value + } + } + + fun setSetDisplayZoomControls(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.displayZoomControls = value + } + } + + fun setSetSupportMultipleWindows(view: RNCWebViewContainer, value: Boolean) { + view.ifHasRNCWebView { webView -> + webView.settings.setSupportMultipleWindows(value) + } + } + + fun setWebViewKey(view: RNCWebViewContainer, webViewKey: String) { + val rncWebViewMap = rncWebViewMap + if (rncWebViewMap.containsKey(webViewKey)) { + val webView = rncWebViewMap[webViewKey] as RNCWebView? + val webViewParent = webView!!.parent as ViewGroup + + // If the RNCWebView is attached to an existing RNCWebViewContainer, first detach + // it from the existing RNCWebViewContainer. + if (webViewParent != null && webViewParent is RNCWebViewContainer) { + val existingRncWebViewContainer = webView.parent as RNCWebViewContainer + existingRncWebViewContainer.detachWebView() + + // The chrome client was originally setup on instance creation but might be pointing to the wrong webview + // so it's reset here. + // Not entirely sure why there is a single instance of the webchrome client for all webviews? + setupWebChromeClient(webView) + } + + // The webview might be attached to the temporary parent; if so, remove it first. + webViewParent?.removeView(webView) + view.attachWebView(webView) + } + + // Update all maps with the view + set/update key + // This means an existing webview can update it's own key + view.ifHasRNCWebView { webView: RNCWebView -> + webView.setWebViewKey(webViewKey) + viewIdMap[webView.id] = view.id + rncWebViewMap[webViewKey] = webView + } + } + + fun setTextZoom(view: RNCWebViewContainer, value: Int) { + view.ifHasRNCWebView { webView -> + webView.settings.textZoom = value + } + } + + fun setThirdPartyCookiesEnabled(view: RNCWebViewContainer, enabled: Boolean) { + view.ifHasRNCWebView { webView -> + CookieManager.getInstance().setAcceptThirdPartyCookies(webView, enabled) + } + } + + fun setWebviewDebuggingEnabled(view: RNCWebViewContainer, enabled: Boolean) { + RNCWebView.setWebContentsDebuggingEnabled(enabled) + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMapManager.kt b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMapManager.kt index b1b20aa0a1..4a11397551 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMapManager.kt +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewMapManager.kt @@ -14,5 +14,5 @@ object RNCWebViewMapManager { // the viewId. See https://reactnative.dev/docs/native-components-android#events // This map facilitates finding the viewId of the wrapper RNCWebView from the WebView // view Id. - val viewIdMap = mutableMapOf(); + val viewIdMap = mutableMapOf(); } diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java deleted file mode 100644 index 1a77e5d797..0000000000 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +++ /dev/null @@ -1,606 +0,0 @@ -package com.reactnativecommunity.webview; - -import android.Manifest; -import android.app.Activity; -import android.app.DownloadManager; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Build; -import android.os.Environment; -import android.os.Parcelable; -import android.provider.MediaStore; - -import androidx.annotation.Nullable; -import androidx.annotation.RequiresApi; -import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; -import androidx.core.util.Pair; - -import android.util.Log; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.webkit.MimeTypeMap; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; -import android.widget.Toast; - -import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.ActivityEventListener; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.modules.core.PermissionAwareActivity; -import com.facebook.react.modules.core.PermissionListener; -import com.facebook.react.uimanager.ThemedReactContext; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.concurrent.atomic.AtomicReference; - -import static android.app.Activity.RESULT_OK; - -@ReactModule(name = RNCWebViewModule.MODULE_NAME) -public class RNCWebViewModule extends ReactContextBaseJavaModule implements ActivityEventListener { - private static final String TAG = "RNCWebViewModule"; - public static final String MODULE_NAME = "RNCWebView"; - private static final int PICKER = 1; - private static final int PICKER_LEGACY = 3; - private static final int FILE_DOWNLOAD_PERMISSION_REQUEST = 1; - private ValueCallback filePathCallbackLegacy; - private ValueCallback filePathCallback; - private File outputImage; - private File outputVideo; - private DownloadManager.Request downloadRequest; - - protected static class ShouldOverrideUrlLoadingLock { - protected enum ShouldOverrideCallbackState { - UNDECIDED, - SHOULD_OVERRIDE, - DO_NOT_OVERRIDE, - } - - private int nextLockIdentifier = 1; - private final HashMap> shouldOverrideLocks = new HashMap<>(); - - public synchronized Pair> getNewLock() { - final int lockIdentifier = nextLockIdentifier++; - final AtomicReference shouldOverride = new AtomicReference<>(ShouldOverrideCallbackState.UNDECIDED); - shouldOverrideLocks.put(lockIdentifier, shouldOverride); - return new Pair<>(lockIdentifier, shouldOverride); - } - - @Nullable - public synchronized AtomicReference getLock(Integer lockIdentifier) { - return shouldOverrideLocks.get(lockIdentifier); - } - - public synchronized void removeLock(Integer lockIdentifier) { - shouldOverrideLocks.remove(lockIdentifier); - } - } - - protected static final ShouldOverrideUrlLoadingLock shouldOverrideUrlLoadingLock = new ShouldOverrideUrlLoadingLock(); - - private enum MimeType { - DEFAULT("*/*"), - IMAGE("image"), - VIDEO("video"); - - private final String value; - - MimeType(String value) { - this.value = value; - } - } - - private PermissionListener getWebviewFileDownloaderPermissionListener(String downloadingMessage, String lackPermissionToDownloadMessage) { - return new PermissionListener() { - @Override - public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - switch (requestCode) { - case FILE_DOWNLOAD_PERMISSION_REQUEST: { - // If request is cancelled, the result arrays are empty. - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - if (downloadRequest != null) { - downloadFile(downloadingMessage); - } - } else { - Toast.makeText(getCurrentActivity().getApplicationContext(), lackPermissionToDownloadMessage, Toast.LENGTH_LONG).show(); - } - return true; - } - } - return false; - } - }; - } - - public RNCWebViewModule(ReactApplicationContext reactContext) { - super(reactContext); - reactContext.addActivityEventListener(this); - } - - @Override - public String getName() { - return MODULE_NAME; - } - - @ReactMethod - public void isFileUploadSupported(final Promise promise) { - Boolean result = false; - int current = Build.VERSION.SDK_INT; - if (current >= Build.VERSION_CODES.LOLLIPOP) { - result = true; - } - if (current >= Build.VERSION_CODES.JELLY_BEAN && current <= Build.VERSION_CODES.JELLY_BEAN_MR2) { - result = true; - } - promise.resolve(result); - } - - @ReactMethod(isBlockingSynchronousMethod = true) - public void onShouldStartLoadWithRequestCallback(final boolean shouldStart, final int lockIdentifier) { - final AtomicReference lockObject = shouldOverrideUrlLoadingLock.getLock(lockIdentifier); - if (lockObject != null) { - synchronized (lockObject) { - lockObject.set(shouldStart ? ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.DO_NOT_OVERRIDE : ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.SHOULD_OVERRIDE); - lockObject.notify(); - } - } - } - - @ReactMethod - public void releaseWebView(final String webViewKey) { - UiThreadUtil.runOnUiThread(() -> { - RNCWebViewManager.RNCWebView webView = (RNCWebViewManager.RNCWebView) RNCWebViewMapManager.INSTANCE.getRncWebViewMap().get(webViewKey); - - if (webView == null) { - FLog.w(TAG, "Failed to release webview with webViewKey: " + webViewKey); - return; - } - - ViewParent webViewParent = webView.getParent(); - - // Detach internal webview from the wrapper RNCWebView - if (webViewParent != null && webViewParent instanceof RNCWebViewContainer) { - RNCWebViewContainer rncWebViewContainer = (RNCWebViewContainer) webViewParent; - RNCWebViewManager.RNCWebView rncWebView = rncWebViewContainer.detachWebView(); - if (rncWebView != webView) { - throw new IllegalStateException("mismatched webview with key: " + webViewKey); - } - } else { - // Remove webview from temporary parent if exists - ViewGroup temporaryParent = (ViewGroup) webView.getParent(); - if (temporaryParent != null) { - temporaryParent.removeView(webView); - } - } - - // Perform webview cleanup - if (webView.webViewKey != null) { - ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener(webView); - webView.cleanupCallbacksAndDestroy(); - } - - RNCWebViewMapManager.INSTANCE.getRncWebViewMap().remove(webViewKey); - }); - } - - @ReactMethod - public void injectJavaScriptWithWebViewKey(final String webViewKey, final String script, final Promise promise) { - UiThreadUtil.runOnUiThread(() -> { - RNCWebViewManager.RNCWebView webView = (RNCWebViewManager.RNCWebView) RNCWebViewMapManager.INSTANCE.getRncWebViewMap().get(webViewKey); - if (webView != null) { - webView.evaluateJavascriptWithFallback(script); - promise.resolve(null); - } else { - promise.reject("err", "Failed to inject javascript with webViewKey: " + webViewKey + ". WebView is null."); - } - }); - } - - public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { - - if (filePathCallback == null && filePathCallbackLegacy == null) { - return; - } - - boolean imageTaken = false; - boolean videoTaken = false; - - if (outputImage != null && outputImage.length() > 0) { - imageTaken = true; - } - if (outputVideo != null && outputVideo.length() > 0) { - videoTaken = true; - } - - // based off of which button was pressed, we get an activity result and a file - // the camera activity doesn't properly return the filename* (I think?) so we use - // this filename instead - switch (requestCode) { - case PICKER: - if (resultCode != RESULT_OK) { - if (filePathCallback != null) { - filePathCallback.onReceiveValue(null); - } - } else { - if (imageTaken) { - filePathCallback.onReceiveValue(new Uri[]{getOutputUri(outputImage)}); - } else if (videoTaken) { - filePathCallback.onReceiveValue(new Uri[]{getOutputUri(outputVideo)}); - } else { - filePathCallback.onReceiveValue(this.getSelectedFiles(data, resultCode)); - } - } - break; - case PICKER_LEGACY: - if (resultCode != RESULT_OK) { - filePathCallbackLegacy.onReceiveValue(null); - } else { - if (imageTaken) { - filePathCallbackLegacy.onReceiveValue(getOutputUri(outputImage)); - } else if (videoTaken) { - filePathCallbackLegacy.onReceiveValue(getOutputUri(outputVideo)); - } else { - filePathCallbackLegacy.onReceiveValue(data.getData()); - } - } - break; - - } - - if (outputImage != null && !imageTaken) { - outputImage.delete(); - } - if (outputVideo != null && !videoTaken) { - outputVideo.delete(); - } - - filePathCallback = null; - filePathCallbackLegacy = null; - outputImage = null; - outputVideo = null; - } - - public void onNewIntent(Intent intent) { - } - - private Uri[] getSelectedFiles(Intent data, int resultCode) { - if (data == null) { - return null; - } - - // we have multiple files selected - if (data.getClipData() != null) { - final int numSelectedFiles = data.getClipData().getItemCount(); - Uri[] result = new Uri[numSelectedFiles]; - for (int i = 0; i < numSelectedFiles; i++) { - result[i] = data.getClipData().getItemAt(i).getUri(); - } - return result; - } - - // we have one file selected - if (data.getData() != null && resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - return WebChromeClient.FileChooserParams.parseResult(resultCode, data); - } - - return null; - } - - public void startPhotoPickerIntent(ValueCallback filePathCallback, String acceptType) { - filePathCallbackLegacy = filePathCallback; - - Intent fileChooserIntent = getFileChooserIntent(acceptType); - Intent chooserIntent = Intent.createChooser(fileChooserIntent, ""); - - ArrayList extraIntents = new ArrayList<>(); - if (acceptsImages(acceptType)) { - Intent photoIntent = getPhotoIntent(); - if (photoIntent != null) { - extraIntents.add(photoIntent); - } - } - if (acceptsVideo(acceptType)) { - Intent videoIntent = getVideoIntent(); - if (videoIntent != null) { - extraIntents.add(videoIntent); - } - } - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); - - if (chooserIntent.resolveActivity(getCurrentActivity().getPackageManager()) != null) { - getCurrentActivity().startActivityForResult(chooserIntent, PICKER_LEGACY); - } else { - Log.w("RNCWebViewModule", "there is no Activity to handle this Intent"); - } - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public boolean startPhotoPickerIntent(final ValueCallback callback, final String[] acceptTypes, final boolean allowMultiple) { - filePathCallback = callback; - - ArrayList extraIntents = new ArrayList<>(); - if (!needsCameraPermission()) { - if (acceptsImages(acceptTypes)) { - Intent photoIntent = getPhotoIntent(); - if (photoIntent != null) { - extraIntents.add(photoIntent); - } - } - if (acceptsVideo(acceptTypes)) { - Intent videoIntent = getVideoIntent(); - if (videoIntent != null) { - extraIntents.add(videoIntent); - } - } - } - - Intent fileSelectionIntent = getFileChooserIntent(acceptTypes, allowMultiple); - - Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); - chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent); - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); - - if (chooserIntent.resolveActivity(getCurrentActivity().getPackageManager()) != null) { - getCurrentActivity().startActivityForResult(chooserIntent, PICKER); - } else { - Log.w("RNCWebViewModule", "there is no Activity to handle this Intent"); - } - - return true; - } - - public void setDownloadRequest(DownloadManager.Request request) { - this.downloadRequest = request; - } - - public void downloadFile(String downloadingMessage) { - DownloadManager dm = (DownloadManager) getCurrentActivity().getBaseContext().getSystemService(Context.DOWNLOAD_SERVICE); - - try { - dm.enqueue(this.downloadRequest); - } catch (IllegalArgumentException e) { - Log.w("RNCWebViewModule", "Unsupported URI, aborting download", e); - return; - } - - Toast.makeText(getCurrentActivity().getApplicationContext(), downloadingMessage, Toast.LENGTH_LONG).show(); - } - - public boolean grantFileDownloaderPermissions(String downloadingMessage, String lackPermissionToDownloadMessage) { - // Permission not required for Android Q and above - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - return true; - } - - boolean result = ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; - if (!result && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - PermissionAwareActivity activity = getPermissionAwareActivity(); - activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, FILE_DOWNLOAD_PERMISSION_REQUEST, getWebviewFileDownloaderPermissionListener(downloadingMessage, lackPermissionToDownloadMessage)); - } - - return result; - } - - protected boolean needsCameraPermission() { - boolean needed = false; - - PackageManager packageManager = getCurrentActivity().getPackageManager(); - try { - String[] requestedPermissions = packageManager.getPackageInfo(getReactApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions; - if (Arrays.asList(requestedPermissions).contains(Manifest.permission.CAMERA) - && ContextCompat.checkSelfPermission(getCurrentActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - needed = true; - } - } catch (PackageManager.NameNotFoundException e) { - needed = true; - } - - return needed; - } - - private Intent getPhotoIntent() { - Intent intent = null; - - try { - outputImage = getCapturedFile(MimeType.IMAGE); - Uri outputImageUri = getOutputUri(outputImage); - intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputImageUri); - } catch (IOException | IllegalArgumentException e) { - Log.e("CREATE FILE", "Error occurred while creating the File", e); - e.printStackTrace(); - } - - return intent; - } - - private Intent getVideoIntent() { - Intent intent = null; - - try { - outputVideo = getCapturedFile(MimeType.VIDEO); - Uri outputVideoUri = getOutputUri(outputVideo); - intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, outputVideoUri); - } catch (IOException | IllegalArgumentException e) { - Log.e("CREATE FILE", "Error occurred while creating the File", e); - e.printStackTrace(); - } - - return intent; - } - - private Intent getFileChooserIntent(String acceptTypes) { - String _acceptTypes = acceptTypes; - if (acceptTypes.isEmpty()) { - _acceptTypes = MimeType.DEFAULT.value; - } - if (acceptTypes.matches("\\.\\w+")) { - _acceptTypes = getMimeTypeFromExtension(acceptTypes.replace(".", "")); - } - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType(_acceptTypes); - return intent; - } - - private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) { - Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setType(MimeType.DEFAULT.value); - intent.putExtra(Intent.EXTRA_MIME_TYPES, getAcceptedMimeType(acceptTypes)); - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple); - return intent; - } - - private Boolean acceptsImages(String types) { - String mimeType = types; - if (types.matches("\\.\\w+")) { - mimeType = getMimeTypeFromExtension(types.replace(".", "")); - } - return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.IMAGE.value); - } - - private Boolean acceptsImages(String[] types) { - String[] mimeTypes = getAcceptedMimeType(types); - return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.IMAGE.value); - } - - private Boolean acceptsVideo(String types) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return false; - } - - String mimeType = types; - if (types.matches("\\.\\w+")) { - mimeType = getMimeTypeFromExtension(types.replace(".", "")); - } - return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.VIDEO.value); - } - - private Boolean acceptsVideo(String[] types) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return false; - } - - String[] mimeTypes = getAcceptedMimeType(types); - return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.VIDEO.value); - } - - private Boolean arrayContainsString(String[] array, String pattern) { - for (String content : array) { - if (content.contains(pattern)) { - return true; - } - } - return false; - } - - private String[] getAcceptedMimeType(String[] types) { - if (noAcceptTypesSet(types)) { - return new String[]{MimeType.DEFAULT.value}; - } - String[] mimeTypes = new String[types.length]; - for (int i = 0; i < types.length; i++) { - String t = types[i]; - // convert file extensions to mime types - if (t.matches("\\.\\w+")) { - String mimeType = getMimeTypeFromExtension(t.replace(".", "")); - if(mimeType != null) { - mimeTypes[i] = mimeType; - } else { - mimeTypes[i] = t; - } - } else { - mimeTypes[i] = t; - } - } - return mimeTypes; - } - - private String getMimeTypeFromExtension(String extension) { - String type = null; - if (extension != null) { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - return type; - } - - private Uri getOutputUri(File capturedFile) { - // for versions below 6.0 (23) we use the old File creation & permissions model - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - return Uri.fromFile(capturedFile); - } - - // for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions - String packageName = getReactApplicationContext().getPackageName(); - return FileProvider.getUriForFile(getReactApplicationContext(), packageName + ".fileprovider", capturedFile); - } - - private File getCapturedFile(MimeType mimeType) throws IOException { - String prefix = ""; - String suffix = ""; - String dir = ""; - - switch (mimeType) { - case IMAGE: - prefix = "image-"; - suffix = ".jpg"; - dir = Environment.DIRECTORY_PICTURES; - break; - case VIDEO: - prefix = "video-"; - suffix = ".mp4"; - dir = Environment.DIRECTORY_MOVIES; - break; - - default: - break; - } - - String filename = prefix + String.valueOf(System.currentTimeMillis()) + suffix; - File outputFile = null; - - // for versions below 6.0 (23) we use the old File creation & permissions model - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - // only this Directory works on all tested Android versions - // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21) - File storageDir = Environment.getExternalStoragePublicDirectory(dir); - outputFile = new File(storageDir, filename); - } else { - File storageDir = getReactApplicationContext().getExternalFilesDir(null); - outputFile = File.createTempFile(prefix, suffix, storageDir); - } - - return outputFile; - } - - private Boolean noAcceptTypesSet(String[] types) { - // when our array returned from getAcceptTypes() has no values set from the webview - // i.e. , without any "accept" attr - // will be an array with one empty string element, afaik - - return types.length == 0 || (types.length == 1 && types[0] != null && types[0].length() == 0); - } - - private PermissionAwareActivity getPermissionAwareActivity() { - Activity activity = getCurrentActivity(); - if (activity == null) { - throw new IllegalStateException("Tried to use permissions API while not attached to an Activity."); - } else if (!(activity instanceof PermissionAwareActivity)) { - throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity."); - } - return (PermissionAwareActivity) activity; - } -} diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java new file mode 100644 index 0000000000..4c4743a372 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModuleImpl.java @@ -0,0 +1,607 @@ +package com.reactnativecommunity.webview; + +import android.Manifest; +import android.app.Activity; +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.Parcelable; +import android.provider.MediaStore; + +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.core.util.Pair; + +import android.util.Log; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.webkit.MimeTypeMap; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.widget.Toast; + +import com.facebook.common.logging.FLog; +import com.facebook.react.bridge.ActivityEventListener; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.UiThreadUtil; +import com.facebook.react.modules.core.PermissionAwareActivity; +import com.facebook.react.modules.core.PermissionListener; +import com.facebook.react.uimanager.ThemedReactContext; + +import java.io.File; +import java.io.IOException; +import java.lang.SecurityException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicReference; + +import static android.app.Activity.RESULT_OK; + +public class RNCWebViewModuleImpl implements ActivityEventListener { + public static final String NAME = "RNCWebView"; + + public static final String TAG = "RNCWebViewModuleImpl"; + + public static final int PICKER = 1; + public static final int PICKER_LEGACY = 3; + public static final int FILE_DOWNLOAD_PERMISSION_REQUEST = 1; + + final private ReactApplicationContext mContext; + + private DownloadManager.Request mDownloadRequest; + + private ValueCallback mFilePathCallbackLegacy; + private ValueCallback mFilePathCallback; + private File mOutputImage; + private File mOutputVideo; + + public RNCWebViewModuleImpl(ReactApplicationContext context) { + mContext = context; + context.addActivityEventListener(this); + } + + @ReactMethod + public void injectJavaScriptWithWebViewKey(final String webViewKey, final String script, final Promise promise) { + UiThreadUtil.runOnUiThread(() -> { + RNCWebView webView = (RNCWebView) RNCWebViewMapManager.INSTANCE.getRncWebViewMap().get(webViewKey); + if (webView != null) { + webView.evaluateJavascriptWithFallback(script); + promise.resolve(null); + } else { + promise.reject("err", "Failed to inject javascript with webViewKey: " + webViewKey + ". WebView is null."); + } + }); + } + + @Override + public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { + if (mFilePathCallback == null && mFilePathCallbackLegacy == null) { + return; + } + + boolean imageTaken = false; + boolean videoTaken = false; + + if (mOutputImage != null && mOutputImage.length() > 0) { + imageTaken = true; + } + if (mOutputVideo != null && mOutputVideo.length() > 0) { + videoTaken = true; + } + + // based off of which button was pressed, we get an activity result and a file + // the camera activity doesn't properly return the filename* (I think?) so we use + // this filename instead + switch (requestCode) { + case RNCWebViewModuleImpl.PICKER: + if (resultCode != RESULT_OK) { + if (mFilePathCallback != null) { + mFilePathCallback.onReceiveValue(null); + } + } else { + if (imageTaken) { + mFilePathCallback.onReceiveValue(new Uri[]{getOutputUri(mOutputImage)}); + } else if (videoTaken) { + mFilePathCallback.onReceiveValue(new Uri[]{getOutputUri(mOutputVideo)}); + } else { + mFilePathCallback.onReceiveValue(getSelectedFiles(data, resultCode)); + } + } + break; + case RNCWebViewModuleImpl.PICKER_LEGACY: + if (resultCode != RESULT_OK) { + mFilePathCallbackLegacy.onReceiveValue(null); + } else { + if (imageTaken) { + mFilePathCallbackLegacy.onReceiveValue(getOutputUri(mOutputImage)); + } else if (videoTaken) { + mFilePathCallbackLegacy.onReceiveValue(getOutputUri(mOutputVideo)); + } else { + mFilePathCallbackLegacy.onReceiveValue(data.getData()); + } + } + break; + + } + + if (mOutputImage != null && !imageTaken) { + mOutputImage.delete(); + } + if (mOutputVideo != null && !videoTaken) { + mOutputVideo.delete(); + } + + mFilePathCallback = null; + mFilePathCallbackLegacy = null; + mOutputImage = null; + mOutputVideo = null; + } + + @Override + public void onNewIntent(Intent intent) { + + } + + protected static class ShouldOverrideUrlLoadingLock { + protected enum ShouldOverrideCallbackState { + UNDECIDED, + SHOULD_OVERRIDE, + DO_NOT_OVERRIDE, + } + + private double nextLockIdentifier = 1; + private final HashMap> shouldOverrideLocks = new HashMap<>(); + + public synchronized Pair> getNewLock() { + final double lockIdentifier = nextLockIdentifier++; + final AtomicReference shouldOverride = new AtomicReference<>(ShouldOverrideCallbackState.UNDECIDED); + shouldOverrideLocks.put(lockIdentifier, shouldOverride); + return new Pair<>(lockIdentifier, shouldOverride); + } + + @Nullable + public synchronized AtomicReference getLock(Double lockIdentifier) { + return shouldOverrideLocks.get(lockIdentifier); + } + + public synchronized void removeLock(Double lockIdentifier) { + shouldOverrideLocks.remove(lockIdentifier); + } + } + + protected static final ShouldOverrideUrlLoadingLock shouldOverrideUrlLoadingLock = new ShouldOverrideUrlLoadingLock(); + + private enum MimeType { + DEFAULT("*/*"), + IMAGE("image"), + VIDEO("video"); + + private final String value; + + MimeType(String value) { + this.value = value; + } + } + + private PermissionListener getWebviewFileDownloaderPermissionListener(String downloadingMessage, String lackPermissionToDownloadMessage) { + return new PermissionListener() { + @Override + public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + switch (requestCode) { + case FILE_DOWNLOAD_PERMISSION_REQUEST: { + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (mDownloadRequest != null) { + downloadFile(downloadingMessage); + } + } else { + Toast.makeText(mContext, lackPermissionToDownloadMessage, Toast.LENGTH_LONG).show(); + } + return true; + } + } + return false; + } + }; + } + + public boolean isFileUploadSupported() { + return true; + } + + @ReactMethod + public void releaseWebView(final String webViewKey) { + UiThreadUtil.runOnUiThread(() -> { + RNCWebView webView = (RNCWebView) RNCWebViewMapManager.INSTANCE.getRncWebViewMap().get(webViewKey); + + if (webView == null) { + FLog.w(TAG, "Failed to release webview with webViewKey: " + webViewKey); + return; + } + + ViewParent webViewParent = webView.getParent(); + + // Detach internal webview from the wrapper RNCWebView + if (webViewParent != null && webViewParent instanceof RNCWebViewContainer) { + RNCWebViewContainer rncWebViewContainer = (RNCWebViewContainer) webViewParent; + RNCWebView rncWebView = rncWebViewContainer.detachWebView(); + if (rncWebView != webView) { + throw new IllegalStateException("mismatched webview with key: " + webViewKey); + } + } else { + // Remove webview from temporary parent if exists + ViewGroup temporaryParent = (ViewGroup) webView.getParent(); + if (temporaryParent != null) { + temporaryParent.removeView(webView); + } + } + + // Perform webview cleanup + if (webView.webViewKey != null) { + ((ThemedReactContext) webView.getContext()).removeLifecycleEventListener(webView); + webView.cleanupCallbacksAndDestroy(); + } + + RNCWebViewMapManager.INSTANCE.getRncWebViewMap().remove(webViewKey); + }); + } + + public void shouldStartLoadWithLockIdentifier(boolean shouldStart, double lockIdentifier) { + final AtomicReference lockObject = shouldOverrideUrlLoadingLock.getLock(lockIdentifier); + if (lockObject != null) { + synchronized (lockObject) { + lockObject.set(shouldStart ? ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.DO_NOT_OVERRIDE : ShouldOverrideUrlLoadingLock.ShouldOverrideCallbackState.SHOULD_OVERRIDE); + lockObject.notify(); + } + } + } + + public Uri[] getSelectedFiles(Intent data, int resultCode) { + if (data == null) { + return null; + } + + // we have multiple files selected + if (data.getClipData() != null) { + final int numSelectedFiles = data.getClipData().getItemCount(); + Uri[] result = new Uri[numSelectedFiles]; + for (int i = 0; i < numSelectedFiles; i++) { + result[i] = data.getClipData().getItemAt(i).getUri(); + } + return result; + } + + // we have one file selected + if (data.getData() != null && resultCode == RESULT_OK && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return WebChromeClient.FileChooserParams.parseResult(resultCode, data); + } + + return null; + } + + public void startPhotoPickerIntent(String acceptType, ValueCallback callback) { + mFilePathCallbackLegacy = callback; + Activity activity = mContext.getCurrentActivity(); + Intent fileChooserIntent = getFileChooserIntent(acceptType); + Intent chooserIntent = Intent.createChooser(fileChooserIntent, ""); + + ArrayList extraIntents = new ArrayList<>(); + if (acceptsImages(acceptType)) { + Intent photoIntent = getPhotoIntent(); + if (photoIntent != null) { + extraIntents.add(photoIntent); + } + } + if (acceptsVideo(acceptType)) { + Intent videoIntent = getVideoIntent(); + if (videoIntent != null) { + extraIntents.add(videoIntent); + } + } + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); + + if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) { + activity.startActivityForResult(chooserIntent, PICKER_LEGACY); + } else { + Log.w("RNCWebViewModule", "there is no Activity to handle this Intent"); + } + } + + public boolean startPhotoPickerIntent(final String[] acceptTypes, final boolean allowMultiple, final ValueCallback callback, final boolean isCaptureEnabled) { + mFilePathCallback = callback; + Activity activity = mContext.getCurrentActivity(); + + ArrayList extraIntents = new ArrayList<>(); + Intent photoIntent = null; + if (!needsCameraPermission()) { + if (acceptsImages(acceptTypes)) { + photoIntent = getPhotoIntent(); + if (photoIntent != null) { + extraIntents.add(photoIntent); + } + } + if (acceptsVideo(acceptTypes)) { + Intent videoIntent = getVideoIntent(); + if (videoIntent != null) { + extraIntents.add(videoIntent); + } + } + } + + Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); + if (isCaptureEnabled) { + chooserIntent = photoIntent; + } else { + Intent fileSelectionIntent = getFileChooserIntent(acceptTypes, allowMultiple); + + chooserIntent.putExtra(Intent.EXTRA_INTENT, fileSelectionIntent); + chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraIntents.toArray(new Parcelable[]{})); + } + + if (chooserIntent != null) { + if (chooserIntent.resolveActivity(activity.getPackageManager()) != null) { + activity.startActivityForResult(chooserIntent, PICKER); + } else { + Log.w("RNCWebViewModule", "there is no Activity to handle this Intent"); + } + } else { + Log.w("RNCWebViewModule", "there is no Camera permission"); + } + + return true; + } + + public void setDownloadRequest(DownloadManager.Request request) { + mDownloadRequest = request; + } + + public void downloadFile(String downloadingMessage) { + DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); + + try { + dm.enqueue(mDownloadRequest); + } catch (IllegalArgumentException | SecurityException e) { + Log.w("RNCWebViewModule", "Unsupported URI, aborting download", e); + return; + } + + Toast.makeText(mContext, downloadingMessage, Toast.LENGTH_LONG).show(); + } + + public boolean grantFileDownloaderPermissions(String downloadingMessage, String lackPermissionToDownloadMessage) { + Activity activity = mContext.getCurrentActivity(); + // Permission not required for Android Q and above + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { + return true; + } + + boolean result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + if (!result && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PermissionAwareActivity PAactivity = getPermissionAwareActivity(); + PAactivity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, FILE_DOWNLOAD_PERMISSION_REQUEST, getWebviewFileDownloaderPermissionListener(downloadingMessage, lackPermissionToDownloadMessage)); + } + + return result; + } + + protected boolean needsCameraPermission() { + Activity activity = mContext.getCurrentActivity(); + boolean needed = false; + + PackageManager packageManager = activity.getPackageManager(); + try { + String[] requestedPermissions = packageManager.getPackageInfo(activity.getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS).requestedPermissions; + if (Arrays.asList(requestedPermissions).contains(Manifest.permission.CAMERA) + && ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + needed = true; + } + } catch (PackageManager.NameNotFoundException e) { + needed = true; + } + + return needed; + } + + public Intent getPhotoIntent() { + Intent intent = null; + + try { + mOutputImage = getCapturedFile(MimeType.IMAGE); + Uri outputImageUri = getOutputUri(mOutputImage); + intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, outputImageUri); + } catch (IOException | IllegalArgumentException e) { + Log.e("CREATE FILE", "Error occurred while creating the File", e); + e.printStackTrace(); + } + + return intent; + } + + public Intent getVideoIntent() { + Intent intent = null; + + try { + mOutputVideo = getCapturedFile(MimeType.VIDEO); + Uri outputVideoUri = getOutputUri(mOutputVideo); + intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, outputVideoUri); + } catch (IOException | IllegalArgumentException e) { + Log.e("CREATE FILE", "Error occurred while creating the File", e); + e.printStackTrace(); + } + + return intent; + } + + private Intent getFileChooserIntent(String acceptTypes) { + String _acceptTypes = acceptTypes; + if (acceptTypes.isEmpty()) { + _acceptTypes = MimeType.DEFAULT.value; + } + if (acceptTypes.matches("\\.\\w+")) { + _acceptTypes = getMimeTypeFromExtension(acceptTypes.replace(".", "")); + } + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType(_acceptTypes); + return intent; + } + + private Intent getFileChooserIntent(String[] acceptTypes, boolean allowMultiple) { + Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType(MimeType.DEFAULT.value); + intent.putExtra(Intent.EXTRA_MIME_TYPES, getAcceptedMimeType(acceptTypes)); + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple); + return intent; + } + + private Boolean acceptsImages(String types) { + String mimeType = types; + if (types.matches("\\.\\w+")) { + mimeType = getMimeTypeFromExtension(types.replace(".", "")); + } + return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.IMAGE.value); + } + + private Boolean acceptsImages(String[] types) { + String[] mimeTypes = getAcceptedMimeType(types); + return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.IMAGE.value); + } + + private Boolean acceptsVideo(String types) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return false; + } + + String mimeType = types; + if (types.matches("\\.\\w+")) { + mimeType = getMimeTypeFromExtension(types.replace(".", "")); + } + return mimeType.isEmpty() || mimeType.toLowerCase().contains(MimeType.VIDEO.value); + } + + private Boolean acceptsVideo(String[] types) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return false; + } + + String[] mimeTypes = getAcceptedMimeType(types); + return arrayContainsString(mimeTypes, MimeType.DEFAULT.value) || arrayContainsString(mimeTypes, MimeType.VIDEO.value); + } + + private Boolean arrayContainsString(String[] array, String pattern) { + for (String content : array) { + if (content.contains(pattern)) { + return true; + } + } + return false; + } + + private String[] getAcceptedMimeType(String[] types) { + if (noAcceptTypesSet(types)) { + return new String[]{MimeType.DEFAULT.value}; + } + String[] mimeTypes = new String[types.length]; + for (int i = 0; i < types.length; i++) { + String t = types[i]; + // convert file extensions to mime types + if (t.matches("\\.\\w+")) { + String mimeType = getMimeTypeFromExtension(t.replace(".", "")); + if(mimeType != null) { + mimeTypes[i] = mimeType; + } else { + mimeTypes[i] = t; + } + } else { + mimeTypes[i] = t; + } + } + return mimeTypes; + } + + private String getMimeTypeFromExtension(String extension) { + String type = null; + if (extension != null) { + type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + } + return type; + } + + public Uri getOutputUri(File capturedFile) { + // for versions below 6.0 (23) we use the old File creation & permissions model + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return Uri.fromFile(capturedFile); + } + + // for versions 6.0+ (23) we use the FileProvider to avoid runtime permissions + String packageName = mContext.getPackageName(); + return FileProvider.getUriForFile(mContext, packageName + ".fileprovider", capturedFile); + } + + public File getCapturedFile(MimeType mimeType) throws IOException { + String prefix = ""; + String suffix = ""; + String dir = ""; + + switch (mimeType) { + case IMAGE: + prefix = "image-"; + suffix = ".jpg"; + dir = Environment.DIRECTORY_PICTURES; + break; + case VIDEO: + prefix = "video-"; + suffix = ".mp4"; + dir = Environment.DIRECTORY_MOVIES; + break; + + default: + break; + } + + String filename = prefix + String.valueOf(System.currentTimeMillis()) + suffix; + File outputFile = null; + + // for versions below 6.0 (23) we use the old File creation & permissions model + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + // only this Directory works on all tested Android versions + // ctx.getExternalFilesDir(dir) was failing on Android 5.0 (sdk 21) + File storageDir = Environment.getExternalStoragePublicDirectory(dir); + outputFile = new File(storageDir, filename); + } else { + File storageDir = mContext.getExternalFilesDir(null); + outputFile = File.createTempFile(prefix, suffix, storageDir); + } + + return outputFile; + } + + private Boolean noAcceptTypesSet(String[] types) { + // when our array returned from getAcceptTypes() has no values set from the webview + // i.e. , without any "accept" attr + // will be an array with one empty string element, afaik + + return types.length == 0 || (types.length == 1 && types[0] != null && types[0].length() == 0); + } + + private PermissionAwareActivity getPermissionAwareActivity() { + Activity activity = mContext.getCurrentActivity(); + if (activity == null) { + throw new IllegalStateException("Tried to use permissions API while not attached to an Activity."); + } else if (!(activity instanceof PermissionAwareActivity)) { + throw new IllegalStateException("Tried to use permissions API but the host Activity doesn't implement PermissionAwareActivity."); + } + return (PermissionAwareActivity) activity; + } +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java new file mode 100644 index 0000000000..24e55ed610 --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java @@ -0,0 +1,56 @@ +package com.reactnativecommunity.webview; + +import androidx.annotation.Nullable; + +import com.facebook.react.TurboReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.uimanager.ViewManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class RNCWebViewPackage extends TurboReactPackage { + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + List viewManagers = new ArrayList<>(); + viewManagers.add(new RNCWebViewManager()); + return viewManagers; + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + RNCWebViewModuleImpl.NAME, + new ReactModuleInfo( + RNCWebViewModuleImpl.NAME, + RNCWebViewModuleImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + return moduleInfos; + }; + } + + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(RNCWebViewModuleImpl.NAME)) { + return new RNCWebViewModule(reactContext); + } else { + return null; + } + } + +} \ No newline at end of file diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt deleted file mode 100644 index 2b74c74aa9..0000000000 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.reactnativecommunity.webview - -import com.facebook.react.ReactPackage -import com.facebook.react.bridge.ReactApplicationContext - - -class RNCWebViewPackage: ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext) = listOf( - RNCWebViewModule(reactContext) - ) - - override fun createViewManagers(reactContext: ReactApplicationContext) = listOf( - RNCWebViewManager() - ) -} diff --git a/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt b/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt new file mode 100644 index 0000000000..47f9f8b12b --- /dev/null +++ b/android/src/main/java/com/reactnativecommunity/webview/events/TopCustomMenuSelectionEvent.kt @@ -0,0 +1,24 @@ +package com.reactnativecommunity.webview.events + +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.RCTEventEmitter + +/** + * Event emitted when there is a loading progress event. + */ +class TopCustomMenuSelectionEvent(viewId: Int, private val mEventData: WritableMap) : + Event(viewId) { + companion object { + const val EVENT_NAME = "topCustomMenuSelection" + } + + override fun getEventName(): String = EVENT_NAME + + override fun canCoalesce(): Boolean = false + + override fun getCoalescingKey(): Short = 0 + + override fun dispatch(rctEventEmitter: RCTEventEmitter) = + rctEventEmitter.receiveEvent(viewTag, eventName, mEventData) +} diff --git a/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java new file mode 100644 index 0000000000..9b0f64db0a --- /dev/null +++ b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -0,0 +1,536 @@ +package com.reactnativecommunity.webview; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.common.MapBuilder; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.SimpleViewManager; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.ViewManagerDelegate; +import com.facebook.react.uimanager.annotations.ReactProp; +import com.facebook.react.viewmanagers.RNCWebViewManagerDelegate; +import com.facebook.react.viewmanagers.RNCWebViewManagerInterface; +import com.facebook.react.views.scroll.ScrollEventType; +import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent; +import com.reactnativecommunity.webview.events.TopHttpErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingFinishEvent; +import com.reactnativecommunity.webview.events.TopLoadingProgressEvent; +import com.reactnativecommunity.webview.events.TopLoadingStartEvent; +import com.reactnativecommunity.webview.events.TopMessageEvent; +import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; +import com.reactnativecommunity.webview.events.TopShouldStartLoadWithRequestEvent; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; + +@ReactModule(name = RNCWebViewManagerImpl.NAME) +public class RNCWebViewManager extends SimpleViewManager + implements RNCWebViewManagerInterface { + + private final ViewManagerDelegate mDelegate; + private final RNCWebViewManagerImpl mRNCWebViewManagerImpl; + + public RNCWebViewManager() { + mDelegate = new RNCWebViewManagerDelegate<>(this); + mRNCWebViewManagerImpl = new RNCWebViewManagerImpl(); + } + + @Nullable + @Override + protected ViewManagerDelegate getDelegate() { + return mDelegate; + } + + @NonNull + @Override + public String getName() { + return RNCWebViewManagerImpl.NAME; + } + + @NonNull + @Override + protected RNCWebView createViewInstance(@NonNull ThemedReactContext context) { + return mRNCWebViewManagerImpl.createViewInstance(context); + } + + @Override + @ReactProp(name = "allowFileAccess") + public void setAllowFileAccess(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowFileAccess(view, value); + } + + @Override + @ReactProp(name = "allowFileAccessFromFileURLs") + public void setAllowFileAccessFromFileURLs(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowFileAccessFromFileURLs(view, value); + + } + + @Override + @ReactProp(name = "allowUniversalAccessFromFileURLs") + public void setAllowUniversalAccessFromFileURLs(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowUniversalAccessFromFileURLs(view, value); + } + + @Override + @ReactProp(name = "allowsFullscreenVideo") + public void setAllowsFullscreenVideo(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowsFullscreenVideo(view, value); + } + + @Override + @ReactProp(name = "allowsProtectedMedia") + public void setAllowsProtectedMedia(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowsProtectedMedia(view, value); + } + + @Override + @ReactProp(name = "androidLayerType") + public void setAndroidLayerType(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setAndroidLayerType(view, value); + } + + @Override + @ReactProp(name = "applicationNameForUserAgent") + public void setApplicationNameForUserAgent(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setApplicationNameForUserAgent(view, value); + } + + @Override + @ReactProp(name = "basicAuthCredential") + public void setBasicAuthCredential(RNCWebViewContainer view, @Nullable ReadableMap value) { + mRNCWebViewManagerImpl.setBasicAuthCredential(view, value); + } + + @Override + @ReactProp(name = "cacheEnabled") + public void setCacheEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setCacheEnabled(view, value); + } + + @Override + @ReactProp(name = "cacheMode") + public void setCacheMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setCacheMode(view, value); + } + + @Override + @ReactProp(name = "domStorageEnabled") + public void setDomStorageEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setDomStorageEnabled(view, value); + } + + @Override + @ReactProp(name = "downloadingMessage") + public void setDownloadingMessage(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setDownloadingMessage(value); + } + + @Override + @ReactProp(name = "forceDarkOn") + public void setForceDarkOn(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setForceDarkOn(view, value); + } + + @Override + @ReactProp(name = "geolocationEnabled") + public void setGeolocationEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setGeolocationEnabled(view, value); + } + + @Override + @ReactProp(name = "hasOnScroll") + public void setHasOnScroll(RNCWebViewContainer view, boolean hasScrollEvent) { + mRNCWebViewManagerImpl.setHasOnScroll(view, hasScrollEvent); + } + + @Override + @ReactProp(name = "incognito") + public void setIncognito(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setIncognito(view, value); + } + + @Override + @ReactProp(name = "injectedJavaScript") + public void setInjectedJavaScript(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setInjectedJavaScript(view, value); + } + + @Override + @ReactProp(name = "injectedJavaScriptBeforeContentLoaded") + public void setInjectedJavaScriptBeforeContentLoaded(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoaded(view, value); + } + + @Override + @ReactProp(name = "injectedJavaScriptForMainFrameOnly") + public void setInjectedJavaScriptForMainFrameOnly(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptForMainFrameOnly(view, value); + + } + + @Override + @ReactProp(name = "injectedJavaScriptBeforeContentLoadedForMainFrameOnly") + public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(view, value); + + } + + @Override + @ReactProp(name = "javaScriptCanOpenWindowsAutomatically") + public void setJavaScriptCanOpenWindowsAutomatically(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setJavaScriptCanOpenWindowsAutomatically(view, value); + } + + @ReactProp(name = "javaScriptEnabled") + public void setJavaScriptEnabled(RNCWebViewContainer view, boolean enabled) { + mRNCWebViewManagerImpl.setJavaScriptEnabled(view, enabled); + } + + @Override + @ReactProp(name = "lackPermissionToDownloadMessage") + public void setLackPermissionToDownloadMessage(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setLackPermissionToDownloadMessage(value); + } + + @Override + @ReactProp(name = "mediaPlaybackRequiresUserAction") + public void setMediaPlaybackRequiresUserAction(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setMediaPlaybackRequiresUserAction(view, value); + } + + @Override + @ReactProp(name = "menuItems") + public void setMenuItems(RNCWebViewContainer view, @Nullable ReadableArray items) { + mRNCWebViewManagerImpl.setMenuCustomItems(view, items); + } + + @Override + @ReactProp(name = "messagingEnabled") + public void setMessagingEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setMessagingEnabled(view, value); + } + + @Override + @ReactProp(name = "messagingModuleName") + public void setMessagingModuleName(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setMessagingModuleName(view, value); + } + + @Override + @ReactProp(name = "minimumFontSize") + public void setMinimumFontSize(RNCWebViewContainer view, int value) { + mRNCWebViewManagerImpl.setMinimumFontSize(view, value); + } + + @Override + @ReactProp(name = "mixedContentMode") + public void setMixedContentMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setMixedContentMode(view, value); + } + + @Override + @ReactProp(name = "nestedScrollEnabled") + public void setNestedScrollEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setNestedScrollEnabled(view, value); + } + + @Override + @ReactProp(name = "overScrollMode") + public void setOverScrollMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setOverScrollMode(view, value); + } + + @Override + @ReactProp(name = "saveFormDataDisabled") + public void setSaveFormDataDisabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSaveFormDataDisabled(view, value); + } + + @Override + @ReactProp(name = "scalesPageToFit") + public void setScalesPageToFit(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setScalesPageToFit(view, value); + } + + @Override + @ReactProp(name = "setBuiltInZoomControls") + public void setSetBuiltInZoomControls(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetBuiltInZoomControls(view, value); + } + + @Override + @ReactProp(name = "setDisplayZoomControls") + public void setSetDisplayZoomControls(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetDisplayZoomControls(view, value); + } + + @Override + @ReactProp(name = "setSupportMultipleWindows") + public void setSetSupportMultipleWindows(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetSupportMultipleWindows(view, value); + } + + @Override + @ReactProp(name = "webViewKey") + public void setWebViewKey(RNCWebViewContainer view, String webViewKey) { + mRNCWebViewManagerImpl.setWebViewKey(view, webViewKey); + } + + @ReactProp(name = "temporaryParentNodeTag") + public void setTemporaryParentNodeTag(RNCWebViewContainer view, int nodeTag) { + mRNCWebViewManagerImpl.setTemporaryParentNodeTag(view, nodeTag); + } + + @Override + @ReactProp(name = "showsHorizontalScrollIndicator") + public void setShowsHorizontalScrollIndicator(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setShowsHorizontalScrollIndicator(view, value); + } + + @Override + @ReactProp(name = "showsVerticalScrollIndicator") + public void setShowsVerticalScrollIndicator(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setShowsVerticalScrollIndicator(view, value); + } + + @Override + @ReactProp(name = "newSource") + public void setNewSource(RNCWebViewContainer view, @Nullable ReadableMap value) { + mRNCWebViewManagerImpl.setSource(view, value, true); + } + + @Override + @ReactProp(name = "textZoom") + public void setTextZoom(RNCWebViewContainer view, int value) { + mRNCWebViewManagerImpl.setTextZoom(view, value); + } + + @Override + @ReactProp(name = "thirdPartyCookiesEnabled") + public void setThirdPartyCookiesEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setThirdPartyCookiesEnabled(view, value); + } + + @Override + @ReactProp(name = "webviewDebuggingEnabled") + public void setWebviewDebuggingEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setWebviewDebuggingEnabled(view, value); + } + + /* iOS PROPS - no implemented here */ + @Override + public void setAllowingReadAccessToURL(RNCWebViewContainer view, @Nullable String value) {} + + @Override + public void setAllowsBackForwardNavigationGestures(RNCWebViewContainer view, boolean value) {} + + @Override + public void setAllowsInlineMediaPlayback(RNCWebViewContainer view, boolean value) {} + + @Override + public void setAllowsAirPlayForMediaPlayback(RNCWebViewContainer view, boolean value) {} + + @Override + public void setAllowsLinkPreview(RNCWebViewContainer view, boolean value) {} + + @Override + public void setAutomaticallyAdjustContentInsets(RNCWebViewContainer view, boolean value) {} + + @Override + public void setAutoManageStatusBarEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setBounces(RNCWebViewContainer view, boolean value) {} + + @Override + public void setContentInset(RNCWebViewContainer view, @Nullable ReadableMap value) {} + + @Override + public void setContentInsetAdjustmentBehavior(RNCWebViewContainer view, @Nullable String value) {} + + @Override + public void setContentMode(RNCWebViewContainer view, @Nullable String value) {} + + @Override + public void setDataDetectorTypes(RNCWebViewContainer view, @Nullable ReadableArray value) {} + + @Override + public void setDecelerationRate(RNCWebViewContainer view, double value) {} + + @Override + public void setDirectionalLockEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setEnableApplePay(RNCWebViewContainer view, boolean value) {} + + @Override + public void setHideKeyboardAccessoryView(RNCWebViewContainer view, boolean value) {} + + @Override + public void setKeyboardDisplayRequiresUserAction(RNCWebViewContainer view, boolean value) {} + + @Override + public void setPagingEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setPullToRefreshEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setScrollEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setSharedCookiesEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setUseSharedProcessPool(RNCWebViewContainer view, boolean value) {} + + @Override + public void setLimitsNavigationsToAppBoundDomains(RNCWebViewContainer view, boolean value) {} + + @Override + public void setTextInteractionEnabled(RNCWebViewContainer view, boolean value) {} + + @Override + public void setHasOnFileDownload(RNCWebViewContainer view, boolean value) {} + + @Override + public void setMediaCapturePermissionGrantType(RNCWebViewContainer view, @Nullable String value) {} + + @Override + public void setFraudulentWebsiteWarningEnabled(RNCWebViewContainer view, boolean value) {} + /* !iOS PROPS - no implemented here */ + + @Override + @ReactProp(name = "userAgent") + public void setUserAgent(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setUserAgent(view, value); + } + + // These will never be called because we use the shared impl for now + @Override + public void goBack(RNCWebView view) { + view.goBack(); + } + + @Override + public void goForward(RNCWebView view) { + view.goForward(); + } + + @Override + public void reload(RNCWebView view) { + view.reload(); + } + + @Override + public void stopLoading(RNCWebView view) { + view.stopLoading(); + } + + @Override + public void injectJavaScript(RNCWebView view, String javascript) { + view.evaluateJavascriptWithFallback(javascript); + } + + @Override + public void requestFocus(RNCWebView view) { + view.requestFocus(); + } + + @Override + public void postMessage(RNCWebView view, String data) { + try { + JSONObject eventInitDict = new JSONObject(); + eventInitDict.put("data", data); + view.evaluateJavascriptWithFallback( + "(function () {" + + "var event;" + + "var data = " + eventInitDict.toString() + ";" + + "try {" + + "event = new MessageEvent('message', data);" + + "} catch (e) {" + + "event = document.createEvent('MessageEvent');" + + "event.initMessageEvent('message', true, true, data.data, data.origin, data.lastEventId, data.source);" + + "}" + + "document.dispatchEvent(event);" + + "})();" + ); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + @Override + public void loadUrl(RNCWebView view, String url) { + view.loadUrl(url); + } + + @Override + public void clearFormData(RNCWebView view) { + view.clearFormData(); + } + + @Override + public void clearCache(RNCWebView view, boolean includeDiskFiles) { + view.clearCache(includeDiskFiles); + } + + @Override + public void clearHistory(RNCWebView view) { + view.clearHistory(); + } + // !These will never be called + + @Override + protected void addEventEmitters(@NonNull ThemedReactContext reactContext, RNCWebView view) { + // Do not register default touch emitter and let WebView implementation handle touches + view.setWebViewClient(new RNCWebViewClient()); + } + + @Override + public Map getExportedCustomDirectEventTypeConstants() { + Map export = super.getExportedCustomDirectEventTypeConstants(); + if (export == null) { + export = MapBuilder.newHashMap(); + } + // Default events but adding them here explicitly for clarity + export.put(TopLoadingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingStart")); + export.put(TopLoadingFinishEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingFinish")); + export.put(TopLoadingErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingError")); + export.put(TopMessageEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMessage")); + // !Default events but adding them here explicitly for clarity + + export.put(TopLoadingProgressEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingProgress")); + export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest")); + export.put(ScrollEventType.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll")); + export.put(TopHttpErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onHttpError")); + export.put(TopRenderProcessGoneEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRenderProcessGone")); + export.put(TopCustomMenuSelectionEvent.EVENT_NAME, MapBuilder.of("registrationName", "onCustomMenuSelection")); + return export; + } + + @Override + public @Nullable + Map getCommandsMap() { + return mRNCWebViewManagerImpl.getCommandsMap(); + } + + @Override + public void receiveCommand(@NonNull RNCWebView reactWebView, String commandId, @Nullable ReadableArray args) { + mRNCWebViewManagerImpl.receiveCommand(reactWebView, commandId, args); + super.receiveCommand(reactWebView, commandId, args); + } + + @Override + public void onDropViewInstance(@NonNull RNCWebView view) { + mRNCWebViewManagerImpl.onDropViewInstance(view); + super.onDropViewInstance(view); + } +} \ No newline at end of file diff --git a/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java new file mode 100644 index 0000000000..95d5e7947b --- /dev/null +++ b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewModule.java @@ -0,0 +1,57 @@ +package com.reactnativecommunity.webview; + +import android.app.DownloadManager; +import android.net.Uri; +import android.webkit.ValueCallback; + +import androidx.annotation.NonNull; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.annotations.ReactModule; + +@ReactModule(name = RNCWebViewModuleImpl.NAME) +public class RNCWebViewModule extends NativeRNCWebViewSpec { + final private RNCWebViewModuleImpl mRNCWebViewModuleImpl; + + public RNCWebViewModule(ReactApplicationContext reactContext) { + super(reactContext); + mRNCWebViewModuleImpl = new RNCWebViewModuleImpl(reactContext); + } + + @Override + public void isFileUploadSupported(final Promise promise) { + promise.resolve(mRNCWebViewModuleImpl.isFileUploadSupported()); + } + + @Override + public void shouldStartLoadWithLockIdentifier(boolean shouldStart, double lockIdentifier) { + mRNCWebViewModuleImpl.shouldStartLoadWithLockIdentifier(shouldStart, lockIdentifier); + } + + public void startPhotoPickerIntent(ValueCallback filePathCallback, String acceptType) { + mRNCWebViewModuleImpl.startPhotoPickerIntent(acceptType, filePathCallback); + } + + public boolean startPhotoPickerIntent(final ValueCallback callback, final String[] acceptTypes, final boolean allowMultiple, final boolean isCaptureEnabled) { + return mRNCWebViewModuleImpl.startPhotoPickerIntent(acceptTypes, allowMultiple, callback, isCaptureEnabled); + } + + public void setDownloadRequest(DownloadManager.Request request) { + mRNCWebViewModuleImpl.setDownloadRequest(request); + } + + public void downloadFile(String downloadingMessage) { + mRNCWebViewModuleImpl.downloadFile(downloadingMessage); + } + + public boolean grantFileDownloaderPermissions(String downloadingMessage, String lackPermissionToDownloadMessage) { + return mRNCWebViewModuleImpl.grantFileDownloaderPermissions(downloadingMessage, lackPermissionToDownloadMessage); + } + + @NonNull + @Override + public String getName() { + return RNCWebViewModuleImpl.NAME; + } +} \ No newline at end of file diff --git a/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java new file mode 100644 index 0000000000..5d219b99f6 --- /dev/null +++ b/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -0,0 +1,335 @@ +package com.reactnativecommunity.webview; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.common.MapBuilder; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.uimanager.SimpleViewManager; +import com.facebook.react.uimanager.ThemedReactContext; +import com.facebook.react.uimanager.annotations.ReactProp; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.views.scroll.ScrollEventType; +import com.reactnativecommunity.webview.events.TopCustomMenuSelectionEvent; +import com.reactnativecommunity.webview.events.TopHttpErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingErrorEvent; +import com.reactnativecommunity.webview.events.TopLoadingFinishEvent; +import com.reactnativecommunity.webview.events.TopLoadingProgressEvent; +import com.reactnativecommunity.webview.events.TopLoadingStartEvent; +import com.reactnativecommunity.webview.events.TopMessageEvent; +import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; +import com.reactnativecommunity.webview.events.TopShouldStartLoadWithRequestEvent; + +import android.graphics.Color; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Map; +import java.util.HashMap; + +public class RNCWebViewManager extends SimpleViewManager { + + private final RNCWebViewManagerImpl mRNCWebViewManagerImpl; + + public RNCWebViewManager() { + mRNCWebViewManagerImpl = new RNCWebViewManagerImpl(); + } + + @Override + public String getName() { + return RNCWebViewManagerImpl.NAME; + } + + @Override + public RNCWebViewContainer createViewInstance(ThemedReactContext context) { + return mRNCWebViewManagerImpl.createViewInstance(context); + } + + public RNCWebViewContainer createViewInstance(ThemedReactContext context, RNCWebView webView) { + return mRNCWebViewManagerImpl.createViewInstance(context, webView); + } + + @ReactProp(name = "allowFileAccess") + public void setAllowFileAccess(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowFileAccess(view, value); + } + + @ReactProp(name = "allowFileAccessFromFileURLs") + public void setAllowFileAccessFromFileURLs(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowFileAccessFromFileURLs(view, value); + + } + + @ReactProp(name = "allowUniversalAccessFromFileURLs") + public void setAllowUniversalAccessFromFileURLs(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowUniversalAccessFromFileURLs(view, value); + } + + @ReactProp(name = "allowsFullscreenVideo") + public void setAllowsFullscreenVideo(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowsFullscreenVideo(view, value); + } + + @ReactProp(name = "allowsProtectedMedia") + public void setAllowsProtectedMedia(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setAllowsProtectedMedia(view, value); + } + + @ReactProp(name = "androidLayerType") + public void setAndroidLayerType(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setAndroidLayerType(view, value); + } + + @ReactProp(name = "androidAssetLoaderConfig") + public void setAndroidAssetLoaderConfig(RNCWebViewContainer view, @Nullable ReadableMap config) { + mRNCWebViewManagerImpl.setAssetLoaderConfig(view, config); + } + + @ReactProp(name = "temporaryParentNodeTag") + public void setTemporaryParentNodeTag(RNCWebViewContainer view, int nodeTag) { + mRNCWebViewManagerImpl.setTemporaryParentNodeTag(view, nodeTag); + } + + @ReactProp(name = "applicationNameForUserAgent") + public void setApplicationNameForUserAgent(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setApplicationNameForUserAgent(view, value); + } + + @ReactProp(name = "basicAuthCredential") + public void setBasicAuthCredential(RNCWebViewContainer view, @Nullable ReadableMap value) { + mRNCWebViewManagerImpl.setBasicAuthCredential(view, value); + } + + @ReactProp(name = "cacheEnabled") + public void setCacheEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setCacheEnabled(view, value); + } + + @ReactProp(name = "cacheMode") + public void setCacheMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setCacheMode(view, value); + } + + @ReactProp(name = "domStorageEnabled") + public void setDomStorageEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setDomStorageEnabled(view, value); + } + + @ReactProp(name = "downloadingMessage") + public void setDownloadingMessage(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setDownloadingMessage(value); + } + + @ReactProp(name = "forceDarkOn") + public void setForceDarkOn(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setForceDarkOn(view, value); + } + + @ReactProp(name = "geolocationEnabled") + public void setGeolocationEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setGeolocationEnabled(view, value); + } + + @ReactProp(name = "hasOnScroll") + public void setHasOnScroll(RNCWebViewContainer view, boolean hasScrollEvent) { + mRNCWebViewManagerImpl.setHasOnScroll(view, hasScrollEvent); + } + + @ReactProp(name = "incognito") + public void setIncognito(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setIncognito(view, value); + } + + @ReactProp(name = "injectedJavaScript") + public void setInjectedJavaScript(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setInjectedJavaScript(view, value); + } + + @ReactProp(name = "injectedJavaScriptBeforeContentLoaded") + public void setInjectedJavaScriptBeforeContentLoaded(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoaded(view, value); + } + + @ReactProp(name = "injectedJavaScriptForMainFrameOnly") + public void setInjectedJavaScriptForMainFrameOnly(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptForMainFrameOnly(view, value); + + } + + @ReactProp(name = "injectedJavaScriptBeforeContentLoadedForMainFrameOnly") + public void setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoadedForMainFrameOnly(view, value); + + } + + @ReactProp(name = "javaScriptCanOpenWindowsAutomatically") + public void setJavaScriptCanOpenWindowsAutomatically(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setJavaScriptCanOpenWindowsAutomatically(view, value); + } + + @ReactProp(name = "javaScriptEnabled") + public void setJavaScriptEnabled(RNCWebViewContainer view, boolean enabled) { + mRNCWebViewManagerImpl.setJavaScriptEnabled(view, enabled); + } + + @ReactProp(name = "lackPermissionToDownloadMessage") + public void setLackPermissionToDownloadMessage(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setLackPermissionToDownloadMessage(value); + } + + @ReactProp(name = "mediaPlaybackRequiresUserAction") + public void setMediaPlaybackRequiresUserAction(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setMediaPlaybackRequiresUserAction(view, value); + } + + @ReactProp(name = "messagingEnabled") + public void setMessagingEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setMessagingEnabled(view, value); + } + + @ReactProp(name = "menuItems") + public void setMenuCustomItems(RNCWebViewContainer view, @Nullable ReadableArray items) { + mRNCWebViewManagerImpl.setMenuCustomItems(view, items); + } + + @ReactProp(name = "messagingModuleName") + public void setMessagingModuleName(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setMessagingModuleName(view, value); + } + + @ReactProp(name = "minimumFontSize") + public void setMinimumFontSize(RNCWebViewContainer view, int value) { + mRNCWebViewManagerImpl.setMinimumFontSize(view, value); + } + + @ReactProp(name = "mixedContentMode") + public void setMixedContentMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setMixedContentMode(view, value); + } + + @ReactProp(name = "nestedScrollEnabled") + public void setNestedScrollEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setNestedScrollEnabled(view, value); + } + + @ReactProp(name = "overScrollMode") + public void setOverScrollMode(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setOverScrollMode(view, value); + } + + @ReactProp(name = "saveFormDataDisabled") + public void setSaveFormDataDisabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSaveFormDataDisabled(view, value); + } + + @ReactProp(name = "scalesPageToFit") + public void setScalesPageToFit(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setScalesPageToFit(view, value); + } + + @ReactProp(name = "setBuiltInZoomControls") + public void setSetBuiltInZoomControls(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetBuiltInZoomControls(view, value); + } + + @ReactProp(name = "setDisplayZoomControls") + public void setSetDisplayZoomControls(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetDisplayZoomControls(view, value); + } + + @ReactProp(name = "setSupportMultipleWindows") + public void setSetSupportMultipleWindows(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setSetSupportMultipleWindows(view, value); + } + + @ReactProp(name = "showsHorizontalScrollIndicator") + public void setShowsHorizontalScrollIndicator(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setShowsHorizontalScrollIndicator(view, value); + } + + @ReactProp(name = "showsVerticalScrollIndicator") + public void setShowsVerticalScrollIndicator(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setShowsVerticalScrollIndicator(view, value); + } + + @ReactProp(name = "source") + public void setSource(RNCWebViewContainer view, @Nullable ReadableMap value) { + mRNCWebViewManagerImpl.setSource(view, value, false); + } + + @ReactProp(name = "textZoom") + public void setTextZoom(RNCWebViewContainer view, int value) { + mRNCWebViewManagerImpl.setTextZoom(view, value); + } + + @ReactProp(name = "thirdPartyCookiesEnabled") + public void setThirdPartyCookiesEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setThirdPartyCookiesEnabled(view, value); + } + + @ReactProp(name = "webviewDebuggingEnabled") + public void setWebviewDebuggingEnabled(RNCWebViewContainer view, boolean value) { + mRNCWebViewManagerImpl.setWebviewDebuggingEnabled(view, value); + } + + @ReactProp(name = "userAgent") + public void setUserAgent(RNCWebViewContainer view, @Nullable String value) { + mRNCWebViewManagerImpl.setUserAgent(view, value); + } + + @Override + protected void addEventEmitters( + @NonNull ThemedReactContext reactContext, + RNCWebViewContainer container + ) { + container.ifHasRNCWebView(view -> { + // Do not register default touch emitter and let WebView implementation handle touches + view.setWebViewClient(new RNCWebViewClient()); + }); + } + + @Override + public Map getExportedCustomDirectEventTypeConstants() { + Map export = super.getExportedCustomDirectEventTypeConstants(); + if (export == null) { + export = MapBuilder.newHashMap(); + } + // Default events but adding them here explicitly for clarity + export.put(TopLoadingStartEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingStart")); + export.put(TopLoadingFinishEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingFinish")); + export.put(TopLoadingErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingError")); + export.put(TopMessageEvent.EVENT_NAME, MapBuilder.of("registrationName", "onMessage")); + // !Default events but adding them here explicitly for clarity + + export.put(TopLoadingProgressEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingProgress")); + export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest")); + export.put(ScrollEventType.getJSEventName(ScrollEventType.SCROLL), MapBuilder.of("registrationName", "onScroll")); + export.put(TopHttpErrorEvent.EVENT_NAME, MapBuilder.of("registrationName", "onHttpError")); + export.put(TopRenderProcessGoneEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRenderProcessGone")); + export.put(TopCustomMenuSelectionEvent.EVENT_NAME, MapBuilder.of("registrationName", "onCustomMenuSelection")); + return export; + } + + @Override + public @Nullable + Map getCommandsMap() { + return mRNCWebViewManagerImpl.getCommandsMap(); + } + + @Override + public void receiveCommand(@NonNull RNCWebViewContainer reactWebViewContainer, String commandId, @Nullable ReadableArray args) { + reactWebViewContainer.ifHasRNCWebView(webView -> { + mRNCWebViewManagerImpl.receiveCommand(webView, commandId, args); + super.receiveCommand(reactWebViewContainer, commandId, args); + }); + } + + @Override + public void onDropViewInstance(@NonNull RNCWebViewContainer view) { + mRNCWebViewManagerImpl.onDropViewInstance(view); + super.onDropViewInstance(view); + } +} \ No newline at end of file diff --git a/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java b/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java new file mode 100644 index 0000000000..526cc1633c --- /dev/null +++ b/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewModule.java @@ -0,0 +1,59 @@ +package com.reactnativecommunity.webview; + +import android.app.DownloadManager; +import android.net.Uri; + +import androidx.annotation.NonNull; +import android.webkit.ValueCallback; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; + +@ReactModule(name = RNCWebViewModuleImpl.NAME) +public class RNCWebViewModule extends ReactContextBaseJavaModule { + final private RNCWebViewModuleImpl mRNCWebViewModuleImpl; + + public RNCWebViewModule(ReactApplicationContext reactContext) { + super(reactContext); + mRNCWebViewModuleImpl = new RNCWebViewModuleImpl(reactContext); + } + + @ReactMethod + public void isFileUploadSupported(final Promise promise) { + promise.resolve(mRNCWebViewModuleImpl.isFileUploadSupported()); + } + + @ReactMethod + public void shouldStartLoadWithLockIdentifier(boolean shouldStart, double lockIdentifier) { + mRNCWebViewModuleImpl.shouldStartLoadWithLockIdentifier(shouldStart, lockIdentifier); + } + + public void startPhotoPickerIntent(ValueCallback filePathCallback, String acceptType) { + mRNCWebViewModuleImpl.startPhotoPickerIntent(acceptType, filePathCallback); + } + + public boolean startPhotoPickerIntent(final ValueCallback callback, final String[] acceptTypes, final boolean allowMultiple, final boolean isCaptureEnabled) { + return mRNCWebViewModuleImpl.startPhotoPickerIntent(acceptTypes, allowMultiple, callback, isCaptureEnabled); + } + + public void setDownloadRequest(DownloadManager.Request request) { + mRNCWebViewModuleImpl.setDownloadRequest(request); + } + + public void downloadFile(String downloadingMessage) { + mRNCWebViewModuleImpl.downloadFile(downloadingMessage); + } + + public boolean grantFileDownloaderPermissions(String downloadingMessage, String lackPermissionToDownloadMessage) { + return mRNCWebViewModuleImpl.grantFileDownloaderPermissions(downloadingMessage, lackPermissionToDownloadMessage); + } + + @NonNull + @Override + public String getName() { + return RNCWebViewModuleImpl.NAME; + } +} \ No newline at end of file diff --git a/apple/RNCScriptMessageManager.m b/apple/RNCScriptMessageManager.m index cf3364e73c..e3cd72ebdc 100644 --- a/apple/RNCScriptMessageManager.m +++ b/apple/RNCScriptMessageManager.m @@ -1,8 +1,11 @@ #import #import "RNCScriptMessageManager.h" #import "ScriptMessageEventEmitter.h" -#import "RNCWebView.h" +#import "RNCWebViewImpl.h" #import "RNCWKWebViewMapManager.h" +#import +#import +#import @implementation RNCScriptMessageHandler @@ -18,8 +21,9 @@ - (instancetype)initWithName:(NSString *)name withWebViewKey:(NSString *)webView - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { WKWebView *webView = [[RNCWKWebViewMapManager sharedManager] sharedWKWebViewDictionary][_webViewKey]; if (webView != nil) { - NSMutableDictionary *event = [RNCWebView createEventFromMessage:message withMessageBodyKey:kMessageHandlerBodyKey withWebView:webView]; + NSMutableDictionary *event = [RNCWebViewImpl createEventFromMessage:message withMessageBodyKey:kMessageHandlerBodyKey withWebView:webView]; event[@"webViewKey"] = _webViewKey; + [[NSNotificationCenter defaultCenter] postNotificationName:kScriptMessageNotificationName object:self userInfo:event]; } } diff --git a/apple/RNCWebView.h b/apple/RNCWebView.h index 32f31df56a..d359365e0f 100644 --- a/apple/RNCWebView.h +++ b/apple/RNCWebView.h @@ -1,128 +1,29 @@ -/** - * Copyright (c) 2015-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. - */ +// This guard prevent this file to be compiled in the old architecture. +#ifdef RCT_NEW_ARCH_ENABLED +#import +#import +#import +#import +#import -#import -#import -#import +#ifndef NativeComponentExampleComponentView_h +#define NativeComponentExampleComponentView_h -typedef enum RNCWebViewPermissionGrantType : NSUInteger { - RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt, - RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny, - RNCWebViewPermissionGrantType_Deny, - RNCWebViewPermissionGrantType_Grant, - RNCWebViewPermissionGrantType_Prompt -} RNCWebViewPermissionGrantType; - -@class RNCWebView; -@class RCTBridge; - -@protocol RNCWebViewDelegate - -- (BOOL)webView:(RNCWebView *_Nonnull)webView -shouldStartLoadForRequest:(NSMutableDictionary *_Nonnull)request - withCallback:(RCTDirectEventBlock _Nonnull)callback; - -@end - -@interface RNCWeakScriptMessageDelegate : NSObject - -@property (nonatomic, weak, nullable) id scriptDelegate; - -- (nullable instancetype)initWithDelegate:(id _Nullable)scriptDelegate; +NS_ASSUME_NONNULL_BEGIN +@interface RNCWebView : RCTViewComponentView @end -@interface RNCWebView : RCTView +namespace facebook { +namespace react { + bool operator==(const RNCWebViewMenuItemsStruct& a, const RNCWebViewMenuItemsStruct& b) + { + return b.key == a.key && b.label == a.label; + } +} +} -@property (nonatomic, weak) id _Nullable delegate; -@property (nonatomic, weak) RCTBridge * _Nullable bridge; -@property (nonatomic, copy) NSDictionary * _Nullable source; -@property (nonatomic, assign) BOOL messagingEnabled; -@property (nonatomic, copy) NSString * _Nullable injectedJavaScript; -@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded; -@property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly; -@property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly; -@property (nonatomic, assign) BOOL scrollEnabled; -@property (nonatomic, assign) BOOL sharedCookiesEnabled; -@property (nonatomic, assign) BOOL autoManageStatusBarEnabled; -@property (nonatomic, assign) BOOL pagingEnabled; -@property (nonatomic, assign) CGFloat decelerationRate; -@property (nonatomic, assign) BOOL allowsInlineMediaPlayback; -@property (nonatomic, assign) BOOL allowsAirPlayForMediaPlayback; -@property (nonatomic, assign) BOOL bounces; -@property (nonatomic, assign) BOOL mediaPlaybackRequiresUserAction; -#if WEBKIT_IOS_10_APIS_AVAILABLE -@property (nonatomic, assign) WKDataDetectorTypes dataDetectorTypes; -#endif -@property (nonatomic, assign) UIEdgeInsets contentInset; -@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets; -@property (nonatomic, assign) BOOL keyboardDisplayRequiresUserAction; -@property (nonatomic, assign) BOOL hideKeyboardAccessoryView; -@property (nonatomic, assign) BOOL allowsBackForwardNavigationGestures; -@property (nonatomic, assign) BOOL incognito; -@property (nonatomic, assign) BOOL useSharedProcessPool; -@property (nonatomic, copy) NSString * _Nullable userAgent; -@property (nonatomic, copy) NSString * _Nullable applicationNameForUserAgent; -@property (nonatomic, assign) BOOL cacheEnabled; -@property (nonatomic, assign) BOOL javaScriptEnabled; -@property (nonatomic, assign) BOOL javaScriptCanOpenWindowsAutomatically; -@property (nonatomic, assign) BOOL allowFileAccessFromFileURLs; -@property (nonatomic, assign) BOOL allowUniversalAccessFromFileURLs; -@property (nonatomic, assign) BOOL allowsLinkPreview; -@property (nonatomic, assign) BOOL showsHorizontalScrollIndicator; -@property (nonatomic, assign) BOOL showsVerticalScrollIndicator; -@property (nonatomic, assign) BOOL directionalLockEnabled; -@property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch; -@property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL; -@property (nonatomic, copy) NSDictionary * _Nullable basicAuthCredential; -@property (nonatomic, assign) BOOL pullToRefreshEnabled; -@property (nonatomic, assign) BOOL enableApplePay; -@property (nonatomic, copy) NSArray * _Nullable menuItems; -@property (nonatomic, copy) RCTDirectEventBlock onCustomMenuSelection; -#if !TARGET_OS_OSX -@property (nonatomic, weak) UIRefreshControl * _Nullable refreshControl; -#endif +NS_ASSUME_NONNULL_END -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ -@property (nonatomic, assign) WKContentMode contentMode; -#endif - -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 /* iOS 14 */ -@property (nonatomic, assign) BOOL limitsNavigationsToAppBoundDomains; -#endif - -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* iOS 14.5 */ -@property (nonatomic, assign) BOOL textInteractionEnabled; -#endif - -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */ -@property (nonatomic, assign) RNCWebViewPermissionGrantType mediaCapturePermissionGrantType; -#endif - -@property (nonatomic, copy) NSString * _Nullable webViewKey; -@property (nonatomic, copy) NSNumber * _Nullable temporaryParentNodeTag; - -+ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential; -+ (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates; -+ (NSMutableDictionary *)baseEventWithWebView: (WKWebView *)webView; -+ (NSMutableDictionary*)createEventFromMessage:(WKScriptMessage *_Nonnull)message withMessageBodyKey: (NSString *_Nonnull)messageBodyKey withWebView: (WKWebView *)webView; -- (void)postMessage:(NSString *_Nullable)message; -- (void)injectJavaScript:(NSString *_Nullable)script; -- (void)goForward; -- (void)goBack; -- (void)reload; -- (void)stopLoading; -- (void)requestFocus; -- (void)releaseWebView; -- (void)cleanUpWebView; -#if !TARGET_OS_OSX -- (void)addPullToRefreshControl; -- (void)pullToRefresh:(UIRefreshControl *_Nonnull)refreshControl; -- (void)cleanUpWebView; -#endif - -@end +#endif /* NativeComponentExampleComponentView_h */ +#endif /* RCT_NEW_ARCH_ENABLED */ diff --git a/apple/RNCWebView.mm b/apple/RNCWebView.mm new file mode 100644 index 0000000000..bf703bf130 --- /dev/null +++ b/apple/RNCWebView.mm @@ -0,0 +1,506 @@ +// This guard prevent the code from being compiled in the old architecture +#ifdef RCT_NEW_ARCH_ENABLED +#import "RNCWebView.h" +#import "RNCWebViewImpl.h" + +#import +#import +#import +#import + +#import "RCTFabricComponentsPlugins.h" + +using namespace facebook::react; + +auto stringToOnShouldStartLoadWithRequestNavigationTypeEnum(std::string value) { + if (value == "click") return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Click; + if (value == "formsubmit") return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Formsubmit; + if (value == "backforward") return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Backforward; + if (value == "reload") return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Reload; + if (value == "formresubmit") return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Formresubmit; + return RNCWebViewEventEmitter::OnShouldStartLoadWithRequestNavigationType::Other; +} + +auto stringToOnLoadingStartNavigationTypeEnum(std::string value) { + if (value == "click") return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Click; + if (value == "formsubmit") return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Formsubmit; + if (value == "backforward") return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Backforward; + if (value == "reload") return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Reload; + if (value == "formresubmit") return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Formresubmit; + return RNCWebViewEventEmitter::OnLoadingStartNavigationType::Other; +} + +auto stringToOnLoadingFinishNavigationTypeEnum(std::string value) { + if (value == "click") return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Click; + if (value == "formsubmit") return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Formsubmit; + if (value == "backforward") return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Backforward; + if (value == "reload") return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Reload; + if (value == "formresubmit") return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Formresubmit; + return RNCWebViewEventEmitter::OnLoadingFinishNavigationType::Other; +} + +@interface RNCWebView () + +@end + +@implementation RNCWebView { + RNCWebViewImpl * _view; +} + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +// Reproduce the idea from here: https://github.com/facebook/react-native/blob/8bd3edec88148d0ab1f225d2119435681fbbba33/React/Fabric/Mounting/ComponentViews/InputAccessory/RCTInputAccessoryComponentView.mm#L142 +- (void)prepareForRecycle { + [super prepareForRecycle]; + [_view destroyWebView]; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + + _view = [[RNCWebViewImpl alloc] init]; + + _view.onShouldStartLoadWithRequest = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnShouldStartLoadWithRequest data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .navigationType = stringToOnShouldStartLoadWithRequestNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String])), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .isTopFrame = [[dictionary valueForKey:@"isTopFrame"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String]) + }; + webViewEventEmitter->onShouldStartLoadWithRequest(data); + }; + }; + _view.onLoadingStart = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnLoadingStart data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .navigationType = stringToOnLoadingStartNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String])), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String], [[dictionary valueForKey:@"mainDocumentURL"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) + }; + webViewEventEmitter->onLoadingStart(data); + } + }; + _view.onLoadingError = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnLoadingError data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .code = [[dictionary valueForKey:@"code"] intValue], + .description = std::string([[dictionary valueForKey:@"description"] UTF8String]), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .domain = std::string([[dictionary valueForKey:@"domain"] UTF8String]) + }; + webViewEventEmitter->onLoadingError(data); + } + }; + _view.onMessage = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnMessage data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .data = std::string([[dictionary valueForKey:@"data"] UTF8String]) + }; + webViewEventEmitter->onMessage(data); + } + }; + _view.onLoadingFinish = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnLoadingFinish data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .navigationType = stringToOnLoadingFinishNavigationTypeEnum(std::string([[dictionary valueForKey:@"navigationType"] UTF8String], [[dictionary valueForKey:@"navigationType"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding])), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .mainDocumentURL = std::string([[dictionary valueForKey:@"mainDocumentURL"] UTF8String], [[dictionary valueForKey:@"mainDocumentURL"] lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) + }; + webViewEventEmitter->onLoadingFinish(data); + } + }; + _view.onLoadingProgress = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnLoadingProgress data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue], + .progress = [[dictionary valueForKey:@"progress"] doubleValue] + }; + webViewEventEmitter->onLoadingProgress(data); + } + }; + _view.onContentProcessDidTerminate = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnContentProcessDidTerminate data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue] + }; + webViewEventEmitter->onContentProcessDidTerminate(data); + } + }; + _view.onCustomMenuSelection = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnCustomMenuSelection data = { + .selectedText = std::string([[dictionary valueForKey:@"selectedText"] UTF8String]), + .key = std::string([[dictionary valueForKey:@"key"] UTF8String]), + .label = std::string([[dictionary valueForKey:@"label"] UTF8String]) + + }; + webViewEventEmitter->onCustomMenuSelection(data); + } + }; + _view.onScroll = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + NSDictionary* contentOffset = [dictionary valueForKey:@"contentOffset"]; + NSDictionary* contentInset = [dictionary valueForKey:@"contentInset"]; + NSDictionary* contentSize = [dictionary valueForKey:@"contentSize"]; + NSDictionary* layoutMeasurement = [dictionary valueForKey:@"layoutMeasurement"]; + double zoomScale = [[dictionary valueForKey:@"zoomScale"] doubleValue]; + + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnScroll data = { + .contentOffset = { + .x = [[contentOffset valueForKey:@"x"] doubleValue], + .y = [[contentOffset valueForKey:@"y"] doubleValue] + }, + .contentInset = { + .left = [[contentInset valueForKey:@"left"] doubleValue], + .right = [[contentInset valueForKey:@"right"] doubleValue], + .top = [[contentInset valueForKey:@"top"] doubleValue], + .bottom = [[contentInset valueForKey:@"bottom"] doubleValue] + }, + .contentSize = { + .width = [[contentSize valueForKey:@"width"] doubleValue], + .height = [[contentSize valueForKey:@"height"] doubleValue] + }, + .layoutMeasurement = { + .width = [[layoutMeasurement valueForKey:@"width"] doubleValue], + .height = [[layoutMeasurement valueForKey:@"height"] doubleValue] }, + .zoomScale = zoomScale + }; + webViewEventEmitter->onScroll(data); + } + }; + _view.onHttpError = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnHttpError data = { + .url = std::string([[dictionary valueForKey:@"url"] UTF8String]), + .lockIdentifier = [[dictionary valueForKey:@"lockIdentifier"] doubleValue], + .title = std::string([[dictionary valueForKey:@"title"] UTF8String]), + .statusCode = [[dictionary valueForKey:@"statusCode"] intValue], + .description = std::string([[dictionary valueForKey:@"description"] UTF8String]), + .canGoBack = [[dictionary valueForKey:@"canGoBack"] boolValue], + .canGoForward = [[dictionary valueForKey:@"canGoBack"] boolValue], + .loading = [[dictionary valueForKey:@"loading"] boolValue] + }; + webViewEventEmitter->onHttpError(data); + } + }; + self.contentView = _view; + } + return self; +} + +- (void)updateEventEmitter:(EventEmitter::Shared const &)eventEmitter +{ + [super updateEventEmitter:eventEmitter]; +} + +- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps +{ + const auto &oldViewProps = *std::static_pointer_cast(_props); + const auto &newViewProps = *std::static_pointer_cast(props); + +#define REMAP_WEBVIEW_PROP(name) \ + if (oldViewProps.name != newViewProps.name) { \ + _view.name = newViewProps.name; \ + } + +#define REMAP_WEBVIEW_STRING_PROP(name) \ + if (oldViewProps.name != newViewProps.name) { \ + _view.name = RCTNSStringFromString(newViewProps.name); \ + } + + REMAP_WEBVIEW_PROP(scrollEnabled) + REMAP_WEBVIEW_STRING_PROP(injectedJavaScript) + REMAP_WEBVIEW_STRING_PROP(injectedJavaScriptBeforeContentLoaded) + REMAP_WEBVIEW_PROP(injectedJavaScriptForMainFrameOnly) + REMAP_WEBVIEW_PROP(injectedJavaScriptBeforeContentLoadedForMainFrameOnly) + REMAP_WEBVIEW_PROP(javaScriptEnabled) + REMAP_WEBVIEW_PROP(javaScriptCanOpenWindowsAutomatically) + REMAP_WEBVIEW_PROP(allowFileAccessFromFileURLs) + REMAP_WEBVIEW_PROP(allowUniversalAccessFromFileURLs) + REMAP_WEBVIEW_PROP(allowsInlineMediaPlayback) + REMAP_WEBVIEW_PROP(webviewDebuggingEnabled) + REMAP_WEBVIEW_PROP(allowsAirPlayForMediaPlayback) + REMAP_WEBVIEW_PROP(mediaPlaybackRequiresUserAction) + REMAP_WEBVIEW_PROP(automaticallyAdjustContentInsets) + REMAP_WEBVIEW_PROP(autoManageStatusBarEnabled) + REMAP_WEBVIEW_PROP(hideKeyboardAccessoryView) + REMAP_WEBVIEW_PROP(allowsBackForwardNavigationGestures) + REMAP_WEBVIEW_PROP(incognito) + REMAP_WEBVIEW_PROP(pagingEnabled) + REMAP_WEBVIEW_STRING_PROP(applicationNameForUserAgent) + REMAP_WEBVIEW_PROP(cacheEnabled) + REMAP_WEBVIEW_PROP(allowsLinkPreview) + REMAP_WEBVIEW_STRING_PROP(allowingReadAccessToURL) + + REMAP_WEBVIEW_PROP(messagingEnabled) + REMAP_WEBVIEW_PROP(fraudulentWebsiteWarningEnabled) + REMAP_WEBVIEW_PROP(enableApplePay) + REMAP_WEBVIEW_PROP(pullToRefreshEnabled) + REMAP_WEBVIEW_PROP(bounces) + REMAP_WEBVIEW_PROP(useSharedProcessPool) + REMAP_WEBVIEW_STRING_PROP(userAgent) + REMAP_WEBVIEW_PROP(sharedCookiesEnabled) + #if !TARGET_OS_OSX + REMAP_WEBVIEW_PROP(decelerationRate) + #endif // !TARGET_OS_OSX + REMAP_WEBVIEW_PROP(directionalLockEnabled) + REMAP_WEBVIEW_PROP(showsHorizontalScrollIndicator) + REMAP_WEBVIEW_PROP(showsVerticalScrollIndicator) + REMAP_WEBVIEW_PROP(keyboardDisplayRequiresUserAction) + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */ + REMAP_WEBVIEW_PROP(automaticallyAdjustContentInsets) +#endif +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 /* iOS 14 */ + REMAP_WEBVIEW_PROP(limitsNavigationsToAppBoundDomains) +#endif +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* iOS 14.5 */ + REMAP_WEBVIEW_PROP(textInteractionEnabled) +#endif + REMAP_WEBVIEW_PROP(webViewKey) + REMAP_WEBVIEW_PROP(temporaryParentNodeTag) + + if (oldViewProps.dataDetectorTypes != newViewProps.dataDetectorTypes) { + WKDataDetectorTypes dataDetectorTypes = WKDataDetectorTypeNone; + if (dataDetectorTypes & RNCWebViewDataDetectorTypes::Address) { + dataDetectorTypes |= WKDataDetectorTypeAddress; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::Link) { + dataDetectorTypes |= WKDataDetectorTypeLink; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::CalendarEvent) { + dataDetectorTypes |= WKDataDetectorTypeCalendarEvent; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::TrackingNumber) { + dataDetectorTypes |= WKDataDetectorTypeTrackingNumber; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::FlightNumber) { + dataDetectorTypes |= WKDataDetectorTypeFlightNumber; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::LookupSuggestion) { + dataDetectorTypes |= WKDataDetectorTypeLookupSuggestion; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::PhoneNumber) { + dataDetectorTypes |= WKDataDetectorTypePhoneNumber; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::All) { + dataDetectorTypes |= WKDataDetectorTypeAll; + } else if (dataDetectorTypes & RNCWebViewDataDetectorTypes::None) { + dataDetectorTypes = WKDataDetectorTypeNone; + } + [_view setDataDetectorTypes:dataDetectorTypes]; + } + if (oldViewProps.contentInset.top != newViewProps.contentInset.top || oldViewProps.contentInset.left != newViewProps.contentInset.left || oldViewProps.contentInset.right != newViewProps.contentInset.right || oldViewProps.contentInset.bottom != newViewProps.contentInset.bottom) { + UIEdgeInsets edgesInsets = { + .top = newViewProps.contentInset.top, + .left = newViewProps.contentInset.left, + .right = newViewProps.contentInset.right, + .bottom = newViewProps.contentInset.bottom + }; + [_view setContentInset: edgesInsets]; + } + + if (oldViewProps.basicAuthCredential.username != newViewProps.basicAuthCredential.username || oldViewProps.basicAuthCredential.password != newViewProps.basicAuthCredential.password) { + [_view setBasicAuthCredential: @{ + @"username": RCTNSStringFromString(newViewProps.basicAuthCredential.username), + @"password": RCTNSStringFromString(newViewProps.basicAuthCredential.password) + }]; + } + if (oldViewProps.contentInsetAdjustmentBehavior != newViewProps.contentInsetAdjustmentBehavior) { + if (newViewProps.contentInsetAdjustmentBehavior == RNCWebViewContentInsetAdjustmentBehavior::Never) { + [_view setContentInsetAdjustmentBehavior: UIScrollViewContentInsetAdjustmentNever]; + } else if (newViewProps.contentInsetAdjustmentBehavior == RNCWebViewContentInsetAdjustmentBehavior::Automatic) { + [_view setContentInsetAdjustmentBehavior: UIScrollViewContentInsetAdjustmentAutomatic]; + } else if (newViewProps.contentInsetAdjustmentBehavior == RNCWebViewContentInsetAdjustmentBehavior::ScrollableAxes) { + [_view setContentInsetAdjustmentBehavior: UIScrollViewContentInsetAdjustmentScrollableAxes]; + } else if (newViewProps.contentInsetAdjustmentBehavior == RNCWebViewContentInsetAdjustmentBehavior::Always) { + [_view setContentInsetAdjustmentBehavior: UIScrollViewContentInsetAdjustmentAlways]; + } + } + + if (oldViewProps.menuItems != newViewProps.menuItems) { + NSMutableArray *newMenuItems = [NSMutableArray array]; + + for (const auto &menuItem: newViewProps.menuItems) { + [newMenuItems addObject:@{ + @"key": RCTNSStringFromString(menuItem.key), + @"label": RCTNSStringFromString(menuItem.label), + }]; + + } + [_view setMenuItems:newMenuItems]; + } + if (oldViewProps.hasOnFileDownload != newViewProps.hasOnFileDownload) { + if (newViewProps.hasOnFileDownload) { + _view.onFileDownload = [self](NSDictionary* dictionary) { + if (_eventEmitter) { + auto webViewEventEmitter = std::static_pointer_cast(_eventEmitter); + facebook::react::RNCWebViewEventEmitter::OnFileDownload data = { + .downloadUrl = std::string([[dictionary valueForKey:@"downloadUrl"] UTF8String]) + }; + webViewEventEmitter->onFileDownload(data); + } + }; + } else { + _view.onFileDownload = nil; + } + } +// +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ + if (oldViewProps.contentMode != newViewProps.contentMode) { + if (newViewProps.contentMode == RNCWebViewContentMode::Recommended) { + [_view setContentMode: WKContentModeRecommended]; + } else if (newViewProps.contentMode == RNCWebViewContentMode::Mobile) { + [_view setContentMode:WKContentModeMobile]; + } else if (newViewProps.contentMode == RNCWebViewContentMode::Desktop) { + [_view setContentMode:WKContentModeDesktop]; + } + } +#endif + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */ + if (oldViewProps.mediaCapturePermissionGrantType != newViewProps.mediaCapturePermissionGrantType) { + if (newViewProps.mediaCapturePermissionGrantType == RNCWebViewMediaCapturePermissionGrantType::Prompt) { + [_view setMediaCapturePermissionGrantType:RNCWebViewPermissionGrantType_Prompt]; + } else if (newViewProps.mediaCapturePermissionGrantType == RNCWebViewMediaCapturePermissionGrantType::Grant) { + [_view setMediaCapturePermissionGrantType:RNCWebViewPermissionGrantType_Grant]; + } else if (newViewProps.mediaCapturePermissionGrantType == RNCWebViewMediaCapturePermissionGrantType::Deny) { + [_view setMediaCapturePermissionGrantType:RNCWebViewPermissionGrantType_Deny]; + }else if (newViewProps.mediaCapturePermissionGrantType == RNCWebViewMediaCapturePermissionGrantType::GrantIfSameHostElsePrompt) { + [_view setMediaCapturePermissionGrantType:RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt]; + }else if (newViewProps.mediaCapturePermissionGrantType == RNCWebViewMediaCapturePermissionGrantType::GrantIfSameHostElseDeny) { + [_view setMediaCapturePermissionGrantType:RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny]; + } + } +#endif + + NSMutableDictionary* source = [[NSMutableDictionary alloc] init]; + if (!newViewProps.newSource.uri.empty()) { + [source setValue:RCTNSStringFromString(newViewProps.newSource.uri) forKey:@"uri"]; + } + NSMutableDictionary* headers = [[NSMutableDictionary alloc] init]; + for (auto & element : newViewProps.newSource.headers) { + [headers setValue:RCTNSStringFromString(element.value) forKey:RCTNSStringFromString(element.name)]; + } + if (headers.count > 0) { + [source setObject:headers forKey:@"headers"]; + } + if (!newViewProps.newSource.baseUrl.empty()) { + [source setValue:RCTNSStringFromString(newViewProps.newSource.baseUrl) forKey:@"baseUrl"]; + } + if (!newViewProps.newSource.body.empty()) { + [source setValue:RCTNSStringFromString(newViewProps.newSource.body) forKey:@"body"]; + } + if (!newViewProps.newSource.html.empty()) { + [source setValue:RCTNSStringFromString(newViewProps.newSource.html) forKey:@"html"]; + } + if (!newViewProps.newSource.method.empty()) { + [source setValue:RCTNSStringFromString(newViewProps.newSource.method) forKey:@"method"]; + } + [_view setSource:source]; + + [super updateProps:props oldProps:oldProps]; +} + +- (void)handleCommand:(nonnull const NSString *)commandName args:(nonnull const NSArray *)args { + RCTRNCWebViewHandleCommand(self, commandName, args); +} + + +Class RNCWebViewCls(void) +{ + return RNCWebView.class; +} + +- (void)goBack { + [_view goBack]; +} + +- (void)goForward { + [_view goForward]; +} + +- (void)injectJavaScript:(nonnull NSString *)javascript { + [_view injectJavaScript:javascript]; +} + +- (void)loadUrl:(nonnull NSString *)url { + // android only +} + +- (void)postMessage:(nonnull NSString *)data { + [_view postMessage:data]; +} + +- (void)reload { + [_view reload]; +} + +- (void)requestFocus { + [_view requestFocus]; +} + +- (void)stopLoading { + [_view stopLoading]; +} + +- (void)clearFormData { + // android only +} + +- (void)clearCache:(BOOL)includeDiskFiles { + // android only +} + +- (void)clearHistory { + // android only +} + +@end +#endif diff --git a/apple/RNCWebViewDecisionManager.h b/apple/RNCWebViewDecisionManager.h new file mode 100644 index 0000000000..da01fba0b8 --- /dev/null +++ b/apple/RNCWebViewDecisionManager.h @@ -0,0 +1,20 @@ +#import +#import +#import + +typedef void (^DecisionBlock)(BOOL); + +@interface RNCWebViewDecisionManager : NSObject { + int nextLockIdentifier; + NSMutableDictionary *decisionHandlers; +} + +@property (nonatomic) int nextLockIdentifier; +@property (nonatomic, retain) NSMutableDictionary *decisionHandlers; + ++ (id) getInstance; + +- (int)setDecisionHandler:(DecisionBlock)handler; +- (void) setResult:(BOOL)shouldStart + forLockIdentifier:(int)lockIdentifier; +@end diff --git a/apple/RNCWebViewDecisionManager.m b/apple/RNCWebViewDecisionManager.m new file mode 100644 index 0000000000..aa90548132 --- /dev/null +++ b/apple/RNCWebViewDecisionManager.m @@ -0,0 +1,47 @@ +#import "RNCWebViewDecisionManager.h" + + + +@implementation RNCWebViewDecisionManager + +@synthesize nextLockIdentifier; +@synthesize decisionHandlers; + ++ (id)getInstance { + static RNCWebViewDecisionManager *lockManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lockManager = [[self alloc] init]; + }); + return lockManager; +} + +- (int)setDecisionHandler:(DecisionBlock)decisionHandler { + int lockIdentifier = self.nextLockIdentifier++; + + [self.decisionHandlers setObject:decisionHandler forKey:@(lockIdentifier)]; + return lockIdentifier; +} + +- (void) setResult:(BOOL)shouldStart + forLockIdentifier:(int)lockIdentifier { + DecisionBlock handler = [self.decisionHandlers objectForKey:@(lockIdentifier)]; + if (handler == nil) { + RCTLogWarn(@"Lock not found"); + return; + } + handler(shouldStart); + [self.decisionHandlers removeObjectForKey:@(lockIdentifier)]; +} + +- (id)init { + if (self = [super init]) { + self.nextLockIdentifier = 1; + self.decisionHandlers = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)dealloc {} + +@end diff --git a/apple/RNCWebViewImpl.h b/apple/RNCWebViewImpl.h new file mode 100644 index 0000000000..68ce000f26 --- /dev/null +++ b/apple/RNCWebViewImpl.h @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2015-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. + */ + +#import +#import +#import +#import + +#if !TARGET_OS_OSX +#import +#endif // !TARGET_OS_OSX + +#import "RNCWebViewDecisionManager.h" + +typedef enum RNCWebViewPermissionGrantType : NSUInteger { + RNCWebViewPermissionGrantType_GrantIfSameHost_ElsePrompt, + RNCWebViewPermissionGrantType_GrantIfSameHost_ElseDeny, + RNCWebViewPermissionGrantType_Deny, + RNCWebViewPermissionGrantType_Grant, + RNCWebViewPermissionGrantType_Prompt +} RNCWebViewPermissionGrantType; + +@class RNCWebViewImpl; + +NS_ASSUME_NONNULL_BEGIN + +@protocol RNCWebViewDelegate + +- (BOOL)webView:(RNCWebViewImpl *)webView +shouldStartLoadForRequest:(NSMutableDictionary *)request + withCallback:(RCTDirectEventBlock)callback; + +@end + +@interface RNCWeakScriptMessageDelegate : NSObject + +@property (nonatomic, weak, nullable) id scriptDelegate; + +- (nullable instancetype)initWithDelegate:(id _Nullable)scriptDelegate; + +@end + +@interface RNCWebViewImpl : RCTView +@property (nonatomic, copy) RCTDirectEventBlock onFileDownload; +@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart; +@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish; +@property (nonatomic, copy) RCTDirectEventBlock onLoadingError; +@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress; +@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest; +@property (nonatomic, copy) RCTDirectEventBlock onHttpError; +@property (nonatomic, copy) RCTDirectEventBlock onMessage; +@property (nonatomic, copy) RCTDirectEventBlock onScroll; +@property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate; + + +@property (nonatomic, weak) id _Nullable delegate; +@property (nonatomic, copy) NSDictionary * _Nullable source; +@property (nonatomic, assign) BOOL messagingEnabled; +@property (nonatomic, copy) NSString * _Nullable injectedJavaScript; +@property (nonatomic, copy) NSString * _Nullable injectedJavaScriptBeforeContentLoaded; +@property (nonatomic, assign) BOOL injectedJavaScriptForMainFrameOnly; +@property (nonatomic, assign) BOOL injectedJavaScriptBeforeContentLoadedForMainFrameOnly; +@property (nonatomic, assign) BOOL scrollEnabled; +@property (nonatomic, assign) BOOL sharedCookiesEnabled; +@property (nonatomic, assign) BOOL autoManageStatusBarEnabled; +@property (nonatomic, assign) BOOL pagingEnabled; +@property (nonatomic, assign) CGFloat decelerationRate; +@property (nonatomic, assign) BOOL allowsInlineMediaPlayback; +@property (nonatomic, assign) BOOL webviewDebuggingEnabled; +@property (nonatomic, assign) BOOL allowsAirPlayForMediaPlayback; +@property (nonatomic, assign) BOOL bounces; +@property (nonatomic, assign) BOOL mediaPlaybackRequiresUserAction; +@property (nonatomic, assign) UIEdgeInsets contentInset; +@property (nonatomic, assign) BOOL automaticallyAdjustContentInsets; +@property (nonatomic, assign) BOOL keyboardDisplayRequiresUserAction; +@property (nonatomic, assign) BOOL hideKeyboardAccessoryView; +@property (nonatomic, assign) BOOL allowsBackForwardNavigationGestures; +@property (nonatomic, assign) BOOL incognito; +@property (nonatomic, assign) BOOL useSharedProcessPool; +@property (nonatomic, copy) NSString * _Nullable userAgent; +@property (nonatomic, copy) NSString * _Nullable applicationNameForUserAgent; +@property (nonatomic, assign) BOOL cacheEnabled; +@property (nonatomic, assign) BOOL javaScriptEnabled; +@property (nonatomic, assign) BOOL javaScriptCanOpenWindowsAutomatically; +@property (nonatomic, assign) BOOL allowFileAccessFromFileURLs; +@property (nonatomic, assign) BOOL allowUniversalAccessFromFileURLs; +@property (nonatomic, assign) BOOL allowsLinkPreview; +@property (nonatomic, assign) BOOL showsHorizontalScrollIndicator; +@property (nonatomic, assign) BOOL showsVerticalScrollIndicator; +@property (nonatomic, assign) BOOL directionalLockEnabled; +@property (nonatomic, assign) BOOL ignoreSilentHardwareSwitch; +@property (nonatomic, copy) NSString * _Nullable allowingReadAccessToURL; +@property (nonatomic, copy) NSDictionary * _Nullable basicAuthCredential; +@property (nonatomic, assign) BOOL pullToRefreshEnabled; +@property (nonatomic, assign) BOOL enableApplePay; +@property (nonatomic, copy) NSArray * _Nullable menuItems; +@property (nonatomic, copy) RCTDirectEventBlock onCustomMenuSelection; +#if !TARGET_OS_OSX +@property (nonatomic, assign) WKDataDetectorTypes dataDetectorTypes; +@property (nonatomic, weak) UIRefreshControl * _Nullable refreshControl; +#endif + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ +@property (nonatomic, assign) WKContentMode contentMode; +@property (nonatomic, assign) BOOL fraudulentWebsiteWarningEnabled; +#endif + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000 /* iOS 14 */ +@property (nonatomic, assign) BOOL limitsNavigationsToAppBoundDomains; +#endif + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500 /* iOS 14.5 */ +@property (nonatomic, assign) BOOL textInteractionEnabled; +#endif + +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000 /* iOS 15 */ +@property (nonatomic, assign) RNCWebViewPermissionGrantType mediaCapturePermissionGrantType; +#endif + +#if !TARGET_OS_OSX +- (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior; +#endif // !TARGET_OS_OSX + +@property (nonatomic, copy) NSString * _Nullable webViewKey; +@property (nonatomic, copy) NSNumber * _Nullable temporaryParentNodeTag; + ++ (void)setClientAuthenticationCredential:(nullable NSURLCredential*)credential; ++ (void)setCustomCertificatesForHost:(nullable NSDictionary *)certificates; ++ (NSMutableDictionary*)createEventFromMessage:(WKScriptMessage *_Nonnull)message withMessageBodyKey: (NSString *_Nonnull)messageBodyKey withWebView: (WKWebView *)webView; +- (void)postMessage:(NSString *_Nullable)message; +- (void)injectJavaScript:(NSString *_Nullable)script; +- (void)goForward; +- (void)goBack; +- (void)reload; +- (void)stopLoading; +- (void)requestFocus; +#ifdef RCT_NEW_ARCH_ENABLED +- (void)destroyWebView; +#endif +- (void)releaseWebView; +- (void)cleanUpWebView; +#if !TARGET_OS_OSX +- (void)addPullToRefreshControl; +- (void)pullToRefresh:(UIRefreshControl *)refreshControl; +#endif + +@end + +NS_ASSUME_NONNULL_END diff --git a/apple/RNCWebView.m b/apple/RNCWebViewImpl.m similarity index 88% rename from apple/RNCWebView.m rename to apple/RNCWebViewImpl.m index a97e25c251..29aaad86a6 100644 --- a/apple/RNCWebView.m +++ b/apple/RNCWebViewImpl.m @@ -5,9 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -#import "RNCWebView.h" +#import "RNCWebViewImpl.h" #import #import +#import #import #import #import "RNCWKProcessPoolManager.h" @@ -43,7 +44,6 @@ -(id)inputAccessoryView if (_webView == nil) { return nil; } - if ([_webView respondsToSelector:@selector(inputAssistantItem)]) { UITextInputAssistantItem *inputAssistantItem = [_webView inputAssistantItem]; inputAssistantItem.leadingBarButtonGroups = @[]; @@ -54,49 +54,56 @@ -(id)inputAccessoryView @end #endif // !TARGET_OS_OSX -#if TARGET_OS_OSX @interface RNCWKWebView : WKWebView +#if !TARGET_OS_OSX +@property (nonatomic, copy) NSArray * _Nullable menuItems; +#endif // !TARGET_OS_OSX @end @implementation RNCWKWebView +#if !TARGET_OS_OSX +- (BOOL)canPerformAction:(SEL)action + withSender:(id)sender{ + + if (!self.menuItems) { + return [super canPerformAction:action withSender:sender]; + } + + return NO; +} +- (void)buildMenuWithBuilder:(id)builder API_AVAILABLE(ios(13.0)) { + if (@available(iOS 16.0, *)) { + if(self.menuItems){ + [builder removeMenuForIdentifier:UIMenuLookup]; + } + } + [super buildMenuWithBuilder:builder]; +} +#else // TARGET_OS_OSX - (void)scrollWheel:(NSEvent *)theEvent { - RNCWebView *rncWebView = (RNCWebView *)[self superview]; - RCTAssert([rncWebView isKindOfClass:[rncWebView class]], @"superview must be an RNCWebView"); + RNCWebViewImpl *rncWebView = (RNCWebViewImpl *)[self superview]; + RCTAssert([rncWebView isKindOfClass:[rncWebView class]], @"superview must be an RNCWebViewImpl"); if (![rncWebView scrollEnabled]) { [[self nextResponder] scrollWheel:theEvent]; return; } [super scrollWheel:theEvent]; } -@end #endif // TARGET_OS_OSX +@end -@interface RNCWebView () -@property (nonatomic, copy) RCTDirectEventBlock onFileDownload; -@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart; -@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish; -@property (nonatomic, copy) RCTDirectEventBlock onLoadingError; -@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress; -@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest; -@property (nonatomic, copy) RCTDirectEventBlock onHttpError; -@property (nonatomic, copy) RCTDirectEventBlock onMessage; -@property (nonatomic, copy) RCTDirectEventBlock onScroll; -@property (nonatomic, copy) RCTDirectEventBlock onContentProcessDidTerminate; -#if !TARGET_OS_OSX -@property (nonatomic, copy) WKWebView *webView; -#else @property (nonatomic, copy) RNCWKWebView *webView; -#endif // !TARGET_OS_OSX @property (nonatomic, strong) WKUserScript *postMessageScript; @property (nonatomic, strong) WKUserScript *atStartScript; @property (nonatomic, strong) WKUserScript *atEndScript; @end -@implementation RNCWebView +@implementation RNCWebViewImpl { #if !TARGET_OS_OSX UIColor * _savedBackgroundColor; @@ -165,7 +172,6 @@ - (instancetype)initWithFrame:(CGRect)frame selector:@selector(appDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appWillResignActive) name:UIApplicationWillResignActiveNotification @@ -181,19 +187,16 @@ - (instancetype)initWithFrame:(CGRect)frame addObserver:self selector:@selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil]; - // Workaround for StatusBar appearance bug for iOS 12 // https://github.com/react-native-webview/react-native-webview/issues/62 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showFullScreenVideoStatusBars) name:UIWindowDidBecomeVisibleNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(hideFullScreenVideoStatusBars) name:UIWindowDidBecomeHiddenNotification object:nil]; - } #endif // !TARGET_OS_OSX return self; @@ -212,27 +215,30 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecogni // Listener for long presses - (void)startLongPress:(UILongPressGestureRecognizer *)pressSender { - // When a long press ends, bring up our custom UIMenu - if(pressSender.state == UIGestureRecognizerStateEnded) { - if (!self.menuItems || self.menuItems.count == 0) { - return; + if (pressSender.state != UIGestureRecognizerStateEnded || !self.menuItems) { + return; + } + // When a long press ends, bring up our custom UIMenu if defined + if (self.menuItems.count == 0) { + UIMenuController *menuController = [UIMenuController sharedMenuController]; + menuController.menuItems = nil; + [menuController setMenuVisible:NO animated:YES]; + return; } UIMenuController *menuController = [UIMenuController sharedMenuController]; NSMutableArray *menuControllerItems = [NSMutableArray arrayWithCapacity:self.menuItems.count]; - + for(NSDictionary *menuItem in self.menuItems) { NSString *menuItemLabel = [RCTConvert NSString:menuItem[@"label"]]; NSString *menuItemKey = [RCTConvert NSString:menuItem[@"key"]]; NSString *sel = [NSString stringWithFormat:@"%@%@", CUSTOM_SELECTOR, menuItemKey]; UIMenuItem *item = [[UIMenuItem alloc] initWithTitle: menuItemLabel action: NSSelectorFromString(sel)]; - [menuControllerItems addObject: item]; } - + menuController.menuItems = menuControllerItems; [menuController setMenuVisible:YES animated:YES]; - } } #endif // !TARGET_OS_OSX @@ -306,7 +312,6 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender NSString *sel = NSStringFromSelector(action); // Do any of them have our custom keys? NSRange match = [sel rangeOfString:CUSTOM_SELECTOR]; - if (match.location == 0) { return YES; } @@ -350,6 +355,14 @@ - (WKWebViewConfiguration *)setUpWkWebViewConfig prefs.javaScriptEnabled = NO; _prefsUsed = YES; } +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ + if (@available(iOS 13.0, *)) { + if (!_fraudulentWebsiteWarningEnabled) { + prefs.fraudulentWebsiteWarningEnabled = NO; + _prefsUsed = YES; + } + } +#endif if (_allowUniversalAccessFromFileURLs) { [wkWebViewConfig setValue:@TRUE forKey:@"allowUniversalAccessFromFileURLs"]; } @@ -404,21 +417,17 @@ - (WKWebViewConfiguration *)setUpWkWebViewConfig [wkWebViewConfig.userContentController addScriptMessageHandler:[[RNCWeakScriptMessageDelegate alloc] initWithDelegate:self] name:HistoryShimName]; [self resetupScripts:wkWebViewConfig]; - + if(@available(macos 10.11, ios 9.0, *)) { wkWebViewConfig.allowsAirPlayForMediaPlayback = _allowsAirPlayForMediaPlayback; } - + #if !TARGET_OS_OSX wkWebViewConfig.allowsInlineMediaPlayback = _allowsInlineMediaPlayback; -#if WEBKIT_IOS_10_APIS_AVAILABLE wkWebViewConfig.mediaTypesRequiringUserActionForPlayback = _mediaPlaybackRequiresUserAction ? WKAudiovisualMediaTypeAll : WKAudiovisualMediaTypeNone; wkWebViewConfig.dataDetectorTypes = _dataDetectorTypes; -#else - wkWebViewConfig.mediaPlaybackRequiresUserAction = _mediaPlaybackRequiresUserAction; -#endif #endif // !TARGET_OS_OSX if (_applicationNameForUserAgent) { @@ -428,20 +437,28 @@ - (WKWebViewConfiguration *)setUpWkWebViewConfig return wkWebViewConfig; } +// react-native-mac os does not support didMoveToSuperView https://github.com/microsoft/react-native-macos/blob/main/React/Base/RCTUIKit.h#L388 +#if !TARGET_OS_OSX +- (void)didMoveToSuperview +{ + if (_webView == nil) { +#else - (void)didMoveToWindow { if (self.window != nil && _webView == nil) { +#endif // !TARGET_OS_OSX + WKWebViewConfiguration *wkWebViewConfig = [self setUpWkWebViewConfig]; NSMutableDictionary *sharedWKWebViewDictionary = [[RNCWKWebViewMapManager sharedManager] sharedWKWebViewDictionary]; if ([self shouldReuseWebView]) { - WKWebView *webViewForKey = sharedWKWebViewDictionary[_webViewKey]; + RNCWKWebView *webViewForKey = sharedWKWebViewDictionary[_webViewKey]; if (webViewForKey != nil) { _webView = webViewForKey; UIView *parentView = webViewForKey.superview; if (parentView != nil) { - if ([parentView isKindOfClass:[RNCWebView class]]) { - [self removeWKWebViewFromSuperView:(RNCWebView*)parentView]; + if ([parentView isKindOfClass:[RNCWebViewImpl class]]) { + [self removeWKWebViewFromSuperView:(RNCWebViewImpl*)parentView]; } else { // The webview might be attached to a temporary parent; if so, remove it first. [_webView removeFromSuperview]; @@ -454,7 +471,7 @@ - (void)didMoveToWindow if (_webView == nil) { #if !TARGET_OS_OSX - _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig]; + _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig]; #else _webView = [[RNCWKWebView alloc] initWithFrame:self.bounds configuration: wkWebViewConfig]; #endif // !TARGET_OS_OSX @@ -469,6 +486,7 @@ - (void)didMoveToWindow [self setBackgroundColor: _savedBackgroundColor]; #if !TARGET_OS_OSX + _webView.menuItems = _menuItems; _webView.scrollView.delegate = self; #endif // !TARGET_OS_OSX _webView.UIDelegate = self; @@ -489,11 +507,13 @@ - (void)didMoveToWindow _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures; _webView.customUserAgent = _userAgent; -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ + +#if !TARGET_OS_OSX if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { _webView.scrollView.contentInsetAdjustmentBehavior = _savedContentInsetAdjustmentBehavior; } -#endif +#endif // !TARGET_OS_OSX + #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */ if (@available(iOS 13.0, *)) { _webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = _savedAutomaticallyAdjustsScrollIndicatorInsets; @@ -505,6 +525,14 @@ - (void)didMoveToWindow // RNCWebView instance. [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil]; + +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \ + __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \ + __TV_OS_VERSION_MAX_ALLOWED >= 160400 + if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *)) + _webView.inspectable = _webviewDebuggingEnabled; +#endif + [self addSubview:_webView]; [self setHideKeyboardAccessoryView: _savedHideKeyboardAccessoryView]; [self setKeyboardDisplayRequiresUserAction: _savedKeyboardDisplayRequiresUserAction]; @@ -533,22 +561,36 @@ - (void)setAllowsBackForwardNavigationGestures:(BOOL)allowsBackForwardNavigation _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures; } +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 130300 || \ + __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400 || \ + __TV_OS_VERSION_MAX_ALLOWED >= 160400 +- (void)setWebviewDebuggingEnabled:(BOOL)webviewDebuggingEnabled { + _webviewDebuggingEnabled = webviewDebuggingEnabled; + if (@available(macOS 13.3, iOS 16.4, tvOS 16.4, *)) + _webView.inspectable = _webviewDebuggingEnabled; +} +#endif + +#ifdef RCT_NEW_ARCH_ENABLED +- (void)destroyWebView +#else - (void)removeFromSuperview +#endif { if (![self shouldReuseWebView]) { [self cleanUpWebView]; } else { NSMutableDictionary *sharedWKWebViewDictionary = [[RNCWKWebViewMapManager sharedManager] sharedWKWebViewDictionary]; - WKWebView *wkWebView = sharedWKWebViewDictionary[_webViewKey]; - RNCWebView *rncWebView = wkWebView.superview; + RNCWKWebView *wkWebView = sharedWKWebViewDictionary[_webViewKey]; + UIView *parentView = wkWebView.superview; // When this view is being unmounted, only remove the WKWebView from the superview // if this RNCWebView is the "active" view. - if (rncWebView == self) { + if (parentView == self) { [self removeWKWebViewFromSuperView:self]; if (_temporaryParentNodeTag != nil) { - UIView* temporaryParentView = [self.bridge.uiManager viewForReactTag:_temporaryParentNodeTag]; + UIView* temporaryParentView = [[[RCTBridge currentBridge] uiManager] viewForReactTag:_temporaryParentNodeTag]; // Resizes the webview to parent bounds [_webView setFrame:temporaryParentView.bounds]; [temporaryParentView addSubview:_webView]; @@ -556,7 +598,9 @@ - (void)removeFromSuperview } } - [super removeFromSuperview]; + #ifndef RCT_NEW_ARCH_ENABLED + [super removeFromSuperview]; + #endif } - (void)cleanUpWebView @@ -567,6 +611,10 @@ - (void)cleanUpWebView [self removeWKWebViewFromSuperView:self]; #if !TARGET_OS_OSX _webView.scrollView.delegate = nil; + if (_menuItems) { + UIMenuController *menuController = [UIMenuController sharedMenuController]; + menuController.menuItems = nil; + } #endif // !TARGET_OS_OSX _webView = nil; if (_onContentProcessDidTerminate) { @@ -576,7 +624,7 @@ - (void)cleanUpWebView } } -- (void)removeWKWebViewFromSuperView:(RNCWebView *)webViewObserver +- (void)removeWKWebViewFromSuperView:(RNCWebViewImpl *)webViewObserver { // If _webView is getting added to a new super view, we need to first both remove it from the old // superview and also remove the observer which can reference the old super view. @@ -592,7 +640,6 @@ -(void)showFullScreenVideoStatusBars if (!_autoManageStatusBarEnabled) { return; } - _isFullScreenVideoOpen = YES; RCTUnsafeExecuteOnMainQueueSync(^{ [RCTSharedApplication() setStatusBarStyle:self->_savedStatusBarStyle animated:YES]; @@ -606,7 +653,6 @@ -(void)hideFullScreenVideoStatusBars if (!_autoManageStatusBarEnabled) { return; } - _isFullScreenVideoOpen = NO; RCTUnsafeExecuteOnMainQueueSync(^{ [RCTSharedApplication() setStatusBarHidden:self->_savedStatusBarHidden animated:YES]; @@ -683,21 +729,21 @@ - (void)setBackgroundColor:(RCTUIColor *)backgroundColor #endif // !TARGET_OS_OSX } -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ +#if !TARGET_OS_OSX - (void)setContentInsetAdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior { _savedContentInsetAdjustmentBehavior = behavior; if (_webView == nil) { return; } - if ([_webView.scrollView respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { CGPoint contentOffset = _webView.scrollView.contentOffset; _webView.scrollView.contentInsetAdjustmentBehavior = behavior; _webView.scrollView.contentOffset = contentOffset; } } -#endif +#endif // !TARGET_OS_OSX + #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* __IPHONE_13_0 */ - (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjustsScrollIndicatorInsets{ _savedAutomaticallyAdjustsScrollIndicatorInsets = automaticallyAdjustsScrollIndicatorInsets; @@ -719,12 +765,12 @@ - (void)userContentController:(WKUserContentController *)userContentController { if ([message.name isEqualToString:HistoryShimName]) { if (_onLoadingFinish) { - NSMutableDictionary *event = [RNCWebView createEventFromMessage:message withMessageBodyKey: @"navigationType" withWebView:_webView]; + NSMutableDictionary *event = [RNCWebViewImpl createEventFromMessage:message withMessageBodyKey: @"navigationType" withWebView:_webView]; _onLoadingFinish(event); } } else if ([message.name isEqualToString:MessageHandlerName]) { if (_onMessage) { - NSMutableDictionary *event = [RNCWebView createEventFromMessage:message withMessageBodyKey: kMessageHandlerBodyKey withWebView:_webView]; + NSMutableDictionary *event = [RNCWebViewImpl createEventFromMessage:message withMessageBodyKey: kMessageHandlerBodyKey withWebView:_webView]; _onMessage(event); } } @@ -789,62 +835,69 @@ - (void)visitSource NSArray *httpCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:urlString]; [self writeCookiesToWebView:httpCookies completion:nil]; } - + NSURLRequest *request = [self requestForSource:_source]; - + __weak WKWebView *webView = _webView; + NSString *allowingReadAccessToURL = _allowingReadAccessToURL; + [self syncCookiesToWebView:^{ // Because of the way React works, as pages redirect, we actually end up // passing the redirect urls back here, so we ignore them if trying to load // the same url. We'll expose a call to 'reload' to allow a user to load // the existing page. - if ([request.URL isEqual:_webView.URL]) { + if ([request.URL isEqual:webView.URL]) { return; } if (!request.URL) { // Clear the webview - [_webView loadHTMLString:@"" baseURL:nil]; + [webView loadHTMLString:@"" baseURL:nil]; return; } if (request.URL.host) { - [_webView loadRequest:request]; + [webView loadRequest:request]; } else { - NSURL* readAccessUrl = _allowingReadAccessToURL ? [RCTConvert NSURL:_allowingReadAccessToURL] : request.URL; - [_webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl]; + NSURL* readAccessUrl = allowingReadAccessToURL ? [RCTConvert NSURL:allowingReadAccessToURL] : request.URL; + [webView loadFileURL:request.URL allowingReadAccessToURL:readAccessUrl]; } }]; } #if !TARGET_OS_OSX +-(void)setMenuItems:(NSArray *)menuItems { + _menuItems = menuItems; + _webView.menuItems = menuItems; +} + -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAction { if (_webView == nil) { _savedKeyboardDisplayRequiresUserAction = keyboardDisplayRequiresUserAction; return; } - + if (_savedKeyboardDisplayRequiresUserAction == true) { return; } - + UIView* subview; - + for (UIView* view in _webView.scrollView.subviews) { if([[view.class description] hasPrefix:@"WK"]) subview = view; } - + if(subview == nil) return; - + Class class = subview.class; - + NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0}; NSOperatingSystemVersion iOS_12_2_0 = (NSOperatingSystemVersion){12, 2, 0}; NSOperatingSystemVersion iOS_13_0_0 = (NSOperatingSystemVersion){13, 0, 0}; - + Method method; IMP override; - + if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_13_0_0]) { // iOS 13.0.0 - Future SEL selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:"); @@ -880,7 +933,6 @@ -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAct ((void (*)(id, SEL, void*, BOOL, BOOL, id))original)(me, selector, arg0, TRUE, arg2, arg3); }); } - method_setImplementation(method, override); } @@ -890,34 +942,34 @@ -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView _savedHideKeyboardAccessoryView = hideKeyboardAccessoryView; return; } - + if (_savedHideKeyboardAccessoryView == false) { return; } - + UIView* subview; - + for (UIView* view in _webView.scrollView.subviews) { if([[view.class description] hasPrefix:@"WK"]) subview = view; } - + if(subview == nil) return; - + NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass]; Class newClass = NSClassFromString(name); - + if(newClass == nil) { newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0); if(!newClass) return; - + Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView)); class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method)); - + objc_registerClassPair(newClass); } - + object_setClass(subview, newClass); } @@ -1008,8 +1060,8 @@ - (void)postMessage:(NSString *)message - (void)layoutSubviews { [super layoutSubviews]; - - // Ensure webview takes the position and dimensions of RNCWebView + + // Ensure webview takes the position and dimensions of RNCWebViewImpl _webView.frame = self.bounds; #if !TARGET_OS_OSX _webView.scrollView.contentInset = _contentInset; @@ -1029,13 +1081,13 @@ - (void)layoutSubviews } - (NSMutableDictionary *)baseEvent { - return [RNCWebView baseEventWithWebView:_webView]; + return [RNCWebViewImpl baseEventWithWebView:_webView]; } + (NSMutableDictionary*)createEventFromMessage:(WKScriptMessage *_Nonnull)message withMessageBodyKey: (NSString *_Nonnull)messageBodyKey withWebView:(WKWebView *)webView { - NSMutableDictionary *event = [RNCWebView baseEventWithWebView:webView]; + NSMutableDictionary *event = [RNCWebViewImpl baseEventWithWebView:webView]; [event addEntriesFromDictionary: @{messageBodyKey: message.body}]; return event; @@ -1229,58 +1281,79 @@ - (void) webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { - static NSDictionary *navigationTypes; - static dispatch_once_t onceToken; - - dispatch_once(&onceToken, ^{ - navigationTypes = @{ - @(WKNavigationTypeLinkActivated): @"click", - @(WKNavigationTypeFormSubmitted): @"formsubmit", - @(WKNavigationTypeBackForward): @"backforward", - @(WKNavigationTypeReload): @"reload", - @(WKNavigationTypeFormResubmitted): @"formresubmit", - @(WKNavigationTypeOther): @"other", - }; - }); - - WKNavigationType navigationType = navigationAction.navigationType; - NSURLRequest *request = navigationAction.request; - BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL]; - - if (_onShouldStartLoadWithRequest) { - NSMutableDictionary *event = [self baseEvent]; - if (request.mainDocumentURL) { - [event addEntriesFromDictionary: @{ - @"mainDocumentURL": (request.mainDocumentURL).absoluteString, - }]; - } - [event addEntriesFromDictionary: @{ - @"url": (request.URL).absoluteString, - @"navigationType": navigationTypes[@(navigationType)], - @"isTopFrame": @(isTopFrame) - }]; - if (![self.delegate webView:self - shouldStartLoadForRequest:event - withCallback:_onShouldStartLoadWithRequest]) { - decisionHandler(WKNavigationActionPolicyCancel); - return; + static NSDictionary *navigationTypes; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + navigationTypes = @{ + @(WKNavigationTypeLinkActivated): @"click", + @(WKNavigationTypeFormSubmitted): @"formsubmit", + @(WKNavigationTypeBackForward): @"backforward", + @(WKNavigationTypeReload): @"reload", + @(WKNavigationTypeFormResubmitted): @"formresubmit", + @(WKNavigationTypeOther): @"other", + }; + }); + + WKNavigationType navigationType = navigationAction.navigationType; + NSURLRequest *request = navigationAction.request; + BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL]; + + if (_onShouldStartLoadWithRequest) { + NSMutableDictionary *event = [self baseEvent]; + int lockIdentifier = [[RNCWebViewDecisionManager getInstance] setDecisionHandler: ^(BOOL shouldStart){ + dispatch_async(dispatch_get_main_queue(), ^{ + if (!shouldStart) { + decisionHandler(WKNavigationActionPolicyCancel); + return; + } + if (self->_onLoadingStart) { + // We have this check to filter out iframe requests and whatnot + if (isTopFrame) { + NSMutableDictionary *event = [self baseEvent]; + [event addEntriesFromDictionary: @{ + @"url": (request.URL).absoluteString, + @"navigationType": navigationTypes[@(navigationType)] + }]; + self->_onLoadingStart(event); + } + } + + // Allow all navigation by default + decisionHandler(WKNavigationActionPolicyAllow); + }); + + }]; + if (request.mainDocumentURL) { + [event addEntriesFromDictionary: @{ + @"mainDocumentURL": (request.mainDocumentURL).absoluteString, + }]; + } + [event addEntriesFromDictionary: @{ + @"url": (request.URL).absoluteString, + @"navigationType": navigationTypes[@(navigationType)], + @"isTopFrame": @(isTopFrame), + @"lockIdentifier": @(lockIdentifier) + }]; + _onShouldStartLoadWithRequest(event); + // decisionHandler(WKNavigationActionPolicyAllow); + return; } - } - - if (_onLoadingStart) { - // We have this check to filter out iframe requests and whatnot - if (isTopFrame) { - NSMutableDictionary *event = [self baseEvent]; - [event addEntriesFromDictionary: @{ - @"url": (request.URL).absoluteString, - @"navigationType": navigationTypes[@(navigationType)] - }]; - _onLoadingStart(event); + + if (_onLoadingStart) { + // We have this check to filter out iframe requests and whatnot + if (isTopFrame) { + NSMutableDictionary *event = [self baseEvent]; + [event addEntriesFromDictionary: @{ + @"url": (request.URL).absoluteString, + @"navigationType": navigationTypes[@(navigationType)] + }]; + _onLoadingStart(event); + } } - } - - // Allow all navigation by default - decisionHandler(WKNavigationActionPolicyAllow); + + // Allow all navigation by default + decisionHandler(WKNavigationActionPolicyAllow); } /** @@ -1321,7 +1394,7 @@ - (void) webView:(WKWebView *)webView } NSString *disposition = nil; - if (@available(iOS 13, *)) { + if (@available(iOS 13, macOS 10.15, *)) { disposition = [response valueForHTTPHeaderField:@"Content-Disposition"]; } BOOL isAttachment = disposition != nil && [disposition hasPrefix:@"attachment"]; @@ -1449,7 +1522,7 @@ - (void)webView:(WKWebView *)webView if (_ignoreSilentHardwareSwitch) { [self forceIgnoreSilentHardwareSwitch:true]; } - + if (_onLoadingFinish) { _onLoadingFinish([self baseEvent]); } @@ -1457,13 +1530,15 @@ - (void)webView:(WKWebView *)webView - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore { - if(_sharedCookiesEnabled && @available(iOS 11.0, *)) { - // Write all cookies from WKWebView back to sharedHTTPCookieStorage - [cookieStore getAllCookies:^(NSArray* cookies) { - for (NSHTTPCookie *cookie in cookies) { - [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; - } - }]; + if (@available(iOS 11.0, *)) { + if(_sharedCookiesEnabled) { + // Write all cookies from WKWebView back to sharedHTTPCookieStorage + [cookieStore getAllCookies:^(NSArray* cookies) { + for (NSHTTPCookie *cookie in cookies) { + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie]; + } + }]; + } } } @@ -1516,13 +1591,11 @@ - (void)pullToRefresh:(UIRefreshControl *)refreshControl - (void)setPullToRefreshEnabled:(BOOL)pullToRefreshEnabled { _pullToRefreshEnabled = pullToRefreshEnabled; - if (pullToRefreshEnabled) { [self addPullToRefreshControl]; } else { [_refreshControl removeFromSuperview]; } - [self setBounces:_bounces]; } #endif // !TARGET_OS_OSX @@ -1563,19 +1636,24 @@ - (void)setInjectedJavaScript:(NSString *)source { self.atEndScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:_injectedJavaScriptForMainFrameOnly]; - if(_webView != nil){ [self resetupScripts:_webView.configuration]; } } +- (void)setEnableApplePay:(BOOL)enableApplePay { + _enableApplePay = enableApplePay; + if(_webView != nil){ + [self resetupScripts:_webView.configuration]; + } +} + - (void)setInjectedJavaScriptBeforeContentLoaded:(NSString *)source { _injectedJavaScriptBeforeContentLoaded = source; self.atStartScript = source == nil ? nil : [[WKUserScript alloc] initWithSource:source injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:_injectedJavaScriptBeforeContentLoadedForMainFrameOnly]; - if(_webView != nil){ [self resetupScripts:_webView.configuration]; } @@ -1621,22 +1699,28 @@ - (void)setMessagingEnabled:(BOOL)messagingEnabled { - (void)writeCookiesToWebView:(NSArray*)cookies completion:(void (^)(void))completion { // The required cookie APIs only became available on iOS 11 - if(_sharedCookiesEnabled && @available(iOS 11.0, *)) { - dispatch_async(dispatch_get_main_queue(), ^{ - dispatch_group_t group = dispatch_group_create(); - for (NSHTTPCookie *cookie in cookies) { - dispatch_group_enter(group); - [_webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:^{ - dispatch_group_leave(group); - }]; - } - dispatch_group_notify(group, dispatch_get_main_queue(), ^{ - if (completion) { - completion(); + if (@available(iOS 11.0, *)) { + if (_sharedCookiesEnabled) { + __weak WKWebView *webView = _webView; + dispatch_async(dispatch_get_main_queue(), ^{ + dispatch_group_t group = dispatch_group_create(); + for (NSHTTPCookie *cookie in cookies) { + dispatch_group_enter(group); + [webView.configuration.websiteDataStore.httpCookieStore setCookie:cookie completionHandler:^{ + dispatch_group_leave(group); + }]; } + dispatch_group_notify(group, dispatch_get_main_queue(), ^{ + if (completion) { + completion(); + } + }); }); - }); - } else if (completion) { + return; + } + } + + if (completion) { completion(); } } @@ -1713,7 +1797,6 @@ - (void)resetupScripts:(WKWebViewConfiguration *)wkWebViewConfig { [script appendString:@" }\n"]; [script appendString:@"})();\n\n"]; */ - // Set cookies in a direct called function. This ensures that no // javascript error will break the web content javascript. // Generates JS: document.cookie = "key=value; Path=/; Expires=Thu, 01 Jan 20xx 00:00:01 GMT;" diff --git a/apple/RNCWebViewManager.h b/apple/RNCWebViewManager.h index 83ba6eb9e8..af000be5c1 100644 --- a/apple/RNCWebViewManager.h +++ b/apple/RNCWebViewManager.h @@ -1,13 +1,9 @@ -/** - * Copyright (c) 2015-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. - */ +#ifndef RNCWebViewManager_h +#define RNCWebViewManager_h #import @interface RNCWebViewManager : RCTViewManager -@property (nonatomic, copy) NSArray * _Nullable menuItems; -@property (nonatomic, copy) RCTDirectEventBlock onCustomMenuSelection; @end + +#endif /* RNCWebViewManager_h */ diff --git a/apple/RNCWebViewManager.m b/apple/RNCWebViewManager.mm similarity index 55% rename from apple/RNCWebViewManager.m rename to apple/RNCWebViewManager.mm index 24bb78e1e3..40a7eb72a5 100644 --- a/apple/RNCWebViewManager.m +++ b/apple/RNCWebViewManager.mm @@ -1,20 +1,20 @@ -/** - * Copyright (c) 2015-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. - */ +#import #import "RNCWebViewManager.h" - -#import -#import -#import "RNCWebView.h" +#import "RNCWebViewImpl.h" +#import "RNCWebViewDecisionManager.h" #import "RNCWKWebViewMapManager.h" -#import +#ifdef RCT_NEW_ARCH_ENABLED +#import "RNCWebViewSpec/RNCWebViewSpec.h" +#endif -@interface RNCWebViewManager () -@end +#if TARGET_OS_OSX +#define RNCView NSView +@class NSView; +#else +#define RNCView UIView +@class UIView; +#endif // TARGET_OS_OSX @implementation RCTConvert (WKWebView) #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ @@ -36,27 +36,22 @@ @implementation RCTConvert (WKWebView) #endif @end -@implementation RNCWebViewManager -{ - NSConditionLock *_shouldStartLoadLock; - BOOL _shouldStartLoad; + +@implementation RNCWebViewManager { + NSConditionLock *_shouldStartLoadLock; + BOOL _shouldStartLoad; } -RCT_EXPORT_MODULE() +RCT_EXPORT_MODULE(RNCWebView) -#if !TARGET_OS_OSX -- (UIView *)view -#else -- (RCTUIView *)view -#endif // !TARGET_OS_OSX +- (RNCView *)view { - RNCWebView *webView = [RNCWebView new]; - webView.delegate = self; - webView.bridge = self.bridge; - return webView; + return [[RNCWebViewImpl alloc] init]; } RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary) +// New arch only +RCT_CUSTOM_VIEW_PROPERTY(newSource, NSDictionary, RNCWebViewImpl) {} RCT_EXPORT_VIEW_PROPERTY(onFileDownload, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock) @@ -74,11 +69,10 @@ - (RCTUIView *)view RCT_EXPORT_VIEW_PROPERTY(allowFileAccessFromFileURLs, BOOL) RCT_EXPORT_VIEW_PROPERTY(allowUniversalAccessFromFileURLs, BOOL) RCT_EXPORT_VIEW_PROPERTY(allowsInlineMediaPlayback, BOOL) +RCT_EXPORT_VIEW_PROPERTY(webviewDebuggingEnabled, BOOL) RCT_EXPORT_VIEW_PROPERTY(allowsAirPlayForMediaPlayback, BOOL) RCT_EXPORT_VIEW_PROPERTY(mediaPlaybackRequiresUserAction, BOOL) -#if WEBKIT_IOS_10_APIS_AVAILABLE RCT_EXPORT_VIEW_PROPERTY(dataDetectorTypes, WKDataDetectorTypes) -#endif RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets) RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL) RCT_EXPORT_VIEW_PROPERTY(autoManageStatusBarEnabled, BOOL) @@ -91,7 +85,6 @@ - (RCTUIView *)view RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL) RCT_EXPORT_VIEW_PROPERTY(allowingReadAccessToURL, NSString) RCT_EXPORT_VIEW_PROPERTY(basicAuthCredential, NSDictionary) -RCT_EXPORT_VIEW_PROPERTY(ignoreSilentHardwareSwitch, BOOL) #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ RCT_EXPORT_VIEW_PROPERTY(contentInsetAdjustmentBehavior, UIScrollViewContentInsetAdjustmentBehavior) @@ -116,8 +109,9 @@ - (RCTUIView *)view RCT_EXPORT_VIEW_PROPERTY(mediaCapturePermissionGrantType, RNCWebViewPermissionGrantType) #endif -RCT_EXPORT_VIEW_PROPERTY(webViewKey, NSString) -RCT_EXPORT_VIEW_PROPERTY(temporaryParentNodeTag, NSNumber) +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 /* iOS 13 */ +RCT_EXPORT_VIEW_PROPERTY(fraudulentWebsiteWarningEnabled, BOOL) +#endif /** * Expose methods to enable messaging the webview. @@ -127,76 +121,107 @@ - (RCTUIView *)view RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(enableApplePay, BOOL) RCT_EXPORT_VIEW_PROPERTY(menuItems, NSArray); +// New arch only +RCT_CUSTOM_VIEW_PROPERTY(hasOnFileDownload, BOOL, RNCWebViewImpl) {} RCT_EXPORT_VIEW_PROPERTY(onCustomMenuSelection, RCTDirectEventBlock) - -RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view postMessage:message]; - } - }]; -} - -RCT_CUSTOM_VIEW_PROPERTY(pullToRefreshEnabled, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(pullToRefreshEnabled, BOOL, RNCWebViewImpl) { view.pullToRefreshEnabled = json == nil ? false : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(bounces, BOOL, RNCWebViewImpl) { view.bounces = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(useSharedProcessPool, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(useSharedProcessPool, BOOL, RNCWebViewImpl) { view.useSharedProcessPool = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(userAgent, NSString, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(userAgent, NSString, RNCWebViewImpl) { view.userAgent = [RCTConvert NSString: json]; } -RCT_CUSTOM_VIEW_PROPERTY(scrollEnabled, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(webViewKey, NSString, RNCWebViewImpl) { + view.webViewKey = [RCTConvert NSString: json]; +} + +RCT_CUSTOM_VIEW_PROPERTY(temporaryParentNodeTag, NSNumber, RNCWebViewImpl) { + view.temporaryParentNodeTag = [RCTConvert NSNumber: json]; +} + +RCT_CUSTOM_VIEW_PROPERTY(scrollEnabled, BOOL, RNCWebViewImpl) { view.scrollEnabled = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(sharedCookiesEnabled, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(sharedCookiesEnabled, BOOL, RNCWebViewImpl) { view.sharedCookiesEnabled = json == nil ? false : [RCTConvert BOOL: json]; } #if !TARGET_OS_OSX -RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(decelerationRate, CGFloat, RNCWebViewImpl) { view.decelerationRate = json == nil ? UIScrollViewDecelerationRateNormal : [RCTConvert CGFloat: json]; } #endif // !TARGET_OS_OSX -RCT_CUSTOM_VIEW_PROPERTY(directionalLockEnabled, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(directionalLockEnabled, BOOL, RNCWebViewImpl) { view.directionalLockEnabled = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(showsHorizontalScrollIndicator, BOOL, RNCWebViewImpl) { view.showsHorizontalScrollIndicator = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL, RNCWebViewImpl) { view.showsVerticalScrollIndicator = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_CUSTOM_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, BOOL, RNCWebView) { +RCT_CUSTOM_VIEW_PROPERTY(keyboardDisplayRequiresUserAction, BOOL, RNCWebViewImpl) { view.keyboardDisplayRequiresUserAction = json == nil ? true : [RCTConvert BOOL: json]; } -RCT_EXPORT_METHOD(injectJavaScript:(nonnull NSNumber *)reactTag script:(NSString *)script) +#if !TARGET_OS_OSX + #define BASE_VIEW_PER_OS() UIView +#else + #define BASE_VIEW_PER_OS() NSView +#endif + +#define QUICK_RCT_EXPORT_COMMAND_METHOD(name) \ +RCT_EXPORT_METHOD(name:(nonnull NSNumber *)reactTag) \ +{ \ +[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { \ + RNCWebViewImpl *view = (RNCWebViewImpl *)viewRegistry[reactTag]; \ + if (![view isKindOfClass:[RNCWebViewImpl class]]) { \ + RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); \ + } else { \ + [view name]; \ + } \ + }]; \ +} +#define QUICK_RCT_EXPORT_COMMAND_METHOD_PARAMS(name, in_param, out_param) \ +RCT_EXPORT_METHOD(name:(nonnull NSNumber *)reactTag in_param) \ +{ \ +[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { \ + RNCWebViewImpl *view = (RNCWebViewImpl *)viewRegistry[reactTag]; \ + if (![view isKindOfClass:[RNCWebViewImpl class]]) { \ + RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); \ + } else { \ + [view name:out_param]; \ + } \ + }]; \ +} + +QUICK_RCT_EXPORT_COMMAND_METHOD(reload) +QUICK_RCT_EXPORT_COMMAND_METHOD(goBack) +QUICK_RCT_EXPORT_COMMAND_METHOD(goForward) +QUICK_RCT_EXPORT_COMMAND_METHOD(stopLoading) +QUICK_RCT_EXPORT_COMMAND_METHOD(requestFocus) + +QUICK_RCT_EXPORT_COMMAND_METHOD_PARAMS(postMessage, message:(NSString *)message, message) +QUICK_RCT_EXPORT_COMMAND_METHOD_PARAMS(injectJavaScript, script:(NSString *)script, script) + +RCT_EXPORT_METHOD(shouldStartLoadWithLockIdentifier:(BOOL)shouldStart + lockIdentifier:(double)lockIdentifier) { - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view injectJavaScript:script]; - } - }]; + [[RNCWebViewDecisionManager getInstance] setResult:shouldStart forLockIdentifier:(int)lockIdentifier]; } RCT_EXPORT_METHOD(injectJavaScriptWithWebViewKey:(nonnull NSString *)webViewKey @@ -204,7 +229,7 @@ - (RCTUIView *)view resolve:(RCTPromiseResolveBlock) resolve reject: (RCTPromiseRejectBlock)reject) { - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary *viewRegistry) { + [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { NSMutableDictionary *sharedWKWebViewDictionary = [[RNCWKWebViewMapManager sharedManager] sharedWKWebViewDictionary]; WKWebView *wkWebView = sharedWKWebViewDictionary[webViewKey]; @@ -221,111 +246,17 @@ - (RCTUIView *)view }]; } -RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view goBack]; - } - }]; -} - -RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view goForward]; - } - }]; -} - -RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view reload]; - } - }]; -} - -RCT_EXPORT_METHOD(stopLoading:(nonnull NSNumber *)reactTag) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view stopLoading]; - } - }]; -} - -RCT_EXPORT_METHOD(requestFocus:(nonnull NSNumber *)reactTag) -{ - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { - RNCWebView *view = viewRegistry[reactTag]; - if (![view isKindOfClass:[RNCWebView class]]) { - RCTLogError(@"Invalid view returned from registry, expecting RNCWebView, got: %@", view); - } else { - [view requestFocus]; - } - }]; -} - -#pragma mark - Exported synchronous methods - -- (BOOL) webView:(RNCWebView *)webView -shouldStartLoadForRequest:(NSMutableDictionary *)request - withCallback:(RCTDirectEventBlock)callback -{ - _shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()]; - _shouldStartLoad = YES; - request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition); - callback(request); - - // Block the main thread for a maximum of 250ms until the JS thread returns - if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) { - BOOL returnValue = _shouldStartLoad; - [_shouldStartLoadLock unlock]; - _shouldStartLoadLock = nil; - return returnValue; - } else { - RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES"); - return YES; - } -} - -RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier) -{ - if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) { - _shouldStartLoad = result; - [_shouldStartLoadLock unlockWithCondition:0]; - } else { - RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: " - "got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition); - } -} - RCT_EXPORT_METHOD(releaseWebView:(nonnull NSString *)webViewKey) { - [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, __unused NSDictionary *viewRegistry) { + [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) { NSMutableDictionary *sharedWKWebViewDictionary = [[RNCWKWebViewMapManager sharedManager] sharedWKWebViewDictionary]; WKWebView *wkWebView = sharedWKWebViewDictionary[webViewKey]; if (wkWebView != nil) { UIView *parentView = wkWebView.superview; if (parentView != nil) { - if ([parentView isKindOfClass:[RNCWebView class]]) { - [(RNCWebView*)parentView cleanUpWebView]; + if ([parentView isKindOfClass:[RNCWebViewImpl class]]) { + [(RNCWebViewImpl*)parentView cleanUpWebView]; } else { // Remove WkWebView from temporary parent if (wkWebView != nil) { @@ -339,4 +270,14 @@ - (BOOL) webView:(RNCWebView *)webView }]; } + +// Thanks to this guard, we won't compile this code when we build for the old architecture. +#ifdef RCT_NEW_ARCH_ENABLED +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} +#endif + @end diff --git a/bin/setup b/bin/setup deleted file mode 100755 index 38212df6c7..0000000000 --- a/bin/setup +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/bash - -# Node installed? -if ! [ -x "$(command -v node)" ]; then - echo 'Error: node is not installed.' >&2 - - if ! [ -x "$(command -v brew)" ]; then - echo 'Go here to install: https://nodejs.org/en/download/' - fi - - if [ -x "$(command -v brew)" ]; then - echo 'You have Homebrew installed, so run "brew install node".' - fi - - exit 1 -fi - -# React Native installed? -if ! [ -x "$(command -v react-native)" ]; then - echo 'Error: React Native is not installed.' >&2 - echo 'Go here: https://reactnative.dev/docs/getting-started.html' >&2 - echo 'Use the "Building Projects With Native Code" option.' - exit 1 -fi - -# TODO: Automate setup on new machines diff --git a/docs/Contributing.md b/docs/Contributing.md index 90669bb32b..a8db1b1788 100644 --- a/docs/Contributing.md +++ b/docs/Contributing.md @@ -59,8 +59,7 @@ The Windows example app will be built, the Metro bundler will launch, and the ex In a new `react-native init` project, do this: ``` -$ yarn add ../react-native-webview -$ react-native link react-native-webview +$ yarn add ``` You may run into a problem where the `jest-haste-map` module map says react-native was added twice: @@ -83,11 +82,15 @@ And then re-run the packager: $ react-native start --reset-cache ``` -When you make a change, you'll probably need to unlink, remove, re-add, and re-link `react-native-webview`: +You may also see a console warning about "Invalid hook call," followed by a render error that "null is not an object (evaluating 'dispatcher.useRef')." Resolving this is similar to the above, but this time remove `react-native-webview/node_modules/react`. + +(if you remove `react` before `react-native`, you may see another render error for "View config getter callback for component 'RNCWebView' must be a function," just remove `react-native` as well to fix this) + +When you make a change, you'll probably need to remove and re-add `react-native-webview`: ``` -$ react-native unlink react-native-webview && yarn remove react-native-webview -$ yarn add ../react-native-webview && react-native link react-native-webview +$ yarn remove react-native-webview +$ yarn add ../react-native-webview ``` ## Notes diff --git a/docs/Custom-Android.md b/docs/Custom-Android.md index e873e9060a..47a3873e64 100644 --- a/docs/Custom-Android.md +++ b/docs/Custom-Android.md @@ -25,8 +25,8 @@ public class CustomWebViewManager extends RNCWebViewManager { } @Override - protected RNCWebView createRNCWebViewInstance(ThemedReactContext reactContext) { - return new CustomWebView(reactContext); + protected RNCWebView createViewInstance(ThemedReactContext reactContext) { + return super.createViewInstance(reactContext, new CustomWebView(reactContext)); } @Override @@ -35,7 +35,7 @@ public class CustomWebViewManager extends RNCWebViewManager { } @Override - protected void addEventEmitters(ThemedReactContext reactContext, WebView view) { + protected void addEventEmitters(ThemedReactContext reactContext, RNCWebView view) { view.setWebViewClient(new CustomWebViewClient()); } } diff --git a/docs/Guide.md b/docs/Guide.md index 8dfdea8de7..8715072fea 100644 --- a/docs/Guide.md +++ b/docs/Guide.md @@ -482,7 +482,7 @@ In React Native WebView, you can set a custom header like this: This will set the header on the first load, but not on subsequent page navigations. -In order to work around this, you can track the current URL, intercept new page loads, and navigate to them yourself ([original credit for this technique to Chirag Shah from Big Binary](https://blog.bigbinary.com/2016/07/26/passing-request-headers-on-each-webview-request-in-react-native.html)): +In order to work around this, you can track the current URL, intercept new page loads, and navigate to them yourself ([original credit for this technique to Chirag Shah from Big Binary](https://www.bigbinary.com/blog/passing-request-headers-on-each-webview-request-in-react-native)): ```jsx const CustomHeaderWebView = (props) => { @@ -610,4 +610,4 @@ Video on `iOS` will always ignore the hardware silence switch. This file is available at: -- [Brazilian portuguese](Guide.portuguese.md) \ No newline at end of file +- [Brazilian portuguese](Guide.portuguese.md) diff --git a/docs/README.french.md b/docs/README.french.md index 0e5f30d2df..da434e85cd 100644 --- a/docs/README.french.md +++ b/docs/README.french.md @@ -1,81 +1,63 @@ +# React Native WebView -# React Native WebView - Une WebView moderne et multiplateforme pour React Native - -[![star this repo](http://githubbadges.com/star.svg?user=react-native-webview&repo=react-native-webview&style=flat)](https://github.com/react-native-webview/react-native-webview) +![star this repo](https://img.shields.io/github/stars/react-native-webview/react-native-webview?style=flat-square) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors) -[![Known Vulnerabilities](https://snyk.io/test/github/react-native-webview/react-native-webview/badge.svg?style=flat-square)](https://snyk.io/test/github/react-native-webview/react-native-webview) [![NPM Version](https://img.shields.io/npm/v/react-native-webview.svg?style=flat-square)](https://www.npmjs.com/package/react-native-webview) -[![Lean Core Extracted](https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg?style=flat-square)][lean-core-issue] - -**React Native WebView** est une WebView moderne, soutenue et multiplateforme pour React Native. Elle est destinée à remplacer la WebView built-in (qui va être [retiré du noyau](https://github.com/react-native-community/discussions-and-proposals/pull/3)). +![Npm Downloads](https://img.shields.io/npm/dm/react-native-webview.svg) -## Mainteneurs principaux - Compagnies sponsors +**React Native WebView** est un composent WebView maintenu par la communauté. Il existe en remplacement au composant WebView de React Native (qui a [été retiré du core](https://github.com/react-native-community/discussions-and-proposals/pull/3)). -_Ce projet est maintenu gratuitement par ces personnes durant leur temps libre et leur temps de travail._ +### Contributeurs -- [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) de [Brigad](https://brigad.co/about) -- [Jamon Holmgren](https://github.com/jamonholmgren) ([Twitter @jamonholmgren](https://twitter.com/jamonholmgren)) de [Infinite Red](https://infinite.red/react-native) -- [Alexander Sklar](https://github.com/asklar) ([Twitter @alexsklar](https://twitter.com/alexsklar)) de [React Native Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) -- [Chiara Mooney](https://github.com/chiaramooney) de [React Native Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) +**Merci beaucoup aux entreprises** pour nous permettre de travailler sur de l'open source. +Également beaucoup de temps personnel est investi pour maintenir ce projet, n'hésitez pas à nous sponsoriser, **ça aide vraiment.** -## Plateformes supportées +- [Thibault Malbranche](https://github.com/Titozzz) ([Twitter @titozzz](https://twitter.com/titozzz)) de [Brigad](https://www.brigad.co/fr-fr/about-us) +[*Me Sponsor* ❤️ !](https://github.com/sponsors/Titozzz) -- [x] iOS -- [x] Android -- [x] macOS -- [x] Windows +Windows et macOS sont maintenues par Microsoft, notamment: +- [Alexander Sklar](https://github.com/asklar) ([Twitter @alexsklar](https://twitter.com/alexsklar)) de [React Native for Windows](https://microsoft.github.io/react-native-windows/) +- [Chiara Mooney](https://github.com/chiaramooney) de [React Native for Windows @ Microsoft](https://microsoft.github.io/react-native-windows/) -_Note: Le support de React Native WebView par Expo a débuté avec [Expo SDK v33.0.0](https://blog.expo.io/expo-sdk-v33-0-0-is-now-available-52d1c99dfe4c)._ +Grand merci à [Jamon Holmgren](https://github.com/jamonholmgren) de [Infinite Red](https://infinite.red) pour l'aide apportée lorsqu'il avait plus de temps disponible. -## Débuter +### Disclaimer -Lisez attentivement notre guide (exclusivement en anglais) [Getting Started Guide](docs/Getting-Started.md). Si la moindre étape ne semble pas claire, merci de créer une **issue** détaillée. +Maintenir la WebView est très compliqué, à cause de ses nombreux usages (rendering svgs, pdfs, login flows, et autres). On supporte également de nombreuses plateformes et les deux architectures de React Native. -## Versionnage +Depuis que la WebView a été retirée du core, près de 500 PR ont été mergées. +En considérant que nous possédons un temps limité, les issues github serviront principalement comme lieu d'échange pour la communauté, tandis que **nous prioriserons les reviews et les merges de pull requests** -Ce projet suit la [gestion sémantique de version](https://semver.org/). Nous n'hésitons pas à publier des modifications "breaking-change", mais elles seront intégrées dans une version majeure. +### Platform compatibles +Ce projet est compatible avec **iOS**, **Android**, **Windows** et **macOS**. +Ce projet supporte à la fois **l'ancienne** (paper) **et la nouvelle architecture** (fabric). +Ce projet est compatible avec [expo](https://docs.expo.dev/versions/latest/sdk/webview/). +## Débuter -**Historique des versions majeures:** - -Current Version: ![version](https://img.shields.io/npm/v/react-native-webview.svg) - -- [11.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v11.0.0) - Android setSupportMultipleWindows. -- [10.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v10.0.0) - Le plugin Android Gradle n'est obligatoire qu'en ouvrant le projet en mode **stand-alone** -- [9.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v9.0.0) - Les mises à jour des props via injectedJavaScript ne sont plus immuables -- [8.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v8.0.0) - Désormais onNavigationStateChange se déclenche au changement du hash de l'url -- [7.0.1](https://github.com/react-native-webview/react-native-webview/releases/tag/v7.0.1) - Suppression de UIWebView -- [6.0.**2**](https://github.com/react-native-webview/react-native-webview/releases/tag/v6.0.2) - Mise à jour d'AndroidX. Soyez attentif à l'activer dans vos projet via `android/gradle.properties`. Voir [Getting Started Guide](docs/Getting-Started.md). -- [5.0.**1**](https://github.com/react-native-webview/react-native-webview/releases/tag/v5.0.0) - Remaniement de l'ancienne implémentation de postMessage pour communiquer de la webview à react native. -- [4.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v4.0.0) - Ajout d'un cache (activé par défaut). -- [3.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v3.0.0) - WKWebview : Ajout d'un pool de processus partagé pour que les cookies et localStorage soient partagés entre les webviews dans iOS (activé par défaut). -- [2.0.0](https://github.com/react-native-webview/react-native-webview/releases/tag/v2.0.0) - Première version, il s'agit d'une réplique du composant webview de base. +Lisez attentivement notre guide (exclusivement en anglais) [Getting Started Guide](docs/Getting-Started.md). Si la moindre étape ne semble pas claire, merci de créer une **issue** détaillée. -**A venir:** +## Versionnage -- Suppression de this.webView.postMessage() (jamais documenté et moins dynamique que injectJavascript) -> [comment migrer](https://github.com/react-native-webview/react-native-webview/issues/809) -- Réécriture du code Kotlin -- Peut-être réécrutire du code Swift +Ce projet suit la [gestion sémantique de version](https://semver.org/). Nous n'hésitons pas à publier des modifications "breaking-change", mais elles seront intégrées dans une version majeure. ## Utilisation Importez le composant `WebView` de `react-native-webview` et utilisez le de la manière suivante : -```jsx +```tsx import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { WebView } from 'react-native-webview'; // ... -class MyWebComponent extends Component { - render() { - return ; - } +const MyWebComponent = () => { + return ; } ``` + Pour plus de détails, lisez la [Référence API](./docs/Reference.md) et le [Guide](./docs/Guide.md). Si vous êtes intéressé à contribuer, lisez le [Guide de contribution](./docs/Contributing.md). ## Problèmes communs @@ -87,28 +69,9 @@ Pour plus de détails, lisez la [Référence API](./docs/Reference.md) et le [Gu Voir [Contributing.md](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Contributing.md) -## Contributeurs - -Un grand remerciement aux contributeurs ([emoji key](https://github.com/all-contributors/all-contributors#emoji-key-)): - - - -
Thibault Malbranche
Thibault Malbranche

💻 🤔 👀 📖 🚧 ⚠️ 🚇 💬
Jamon Holmgren
Jamon Holmgren

💻 🤔 👀 📖 🚧 ⚠️ 💡 💬
Andrei Pfeiffer
Andrei Pfeiffer

💻 👀 🤔
Michael Diarmid
Michael Diarmid

💻 👀 🤔 🔧
Scott Mathson
Scott Mathson

💻 📖
Margaret
Margaret

💻 📖
Jordan Sexton
Jordan Sexton

💻 📖
Malcolm Scruggs
Malcolm Scruggs

💻 🔧 ⚠️
Momazo7u7
Momazo7u7

📖
Marco
Marco

📖
Julien Eluard
Julien Eluard

📖
Jian Wei
Jian Wei

💻 📖
Sergei Butko
Sergei Butko

📖
TMomemt
TMomemt

💻
Eric Lewis
Eric Lewis

💻 📖
Daniel Vicory
Daniel Vicory

💻 📖
- - - - -Ce projet suit les spécifications [all-contributors](https://github.com/all-contributors/all-contributors). Les contributions de toute nature sont les bienvenues ! - -## License - -MIT - ## Translations This readme is available in: - [English](../README.md) - [Brazilian portuguese](README.portuguese.md) - -[lean-core-issue]: https://github.com/facebook/react-native/issues/23313 diff --git a/docs/Reference.md b/docs/Reference.md index b3157ed238..5b78890d81 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -36,7 +36,6 @@ This document lays out the current public properties and methods for the React N - [`domStorageEnabled`](Reference.md#domstorageenabled) - [`javaScriptEnabled`](Reference.md#javascriptenabled) - [`javaScriptCanOpenWindowsAutomatically`](Reference.md#javascriptcanopenwindowsautomatically) -- [`androidHardwareAccelerationDisabled`](Reference.md#androidHardwareAccelerationDisabled) - [`androidLayerType`](Reference.md#androidLayerType) - [`mixedContentMode`](Reference.md#mixedcontentmode) - [`thirdPartyCookiesEnabled`](Reference.md#thirdpartycookiesenabled) @@ -60,8 +59,6 @@ This document lays out the current public properties and methods for the React N - [`allowFileAccessFromFileURLs`](Reference.md#allowFileAccessFromFileURLs) - [`allowUniversalAccessFromFileURLs`](Reference.md#allowUniversalAccessFromFileURLs) - [`allowingReadAccessToURL`](Reference.md#allowingReadAccessToURL) -- [`url`](Reference.md#url) -- [`html`](Reference.md#html) - [`keyboardDisplayRequiresUserAction`](Reference.md#keyboardDisplayRequiresUserAction) - [`hideKeyboardAccessoryView`](Reference.md#hidekeyboardaccessoryview) - [`allowsBackForwardNavigationGestures`](Reference.md#allowsbackforwardnavigationgestures) @@ -90,6 +87,7 @@ This document lays out the current public properties and methods for the React N - [`downloadingMessage`](Reference.md#downloadingMessage) - [`lackPermissionToDownloadMessage`](Reference.md#lackPermissionToDownloadMessage) - [`allowsProtectedMedia`](Reference.md#allowsProtectedMedia) +- [`webviewDebuggingEnabled`](Reference.md#webviewDebuggingEnabled) ## Methods Index @@ -110,7 +108,7 @@ This document lays out the current public properties and methods for the React N ## Props -### `source`[⬆](#props-index) +### `source`[⬆](#props-index) Loads static HTML or a URI (with optional headers) in the WebView. Note that static HTML will require setting [`originWhitelist`](Reference.md#originwhitelist) to `["*"]`. @@ -136,7 +134,7 @@ _Note that using static HTML requires the WebView property [originWhiteList](Ref --- -### `automaticallyAdjustContentInsets`[⬆](#props-index) +### `automaticallyAdjustContentInsets`[⬆](#props-index) Controls whether to adjust the content inset for web views that are placed behind a navigation bar, tab bar, or toolbar. The default value is `true`. @@ -146,7 +144,7 @@ Controls whether to adjust the content inset for web views that are placed behin --- -### `automaticallyAdjustsScrollIndicatorInsets`[⬆](#props-index) +### `automaticallyAdjustsScrollIndicatorInsets`[⬆](#props-index) Controls whether to adjust the scroll indicator inset for web views that are placed behind a navigation bar, tab bar, or toolbar. The default value `false`. (iOS 13+) @@ -156,7 +154,7 @@ Controls whether to adjust the scroll indicator inset for web views that are pla --- -### `injectedJavaScript`[⬆](#props-index) +### `injectedJavaScript`[⬆](#props-index) Set this to provide JavaScript that will be injected into the web page after the document finishes loading, but before other subresources finish loading. @@ -191,7 +189,7 @@ const INJECTED_JAVASCRIPT = `(function() { --- -### `injectedJavaScriptBeforeContentLoaded`[⬆](#props-index) +### `injectedJavaScriptBeforeContentLoaded`[⬆](#props-index) Set this to provide JavaScript that will be injected into the web page after the document element is created, but before other subresources finish loading. @@ -226,7 +224,7 @@ const INJECTED_JAVASCRIPT = `(function() { --- -### `injectedJavaScriptForMainFrameOnly`[⬆](#props-index) +### `injectedJavaScriptForMainFrameOnly`[⬆](#props-index) If `true` (default; mandatory for Android), loads the `injectedJavaScript` only into the main frame. @@ -238,7 +236,7 @@ If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. if --- -### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`[⬆](#props-index) +### `injectedJavaScriptBeforeContentLoadedForMainFrameOnly`[⬆](#props-index) If `true` (default; mandatory for Android), loads the `injectedJavaScriptBeforeContentLoaded` only into the main frame. @@ -250,7 +248,7 @@ If `false`, (only supported on iOS and macOS), loads it into all frames (e.g. if --- -### `mediaPlaybackRequiresUserAction`[⬆](#props-index) +### `mediaPlaybackRequiresUserAction`[⬆](#props-index) Boolean that determines whether HTML5 audio and video requires the user to tap them before they start playing. The default value is `true`. (Android API minimum version 17). @@ -262,7 +260,7 @@ NOTE: the default `true` value might cause some videos to hang loading on iOS. S --- -### `nativeConfig`[⬆](#props-index) +### `nativeConfig`[⬆](#props-index) Override the native component used to render the WebView. Enables a custom native WebView which uses the same JavaScript as the original WebView. @@ -278,7 +276,7 @@ The `nativeConfig` prop expects an object with the following keys: --- -### `onError`[⬆](#props-index) +### `onError`[⬆](#props-index) Function that is invoked when the `WebView` load fails. @@ -320,7 +318,7 @@ The `syntheticEvent` can be stopped doing its default action by calling `synthet --- -### `onLoad`[⬆](#props-index) +### `onLoad`[⬆](#props-index) Function that is invoked when the `WebView` has finished loading. @@ -353,7 +351,7 @@ url --- -### `onLoadEnd`[⬆](#props-index) +### `onLoadEnd`[⬆](#props-index) Function that is invoked when the `WebView` load succeeds or fails. @@ -387,7 +385,7 @@ url --- -### `onLoadStart`[⬆](#props-index) +### `onLoadStart`[⬆](#props-index) Function that is invoked when the `WebView` starts loading. @@ -421,7 +419,7 @@ url --- -### `onLoadProgress`[⬆](#props-index) +### `onLoadProgress`[⬆](#props-index) Function that is invoked when the `WebView` is loading. @@ -454,7 +452,7 @@ url --- -### `onHttpError`[⬆](#props-index) +### `onHttpError`[⬆](#props-index) Function that is invoked when the `WebView` receives an http error. @@ -498,7 +496,7 @@ url --- -### `onRenderProcessGone`[⬆](#props-index) +### `onRenderProcessGone`[⬆](#props-index) Function that is invoked when the `WebView` process crashes or is killed by the OS on Android. @@ -531,7 +529,7 @@ didCrash ``` --- -### `onMessage`[⬆](#props-index) +### `onMessage`[⬆](#props-index) Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`. Setting this property will inject this global into your webview. @@ -545,7 +543,7 @@ To learn more, read the [Communicating between JS and Native](Guide.md#communica --- -### `onNavigationStateChange`[⬆](#props-index) +### `onNavigationStateChange`[⬆](#props-index) Function that is invoked when the `WebView` loading starts or ends. @@ -579,15 +577,15 @@ url --- -### `onContentProcessDidTerminate`[⬆](#props-index) +### `onContentProcessDidTerminate`[⬆](#props-index) -Function that is invoked when the `WebView` content process is terminated. +Function that is invoked when the `WebView` content process is terminated. | Type | Required | Platform | | -------- | -------- | ----------------------- | | function | No | iOS and macOS WKWebView | -iOS Web views use a separate process to render and manage web content. WebKit calls this method when the process for the specified web view terminates for any reason. +iOS Web views use a separate process to render and manage web content. WebKit calls this method when the process for the specified web view terminates for any reason. The reason is not necessarily a crash. For instance, since iOS WebViews are not included in the total RAM of the app, they can be terminated independently of the app to liberate memory for new apps the user is opening. It's not unexpected to have WebViews get terminated after a while in the background. Example: @@ -616,7 +614,7 @@ url --- -### `onScroll`[⬆](#props-index) +### `onScroll`[⬆](#props-index) Function that is invoked when the scroll event is fired in the `WebView`. @@ -649,7 +647,7 @@ zoomScale --- -### `originWhitelist`[⬆](#props-index) +### `originWhitelist`[⬆](#props-index) List of origin strings to allow being navigated to. The strings allow wildcards and get matched against _just_ the origin (not the full URL). If the user taps to navigate to a new page but the new page is not in this whitelist, the URL will be handled by the OS. The default whitelisted origins are "http://*" and "https://*". @@ -669,7 +667,7 @@ Example: --- -### `renderError`[⬆](#props-index) +### `renderError`[⬆](#props-index) Function that returns a view to show if there's an error. @@ -690,7 +688,7 @@ The function passed to `renderError` will be called with the name of the error --- -### `renderLoading`[⬆](#props-index) +### `renderLoading`[⬆](#props-index) Function that returns a loading indicator. The startInLoadingState prop must be set to true in order to use this prop. @@ -710,7 +708,7 @@ Example: --- -### `scalesPageToFit`[⬆](#props-index) +### `scalesPageToFit`[⬆](#props-index) Boolean that controls whether the web content is scaled to fit the view and enables the user to change the scale. The default value is `true`. @@ -720,7 +718,7 @@ Boolean that controls whether the web content is scaled to fit the view and enab --- -### `onShouldStartLoadWithRequest`[⬆](#props-index) +### `onShouldStartLoadWithRequest`[⬆](#props-index) Function that allows custom handling of any web view requests. Return `true` from the function to continue loading the request and `false` to stop loading. @@ -759,7 +757,7 @@ isTopFrame (iOS only) --- -### `startInLoadingState`[⬆](#props-index) +### `startInLoadingState`[⬆](#props-index) Boolean value that forces the `WebView` to show the loading view on the first load. This prop must be set to `true` in order for the `renderLoading` prop to work. @@ -769,7 +767,7 @@ Boolean value that forces the `WebView` to show the loading view on the first lo --- -### `style`[⬆](#props-index) +### `style`[⬆](#props-index) A style object that allow you to customize the `WebView` style. Please note that there are default styles (example: you need to add `flex: 0` to the style if you want to use `height` property). @@ -788,7 +786,7 @@ Example: --- -### `containerStyle`[⬆](#props-index) +### `containerStyle`[⬆](#props-index) A style object that allow you to customize the `WebView` container style. Please note that there are default styles (example: you need to add `flex: 0` to the style if you want to use `height` property). @@ -807,7 +805,7 @@ Example: --- -### `decelerationRate`[⬆](#props-index) +### `decelerationRate`[⬆](#props-index) A floating-point number that determines how quickly the scroll view decelerates after the user lifts their finger. You may also use the string shortcuts `"normal"` and `"fast"` which match the underlying iOS settings for `UIScrollViewDecelerationRateNormal` and `UIScrollViewDecelerationRateFast` respectively: @@ -820,7 +818,7 @@ A floating-point number that determines how quickly the scroll view decelerates --- -### `domStorageEnabled`[⬆](#props-index) +### `domStorageEnabled`[⬆](#props-index) Boolean value to control whether DOM Storage is enabled. Used only in Android. @@ -830,7 +828,7 @@ Boolean value to control whether DOM Storage is enabled. Used only in Android. --- -### `javaScriptEnabled`[⬆](#props-index) +### `javaScriptEnabled`[⬆](#props-index) Boolean value to enable JavaScript in the `WebView`. The default value is `true`. @@ -840,7 +838,7 @@ Boolean value to enable JavaScript in the `WebView`. The default value is `true` --- -### `javaScriptCanOpenWindowsAutomatically`[⬆](#props-index) +### `javaScriptCanOpenWindowsAutomatically`[⬆](#props-index) A Boolean value indicating whether JavaScript can open windows without user interaction. The default value is `false`. @@ -850,17 +848,7 @@ A Boolean value indicating whether JavaScript can open windows without user inte --- -### `androidHardwareAccelerationDisabled`[⬆](#props-index) - -**Deprecated.** Use the `androidLayerType` prop instead. - -| Type | Required | Platform | -| ---- | -------- | -------- | -| bool | No | Android | - ---- - -### `androidLayerType`[⬆](#props-index) +### `androidLayerType`[⬆](#props-index) Specifies the layer type. @@ -870,7 +858,6 @@ Possible values for `androidLayerType` are: - `software` - The view has a software layer. A software layer is backed by a bitmap and causes the view to be rendered using Android's software rendering pipeline, even if hardware acceleration is enabled. - `hardware` - The view has a hardware layer. A hardware layer is backed by a hardware specific texture and causes the view to be rendered using Android's hardware rendering pipeline, but only if hardware acceleration is turned on for the view hierarchy. -Avoid setting both `androidLayerType` and `androidHardwareAccelerationDisabled` props at the same time, as this may cause undefined behaviour. | Type | Required | Platform | | ------ | -------- | -------- | @@ -878,7 +865,7 @@ Avoid setting both `androidLayerType` and `androidHardwareAccelerationDisabled` --- -### `mixedContentMode`[⬆](#props-index) +### `mixedContentMode`[⬆](#props-index) Specifies the mixed content mode. i.e WebView will allow a secure origin to load content from any other origin. @@ -894,7 +881,7 @@ Possible values for `mixedContentMode` are: --- -### `thirdPartyCookiesEnabled`[⬆](#props-index) +### `thirdPartyCookiesEnabled`[⬆](#props-index) Boolean value to enable third party cookies in the `WebView`. Used on Android Lollipop and above only as third party cookies are enabled by default on Android Kitkat and below and on iOS. The default value is `true`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies) @@ -904,7 +891,7 @@ Boolean value to enable third party cookies in the `WebView`. Used on Android Lo --- -### `userAgent`[⬆](#props-index) +### `userAgent`[⬆](#props-index) Sets the user-agent for the `WebView`. @@ -914,7 +901,7 @@ Sets the user-agent for the `WebView`. --- -### `applicationNameForUserAgent`[⬆](#props-index) +### `applicationNameForUserAgent`[⬆](#props-index) Append to the existing user-agent. Setting `userAgent` will override this. @@ -932,7 +919,7 @@ Append to the existing user-agent. Setting `userAgent` will override this. // Mozilla/5.0 (iPhone; CPU iPhone OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 DemoApp/1.1.0 ``` -### `allowsFullscreenVideo`[⬆](#props-index) +### `allowsFullscreenVideo`[⬆](#props-index) Boolean that determines whether videos are allowed to be played in fullscreen. The default value is `false`. @@ -942,7 +929,7 @@ Boolean that determines whether videos are allowed to be played in fullscreen. T --- -### `allowsInlineMediaPlayback`[⬆](#props-index) +### `allowsInlineMediaPlayback`[⬆](#props-index) Boolean that determines whether HTML5 videos play inline or use the native full-screen controller. The default value is `false`. @@ -955,7 +942,7 @@ Boolean that determines whether HTML5 videos play inline or use the native full- | bool | No | iOS | --- -### `allowsAirPlayForMediaPlayback`[⬆](#props-index) +### `allowsAirPlayForMediaPlayback`[⬆](#props-index) A Boolean value indicating whether AirPlay is allowed. The default value is `false`. @@ -965,7 +952,7 @@ A Boolean value indicating whether AirPlay is allowed. The default value is `fal --- -### `bounces`[⬆](#props-index) +### `bounces`[⬆](#props-index) Boolean value that determines whether the web view bounces when it reaches the edge of the content. The default value is `true`. @@ -975,7 +962,7 @@ Boolean value that determines whether the web view bounces when it reaches the e --- -### `overScrollMode`[⬆](#props-index) +### `overScrollMode`[⬆](#props-index) Specifies the over scroll mode. @@ -991,7 +978,7 @@ Possible values for `overScrollMode` are: --- -### `contentInset`[⬆](#props-index) +### `contentInset`[⬆](#props-index) The amount by which the web view content is inset from the edges of the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}. @@ -1001,7 +988,7 @@ The amount by which the web view content is inset from the edges of the scroll v --- -### `contentInsetAdjustmentBehavior`[⬆](#props-index) +### `contentInsetAdjustmentBehavior`[⬆](#props-index) This property specifies how the safe area insets are used to modify the content area of the scroll view. The default value of this property is "never". Available on iOS 11 and later. Defaults to `never`. @@ -1018,7 +1005,7 @@ Possible values: --- -### `contentMode`[⬆](#props-index) +### `contentMode`[⬆](#props-index) Controls the type of content to load. Available on iOS 13 and later. Defaults to `recommended`, which loads mobile content on iPhone & iPad Mini but desktop content on larger iPads. @@ -1036,7 +1023,7 @@ Possible values: --- -### `dataDetectorTypes`[⬆](#props-index) +### `dataDetectorTypes`[⬆](#props-index) Determines the types of data converted to clickable URLs in the web view's content. By default only phone numbers are detected. @@ -1060,7 +1047,7 @@ Possible values for `dataDetectorTypes` are: --- -### `scrollEnabled`[⬆](#props-index) +### `scrollEnabled`[⬆](#props-index) Boolean value that determines whether scrolling is enabled in the `WebView`. The default value is `true`. Setting this to `false` will prevent the webview from moving the document body when the keyboard appears over an input. @@ -1072,7 +1059,7 @@ Boolean value that determines whether scrolling is enabled in the `WebView`. The ### `nestedScrollEnabled`[⬆](#props-index) -Boolean value that determines whether scrolling is possible in the `WebView` when used inside a `ScrollView` on Android. The default value is `false`. +Boolean value that determines whether scrolling is possible in the `WebView` when used inside a `ScrollView` on Android. The default value is `false`. Setting this to `true` will prevent the `ScrollView` to scroll when scrolling from inside the `WebView`. @@ -1082,7 +1069,7 @@ Setting this to `true` will prevent the `ScrollView` to scroll when scrolling fr --- -### `setBuiltInZoomControls`[⬆](#props-index) +### `setBuiltInZoomControls`[⬆](#props-index) Sets whether the WebView should use its built-in zoom mechanisms. The default value is `true`. Setting this to `false` will prevent the use of a pinch gesture to control zooming. @@ -1092,9 +1079,9 @@ Sets whether the WebView should use its built-in zoom mechanisms. The default va --- -### `setDisplayZoomControls`[⬆](#props-index) +### `setDisplayZoomControls`[⬆](#props-index) -Sets whether the WebView should display on-screen zoom controls when using the built-in zoom mechanisms (see `setBuiltInZoomControls`). The default value is `false`. +Sets whether the WebView should display on-screen zoom controls when using the built-in zoom mechanisms (see `setBuiltInZoomControls`). The default value is `false`. | Type | Required | Platform | | ---- | -------- | ------------- | @@ -1102,7 +1089,7 @@ Sets whether the WebView should display on-screen zoom controls when using the b --- -### `directionalLockEnabled`[⬆](#props-index) +### `directionalLockEnabled`[⬆](#props-index) A Boolean value that determines whether scrolling is disabled in a particular direction. The default value is `true`. @@ -1113,7 +1100,7 @@ The default value is `true`. --- -### `showsHorizontalScrollIndicator`[⬆](#props-index) +### `showsHorizontalScrollIndicator`[⬆](#props-index) Boolean value that determines whether a horizontal scroll indicator is shown in the `WebView`. The default value is `true`. @@ -1123,7 +1110,7 @@ Boolean value that determines whether a horizontal scroll indicator is shown in --- -### `showsVerticalScrollIndicator`[⬆](#props-index) +### `showsVerticalScrollIndicator`[⬆](#props-index) Boolean value that determines whether a vertical scroll indicator is shown in the `WebView`. The default value is `true`. @@ -1133,7 +1120,7 @@ Boolean value that determines whether a vertical scroll indicator is shown in th --- -### `geolocationEnabled`[⬆](#props-index) +### `geolocationEnabled`[⬆](#props-index) Set whether Geolocation is enabled in the `WebView`. The default value is `false`. Used only in Android. @@ -1143,7 +1130,7 @@ Set whether Geolocation is enabled in the `WebView`. The default value is `false --- -### `allowFileAccessFromFileURLs`[⬆](#props-index) +### `allowFileAccessFromFileURLs`[⬆](#props-index) Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from other file scheme URLs. The default value is `false`. @@ -1153,7 +1140,7 @@ Boolean that sets whether JavaScript running in the context of a file scheme URL --- -### `allowUniversalAccessFromFileURLs`[⬆](#props-index) +### `allowUniversalAccessFromFileURLs`[⬆](#props-index) Boolean that sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from any origin. Including accessing content from other file scheme URLs. The default value is `false`. @@ -1163,7 +1150,7 @@ Boolean that sets whether JavaScript running in the context of a file scheme URL --- -### `allowingReadAccessToURL`[⬆](#props-index) +### `allowingReadAccessToURL`[⬆](#props-index) A String value that indicates which URLs the WebView's file can then reference in scripts, AJAX requests, and CSS imports. This is only used in for WebViews that are loaded with a source.uri set to a `'file://'` URL. If not provided, the default is to only allow read access to the URL provided in source.uri itself. @@ -1173,27 +1160,7 @@ A String value that indicates which URLs the WebView's file can then reference i --- -### `url`[⬆](#props-index) - -**Deprecated.** Use the `source` prop instead. - -| Type | Required | -| ------ | -------- | -| string | No | - ---- - -### `html`[⬆](#props-index) - -**Deprecated.** Use the `source` prop instead. - -| Type | Required | -| ------ | -------- | -| string | No | - ---- - -### `keyboardDisplayRequiresUserAction`[⬆](#props-index) +### `keyboardDisplayRequiresUserAction`[⬆](#props-index) If false, web content can programmatically display the keyboard. The default value is `true`. @@ -1203,7 +1170,7 @@ If false, web content can programmatically display the keyboard. The default val --- -### `hideKeyboardAccessoryView`[⬆](#props-index) +### `hideKeyboardAccessoryView`[⬆](#props-index) If true, this will hide the keyboard accessory view (< > and Done). @@ -1213,7 +1180,7 @@ If true, this will hide the keyboard accessory view (< > and Done). --- -### `allowsBackForwardNavigationGestures`[⬆](#props-index) +### `allowsBackForwardNavigationGestures`[⬆](#props-index) If true, this will be able horizontal swipe gestures. The default value is `false`. @@ -1223,7 +1190,7 @@ If true, this will be able horizontal swipe gestures. The default value is `fals --- -### `incognito`[⬆](#props-index) +### `incognito`[⬆](#props-index) Does not store any data within the lifetime of the WebView. @@ -1233,7 +1200,7 @@ Does not store any data within the lifetime of the WebView. --- -### `allowFileAccess`[⬆](#props-index) +### `allowFileAccess`[⬆](#props-index) If true, this will allow access to the file system via `file://` URI's. The default value is `false`. @@ -1243,7 +1210,7 @@ If true, this will allow access to the file system via `file://` URI's. The defa --- -### `saveFormDataDisabled`[⬆](#props-index) +### `saveFormDataDisabled`[⬆](#props-index) Sets whether the WebView should disable saving form data. The default value is `false`. This function does not have any effect from Android API level 26 onwards as there is an Autofill feature which stores form data. @@ -1253,7 +1220,7 @@ Sets whether the WebView should disable saving form data. The default value is ` --- -### `cacheEnabled`[⬆](#props-index) +### `cacheEnabled`[⬆](#props-index) Sets whether WebView should use browser caching. @@ -1263,7 +1230,7 @@ Sets whether WebView should use browser caching. --- -### `cacheMode`[⬆](#props-index) +### `cacheMode`[⬆](#props-index) Overrides the way the cache is used. The way the cache is used is based on the navigation type. For a normal page load, the cache is checked and content is re-validated as needed. When navigating back, content is not revalidated, instead the content is just retrieved from the cache. This property allows the client to override this behavior. @@ -1280,7 +1247,7 @@ Possible values are: --- -### `pagingEnabled`[⬆](#props-index) +### `pagingEnabled`[⬆](#props-index) If the value of this property is true, the scroll view stops on multiples of the scroll view’s bounds when the user scrolls. The default value is false. @@ -1290,7 +1257,7 @@ If the value of this property is true, the scroll view stops on multiples of the --- -### `allowsLinkPreview`[⬆](#props-index) +### `allowsLinkPreview`[⬆](#props-index) A Boolean value that determines whether pressing on a link displays a preview of the destination for the link. In iOS this property is available on devices that support 3D Touch. In iOS 10 and later, the default value is true; before that, the default value is false. @@ -1300,7 +1267,7 @@ A Boolean value that determines whether pressing on a link displays a preview of --- -### `sharedCookiesEnabled`[⬆](#props-index) +### `sharedCookiesEnabled`[⬆](#props-index) Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage]` should used for every load request in the WebView. The default value is `false`. For more on cookies, read the [Guide](Guide.md#Managing-Cookies) @@ -1310,7 +1277,7 @@ Set `true` if shared cookies from `[NSHTTPCookieStorage sharedHTTPCookieStorage] --- -### `textZoom`[⬆](#props-index) +### `textZoom`[⬆](#props-index) If the user has set a custom font size in the Android system, an undesirable scale of the site interface in WebView occurs. @@ -1326,7 +1293,7 @@ Example: --- -### `pullToRefreshEnabled`[⬆](#props-index) +### `pullToRefreshEnabled`[⬆](#props-index) Boolean value that determines whether a pull to refresh gesture is available in the `WebView`. The default value is `false`. If `true`, sets `bounces` automatically to `true`. @@ -1334,7 +1301,7 @@ Boolean value that determines whether a pull to refresh gesture is available in | ------- | -------- | -------- | | boolean | No | iOS | -### `ignoreSilentHardwareSwitch`[⬆](#props-index) +### `ignoreSilentHardwareSwitch`[⬆](#props-index) (ios only) @@ -1344,7 +1311,7 @@ When set to true the hardware silent switch is ignored. Default: `false` | ------- | -------- | -------- | | boolean | No | iOS | -### `onFileDownload`[⬆](#props-index) +### `onFileDownload`[⬆](#props-index) This property is iOS-only. Function that is invoked when the client needs to download a file. @@ -1379,7 +1346,7 @@ Example: --- -### `limitsNavigationsToAppBoundDomains`[⬆](#props-index) +### `limitsNavigationsToAppBoundDomains`[⬆](#props-index) If true indicates to WebKit that a WKWebView will only navigate to app-bound domains. Only applicable for iOS 14 or greater. @@ -1398,7 +1365,7 @@ Example: --- -### `textInteractionEnabled`[⬆](#props-index) +### `textInteractionEnabled`[⬆](#props-index) If false indicates to WebKit that a WKWebView will not interact with text, thus not showing a text selection loop. Only applicable for iOS 14.5 or greater. @@ -1416,7 +1383,7 @@ Example: --- -### `mediaCapturePermissionGrantType` +### `mediaCapturePermissionGrantType`[⬆](#props-index) This property specifies how to handle media capture permission requests. Defaults to `prompt`, resulting in the user being prompted repeatedly. Available on iOS 15 and later. @@ -1442,7 +1409,7 @@ Example: --- -### `autoManageStatusBarEnabled` +### `autoManageStatusBarEnabled`[⬆](#props-index) If set to `true`, the status bar will be automatically hidden/shown by WebView, specifically when full screen video is being watched. If `false`, WebView will not manage the status bar at all. The default value is `true`. @@ -1456,7 +1423,7 @@ Example: ``` -### `setSupportMultipleWindows` +### `setSupportMultipleWindows`[⬆](#props-index) Sets whether the WebView supports multiple windows. See [Android documentation]('https://developer.android.com/reference/android/webkit/WebSettings#setSupportMultipleWindows(boolean)') for more information. Setting this to false can expose the application to this [vulnerability](https://alesandroortiz.com/articles/uxss-android-webview-cve-2020-6506/) allowing a malicious iframe to escape into the top layer DOM. @@ -1471,7 +1438,7 @@ Example: ``` -### `enableApplePay` +### `enableApplePay`[⬆](#props-index) A Boolean value which, when set to `true`, WebView will be rendered with Apple Pay support. Once set, websites will be able to invoke Apple Pay from React Native Webview. This comes with a cost features like [`injectJavaScript`](Reference.md#injectjavascriptstr), html5 History, [`sharedCookiesEnabled`](Reference.md#sharedCookiesEnabled), [`injectedJavaScript`](Reference.md#injectedjavascript), [`injectedJavaScriptBeforeContentLoaded`](Reference.md#injectedjavascriptbeforecontentloaded) will not work See [Apple Pay Release Note](https://developer.apple.com/documentation/safari-release-notes/safari-13-release-notes#Payment-Request-API). @@ -1491,7 +1458,7 @@ Example: ``` -### `forceDarkOn` +### `forceDarkOn`[⬆](#props-index) Configuring Dark Theme @@ -1508,7 +1475,8 @@ Example: ```javascript ``` -### `menuItems` + +### `menuItems`[⬆](#props-index) An array of custom menu item objects that will be appended to the UIMenu that appears when selecting text (will appear after 'Copy' and 'Share...'). Used in tandem with `onCustomMenuSelection` @@ -1522,7 +1490,7 @@ Example: ``` -### `onCustomMenuSelection` +### `onCustomMenuSelection`[⬆](#props-index) Function called when a custom menu item is selected. It receives a Native event, which includes three custom keys: `label`, `key` and `selectedText`. @@ -1531,7 +1499,7 @@ Function called when a custom menu item is selected. It receives a Native event | function | No | iOS | ```javascript - { const { label } = webViewEvent.nativeEvent; // The name of the menu item, i.e. 'Tweet' @@ -1541,7 +1509,7 @@ Function called when a custom menu item is selected. It receives a Native event /> ``` -### `basicAuthCredential` +### `basicAuthCredential`[⬆](#props-index) An object that specifies the credentials of a user to be used for basic authentication. @@ -1552,7 +1520,7 @@ An object that specifies the credentials of a user to be used for basic authenti | ------ | -------- | | object | No | -### `useWebView2` +### `useWebView2`[⬆](#props-index) Use WinUI WebView2 control instead of WebView control as the native webview. The WebView2 control is a WinUI control that renders web content using the Microsoft Edge (Chromium) rendering engine. Option can be toggled at runtime and supports Fast Refresh. @@ -1566,7 +1534,7 @@ Example: ``` -### `minimumFontSize` +### `minimumFontSize`[⬆](#props-index) Android enforces a minimum font size based on this value. A non-negative integer between 1 and 72. Any number outside the specified range will be pinned. Default value is 8. If you are using smaller font sizes and are having trouble fitting the whole window onto one screen, try setting this to a smaller value. @@ -1580,7 +1548,7 @@ Example: ``` -### `downloadingMessage` +### `downloadingMessage`[⬆](#props-index) This is the message that is shown in the Toast when downloading a file via WebView. Default message is "Downloading". @@ -1588,7 +1556,7 @@ This is the message that is shown in the Toast when downloading a file via WebVi | ------ | -------- | -------- | | string | No | Android | -### `lackPermissionToDownloadMessage` +### `lackPermissionToDownloadMessage`[⬆](#props-index) This is the message that is shown in the Toast when the webview is unable to download a file. Default message is "Cannot download files as permission was denied. Please provide permission to write to storage, in order to download files.". @@ -1596,18 +1564,35 @@ This is the message that is shown in the Toast when the webview is unable to dow | ------ | -------- | -------- | | string | No | Android | -### `allowsProtectedMedia` +### `allowsProtectedMedia`[⬆](#props-index) Whether or not the Webview can play media protected by DRM. Default is false. /!\ Setting this to false won't revoke the permission already granted to the current webpage. In order to do so, you'd have to reload the page as well. /!\ -| Type | Required | Platform | -| ------ | -------- | -------- | +| Type | Required | Platform | +| ------- | -------- | -------- | | boolean | No | Android | +### `fraudulentWebsiteWarningEnabled`[⬆](#props-index) + +A Boolean value that indicates whether the web view shows warnings for suspected fraudulent content, such as malware or phishing attempts. The default value is `true`. (iOS 13+) + +| Type | Required | Default | Platform | +| ------- | -------- | ------- | -------- | +| boolean | No | true | iOS | + +### `webviewDebuggingEnabled`[⬆](#props-index) + +Whether or not the webview can be debugged remotely using Safari / Chrome. +Default is false. Supported on iOS as of 16.4, previous versions always allow debugging by default. + +| Type | Required | Platform | +| ------- | -------- | -------- | +| boolean | No | iOS & Android | + ## Methods -### `goForward()`[⬆](#methods-index) +### `goForward()`[⬆](#methods-index) ```javascript goForward(); @@ -1615,7 +1600,7 @@ goForward(); Go forward one page in the web view's history. -### `goBack()`[⬆](#methods-index) +### `goBack()`[⬆](#methods-index) ```javascript goBack(); @@ -1623,7 +1608,7 @@ goBack(); Go back one page in the web view's history. -### `reload()`[⬆](#methods-index) +### `reload()`[⬆](#methods-index) ```javascript reload(); @@ -1631,7 +1616,7 @@ reload(); Reloads the current page. -### `stopLoading()`[⬆](#methods-index) +### `stopLoading()`[⬆](#methods-index) ```javascript stopLoading(); @@ -1639,7 +1624,7 @@ stopLoading(); Stop loading the current page. -### `injectJavaScript(str)`[⬆](#methods-index) +### `injectJavaScript(str)`[⬆](#methods-index) ```javascript injectJavaScript('... javascript string ...'); @@ -1649,7 +1634,7 @@ Executes the JavaScript string. To learn more, read the [Communicating between JS and Native](Guide.md#communicating-between-js-and-native) guide. -### `requestFocus()`[⬆](#methods-index) +### `requestFocus()`[⬆](#methods-index) ```javascript requestFocus(); @@ -1657,7 +1642,7 @@ requestFocus(); Request the webView to ask for focus. (People working on TV apps might want having a look at this!) -### `postMessage(str)`[⬆](#methods-index) +### `postMessage(str)`[⬆](#methods-index) ```javascript postMessage('message'); @@ -1665,7 +1650,7 @@ postMessage('message'); Post a message to WebView, handled by [`onMessage`](Reference.md#onmessage). -### `clearFormData()`[⬆](#methods-index) +### `clearFormData()`[⬆](#methods-index) (android only) @@ -1675,7 +1660,7 @@ clearFormData(); Removes the autocomplete popup from the currently focused form field, if present. [developer.android.com reference]() -### `clearCache(bool)`[⬆](#methods-index) +### `clearCache(bool)`[⬆](#methods-index) (android only) @@ -1685,7 +1670,7 @@ clearCache(true) Clears the resource cache. Note that the cache is per-application, so this will clear the cache for all WebViews used. [developer.android.com reference]() -### `clearHistory()`[⬆](#methods-index) +### `clearHistory()`[⬆](#methods-index) (android only) diff --git a/docs/Reference.portuguese.md b/docs/Reference.portuguese.md index b50a5bc75a..a4153910e4 100644 --- a/docs/Reference.portuguese.md +++ b/docs/Reference.portuguese.md @@ -36,7 +36,6 @@ Este documento apresenta as propriedades e métodos públicos para o React Nativ - [`domStorageEnabled`](Reference.portuguese.md#domstorageenabled) - [`javaScriptEnabled`](Reference.portuguese.md#javascriptenabled) - [`javaScriptCanOpenWindowsAutomatically`](Reference.portuguese.md#javascriptcanopenwindowsautomatically) -- [`androidHardwareAccelerationDisabled`](Reference.portuguese.md#androidHardwareAccelerationDisabled) - [`androidLayerType`](Reference.portuguese.md#androidLayerType) - [`mixedContentMode`](Reference.portuguese.md#mixedcontentmode) - [`thirdPartyCookiesEnabled`](Reference.portuguese.md#thirdpartycookiesenabled) @@ -60,8 +59,6 @@ Este documento apresenta as propriedades e métodos públicos para o React Nativ - [`allowFileAccessFromFileURLs`](Reference.portuguese.md#allowFileAccessFromFileURLs) - [`allowUniversalAccessFromFileURLs`](Reference.portuguese.md#allowUniversalAccessFromFileURLs) - [`allowingReadAccessToURL`](Reference.portuguese.md#allowingReadAccessToURL) -- [`url`](Reference.portuguese.md#url) -- [`html`](Reference.portuguese.md#html) - [`keyboardDisplayRequiresUserAction`](Reference.portuguese.md#keyboardDisplayRequiresUserAction) - [`hideKeyboardAccessoryView`](Reference.portuguese.md#hidekeyboardaccessoryview) - [`allowsBackForwardNavigationGestures`](Reference.portuguese.md#allowsbackforwardnavigationgestures) @@ -841,16 +838,6 @@ Um valor booleano que indica se o JavaScript pode abrir janelas sem interação --- -### `androidHardwareAccelerationDisabled`[⬆](#props-index) - -**Descontinuado.** Em vez disso, use o prop `androidLayerType`. - -| Tipo | Requerido | Plataforma | -| ---- | --------- | ---------- | -| bool | Não | Android | - ---- - ### `androidLayerType`[⬆](#props-index) Especifica o tipo de camada. @@ -861,8 +848,6 @@ Os valores possíveis para `androidLayerType` são: - `software` - A visão tem uma camada de software. Uma camada de software é apoiada por um bitmap e faz com que a exibição seja renderizada usando o pipeline de renderização de software do Android, mesmo se a aceleração de hardware estiver habilitada. - `hardware` - A visualização tem uma camada de hardware. Uma camada de hardware é apoiada por uma textura específica de hardware e faz com que a exibição seja renderizada usando o pipeline de renderização de hardware do Android, mas somente se a aceleração de hardware estiver ativada para a hierarquia de exibição. -Evite definir as props `androidLayerType` e `androidHardwareAccelerationDisabled` ao mesmo tempo, pois isso pode causar um comportamento indefinido. - | Tipo | Requerido | Plataforma | | ------ | --------- | ---------- | | string | Não | Android | @@ -1163,26 +1148,6 @@ Um valor String que indica quais URLs o arquivo da WebView pode referenciar em s --- -### `url`[⬆](#props-index) - -**Descontinuado.** Em vez disso, use a propriedade `source`. - -| Tipo | Requerido | -| ------ | --------- | -| string | Não | - ---- - -### `html`[⬆](#props-index) - -**Descontinuado.** Em vez disso, use a propriedade `source`. - -| Tipo | Requerido | -| ------ | --------- | -| string | Não | - ---- - ### `keyboardDisplayRequiresUserAction`[⬆](#props-index) Se false, o conteúdo da Web pode exibir programaticamente o teclado. O valor padrão é `true`. @@ -1521,7 +1486,7 @@ Função chamada quando um item de menu personalizado é selecionado. Ele recebe | function | Não | iOS | ```javascript - { const { label } = webViewEvent.nativeEvent; // O nome do item de menu, ou seja, 'Tweet' diff --git a/example/App.tsx b/example/App.tsx index 49c9a039e8..f0bbfac3d2 100644 --- a/example/App.tsx +++ b/example/App.tsx @@ -23,6 +23,7 @@ import ApplePay from './examples/ApplePay'; import Portals from './examples/Portals'; import AssetLoadedWebpage from './examples/AssetLoadedWebpage'; import TemporaryParenting from './examples/TemporaryParenting'; +import CustomMenu from './examples/CustomMenu'; const TESTS = { Messaging: { @@ -128,11 +129,19 @@ const TESTS = { render() { return ; }, + }, + CustomMenu: { + title: 'Custom Menu', + testId: 'CustomMenu', + description: 'Test to custom context menu shown on highlighting text', + render() { + return ; + }, } }; -type Props = {}; -type State = {restarting: boolean; currentTest: Object}; +interface Props {} +interface State {restarting: boolean; currentTest: Object} export default class App extends Component { state = { @@ -238,6 +247,11 @@ export default class App extends Component { onPress={() => this._changeTest('AssetLoaded')} /> )} +

+

Nothing received yet

+ @@ -48,6 +55,9 @@ export default class Messaging extends Component { render() { return ( + { + this.webView.current.postMessage(e.nativeEvent.text); + }}/> { state = {}; @@ -15,6 +15,13 @@ export default class NativeWebpage extends Component { { + console.log("onShouldStartLoadWithRequest", event); + return true; + }} + onLoadStart={(event) => { + console.log("onLoadStart", event.nativeEvent); + }} /> ); diff --git a/example/ios/.xcode.env b/example/ios/.xcode.env new file mode 100644 index 0000000000..e7e7f04015 --- /dev/null +++ b/example/ios/.xcode.env @@ -0,0 +1 @@ +export NODE_BINARY=/Users/donald/.nvm/versions/node/v16.8.0/bin/node diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 2f83ff5625..edaeae1529 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,291 +1,322 @@ PODS: - boost (1.76.0) - DoubleConversion (1.1.6) - - FBLazyVector (0.68.5) - - FBReactNativeSpec (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTRequired (= 0.68.5) - - RCTTypeSafety (= 0.68.5) - - React-Core (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) + - FBLazyVector (0.71.10) + - FBReactNativeSpec (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.71.10) + - RCTTypeSafety (= 0.71.10) + - React-Core (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) - fmt (6.2.1) - glog (0.3.5) - - RCT-Folly (2021.06.28.00-v2): + - RCT-Folly (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Default (= 2021.06.28.00-v2) - - RCT-Folly/Default (2021.06.28.00-v2): + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCTRequired (0.68.5) - - RCTTypeSafety (0.68.5): - - FBLazyVector (= 0.68.5) - - RCT-Folly (= 2021.06.28.00-v2) - - RCTRequired (= 0.68.5) - - React-Core (= 0.68.5) - - React (0.68.5): - - React-Core (= 0.68.5) - - React-Core/DevSupport (= 0.68.5) - - React-Core/RCTWebSocket (= 0.68.5) - - React-RCTActionSheet (= 0.68.5) - - React-RCTAnimation (= 0.68.5) - - React-RCTBlob (= 0.68.5) - - React-RCTImage (= 0.68.5) - - React-RCTLinking (= 0.68.5) - - React-RCTNetwork (= 0.68.5) - - React-RCTSettings (= 0.68.5) - - React-RCTText (= 0.68.5) - - React-RCTVibration (= 0.68.5) - - React-callinvoker (0.68.5) - - React-Codegen (0.68.5): - - FBReactNativeSpec (= 0.68.5) - - RCT-Folly (= 2021.06.28.00-v2) - - RCTRequired (= 0.68.5) - - RCTTypeSafety (= 0.68.5) - - React-Core (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-Core (0.68.5): + - RCTRequired (0.71.10) + - RCTTypeSafety (0.71.10): + - FBLazyVector (= 0.71.10) + - RCTRequired (= 0.71.10) + - React-Core (= 0.71.10) + - React (0.71.10): + - React-Core (= 0.71.10) + - React-Core/DevSupport (= 0.71.10) + - React-Core/RCTWebSocket (= 0.71.10) + - React-RCTActionSheet (= 0.71.10) + - React-RCTAnimation (= 0.71.10) + - React-RCTBlob (= 0.71.10) + - React-RCTImage (= 0.71.10) + - React-RCTLinking (= 0.71.10) + - React-RCTNetwork (= 0.71.10) + - React-RCTSettings (= 0.71.10) + - React-RCTText (= 0.71.10) + - React-RCTVibration (= 0.71.10) + - React-callinvoker (0.71.10) + - React-Codegen (0.71.10): + - FBReactNativeSpec + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsc + - React-jsi + - React-jsiexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.68.5) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.10) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/CoreModulesHeaders (0.68.5): + - React-Core/CoreModulesHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/Default (0.68.5): + - React-Core/Default (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/DevSupport (0.68.5): + - React-Core/DevSupport (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.68.5) - - React-Core/RCTWebSocket (= 0.68.5) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-jsinspector (= 0.68.5) - - React-perflogger (= 0.68.5) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.10) + - React-Core/RCTWebSocket (= 0.71.10) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-jsinspector (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTActionSheetHeaders (0.68.5): + - React-Core/RCTActionSheetHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTAnimationHeaders (0.68.5): + - React-Core/RCTAnimationHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTBlobHeaders (0.68.5): + - React-Core/RCTBlobHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTImageHeaders (0.68.5): + - React-Core/RCTImageHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTLinkingHeaders (0.68.5): + - React-Core/RCTLinkingHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTNetworkHeaders (0.68.5): + - React-Core/RCTNetworkHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTSettingsHeaders (0.68.5): + - React-Core/RCTSettingsHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTTextHeaders (0.68.5): + - React-Core/RCTTextHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTVibrationHeaders (0.68.5): + - React-Core/RCTVibrationHeaders (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) + - RCT-Folly (= 2021.07.22.00) - React-Core/Default - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-Core/RCTWebSocket (0.68.5): + - React-Core/RCTWebSocket (0.71.10): - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-Core/Default (= 0.68.5) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsiexecutor (= 0.68.5) - - React-perflogger (= 0.68.5) + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.71.10) + - React-cxxreact (= 0.71.10) + - React-jsc + - React-jsi (= 0.71.10) + - React-jsiexecutor (= 0.71.10) + - React-perflogger (= 0.71.10) - Yoga - - React-CoreModules (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.68.5) - - React-Codegen (= 0.68.5) - - React-Core/CoreModulesHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - React-RCTImage (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-cxxreact (0.68.5): - - boost (= 1.76.0) - - DoubleConversion - - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-callinvoker (= 0.68.5) - - React-jsi (= 0.68.5) - - React-jsinspector (= 0.68.5) - - React-logger (= 0.68.5) - - React-perflogger (= 0.68.5) - - React-runtimeexecutor (= 0.68.5) - - React-jsi (0.68.5): + - React-CoreModules (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.10) + - React-Codegen (= 0.71.10) + - React-Core/CoreModulesHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - React-RCTBlob + - React-RCTImage (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-cxxreact (0.71.10): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-jsi/Default (= 0.68.5) - - React-jsi/Default (0.68.5): + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.10) + - React-jsi (= 0.71.10) + - React-jsinspector (= 0.71.10) + - React-logger (= 0.71.10) + - React-perflogger (= 0.71.10) + - React-runtimeexecutor (= 0.71.10) + - React-jsc (0.71.10): + - React-jsc/Fabric (= 0.71.10) + - React-jsi (= 0.71.10) + - React-jsc/Fabric (0.71.10): + - React-jsi (= 0.71.10) + - React-jsi (0.71.10): - boost (= 1.76.0) - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-jsiexecutor (0.68.5): + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.71.10): - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-perflogger (= 0.68.5) - - React-jsinspector (0.68.5) - - React-logger (0.68.5): + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.71.10) + - React-jsi (= 0.71.10) + - React-perflogger (= 0.71.10) + - React-jsinspector (0.71.10) + - React-logger (0.71.10): - glog - - react-native-webview (11.26.1): + - react-native-webview (13.2.2): + - React-Core + - React-perflogger (0.71.10) + - React-RCTActionSheet (0.71.10): + - React-Core/RCTActionSheetHeaders (= 0.71.10) + - React-RCTAnimation (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.10) + - React-Codegen (= 0.71.10) + - React-Core/RCTAnimationHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTAppDelegate (0.71.10): + - RCT-Folly + - RCTRequired + - RCTTypeSafety - React-Core - - React-perflogger (0.68.5) - - React-RCTActionSheet (0.68.5): - - React-Core/RCTActionSheetHeaders (= 0.68.5) - - React-RCTAnimation (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.68.5) - - React-Codegen (= 0.68.5) - - React-Core/RCTAnimationHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTBlob (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - React-Codegen (= 0.68.5) - - React-Core/RCTBlobHeaders (= 0.68.5) - - React-Core/RCTWebSocket (= 0.68.5) - - React-jsi (= 0.68.5) - - React-RCTNetwork (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTImage (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.68.5) - - React-Codegen (= 0.68.5) - - React-Core/RCTImageHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - React-RCTNetwork (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTLinking (0.68.5): - - React-Codegen (= 0.68.5) - - React-Core/RCTLinkingHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTNetwork (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.68.5) - - React-Codegen (= 0.68.5) - - React-Core/RCTNetworkHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTSettings (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - RCTTypeSafety (= 0.68.5) - - React-Codegen (= 0.68.5) - - React-Core/RCTSettingsHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-RCTText (0.68.5): - - React-Core/RCTTextHeaders (= 0.68.5) - - React-RCTVibration (0.68.5): - - RCT-Folly (= 2021.06.28.00-v2) - - React-Codegen (= 0.68.5) - - React-Core/RCTVibrationHeaders (= 0.68.5) - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (= 0.68.5) - - React-runtimeexecutor (0.68.5): - - React-jsi (= 0.68.5) - - ReactCommon/turbomodule/core (0.68.5): + - ReactCommon/turbomodule/core + - React-RCTBlob (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.10) + - React-Core/RCTBlobHeaders (= 0.71.10) + - React-Core/RCTWebSocket (= 0.71.10) + - React-jsi (= 0.71.10) + - React-RCTNetwork (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTImage (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.10) + - React-Codegen (= 0.71.10) + - React-Core/RCTImageHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - React-RCTNetwork (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTLinking (0.71.10): + - React-Codegen (= 0.71.10) + - React-Core/RCTLinkingHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTNetwork (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.10) + - React-Codegen (= 0.71.10) + - React-Core/RCTNetworkHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTSettings (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.71.10) + - React-Codegen (= 0.71.10) + - React-Core/RCTSettingsHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-RCTText (0.71.10): + - React-Core/RCTTextHeaders (= 0.71.10) + - React-RCTVibration (0.71.10): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.71.10) + - React-Core/RCTVibrationHeaders (= 0.71.10) + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/core (= 0.71.10) + - React-runtimeexecutor (0.71.10): + - React-jsi (= 0.71.10) + - ReactCommon/turbomodule/bridging (0.71.10): + - DoubleConversion + - glog + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.10) + - React-Core (= 0.71.10) + - React-cxxreact (= 0.71.10) + - React-jsi (= 0.71.10) + - React-logger (= 0.71.10) + - React-perflogger (= 0.71.10) + - ReactCommon/turbomodule/core (0.71.10): - DoubleConversion - glog - - RCT-Folly (= 2021.06.28.00-v2) - - React-callinvoker (= 0.68.5) - - React-Core (= 0.68.5) - - React-cxxreact (= 0.68.5) - - React-jsi (= 0.68.5) - - React-logger (= 0.68.5) - - React-perflogger (= 0.68.5) - - ReactTestApp-DevSupport (2.3.2): + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.71.10) + - React-Core (= 0.71.10) + - React-cxxreact (= 0.71.10) + - React-jsi (= 0.71.10) + - React-logger (= 0.71.10) + - React-perflogger (= 0.71.10) + - ReactTestApp-DevSupport (2.3.18): - React-Core - React-jsi - ReactTestApp-Resources (1.0.0-dev) @@ -304,10 +335,10 @@ DEPENDENCIES: - React-callinvoker (from `../../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../../node_modules/react-native/`) - - React-Core/DevSupport (from `../../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../../node_modules/react-native/`) - React-CoreModules (from `../../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../../node_modules/react-native/ReactCommon/cxxreact`) + - React-jsc (from `../../node_modules/react-native/ReactCommon/jsc`) - React-jsi (from `../../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`) @@ -316,6 +347,7 @@ DEPENDENCIES: - React-perflogger (from `../../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../../node_modules/react-native/Libraries/AppDelegate`) - React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`) - React-RCTImage (from `../../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../../node_modules/react-native/Libraries/LinkingIOS`) @@ -362,6 +394,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/react-native/React/CoreModules" React-cxxreact: :path: "../../node_modules/react-native/ReactCommon/cxxreact" + React-jsc: + :path: "../../node_modules/react-native/ReactCommon/jsc" React-jsi: :path: "../../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: @@ -378,6 +412,8 @@ EXTERNAL SOURCES: :path: "../../node_modules/react-native/Libraries/ActionSheetIOS" React-RCTAnimation: :path: "../../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../../node_modules/react-native/Libraries/AppDelegate" React-RCTBlob: :path: "../../node_modules/react-native/Libraries/Blob" React-RCTImage: @@ -406,39 +442,41 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: a7c83b31436843459a1961bfd74b96033dc77234 DoubleConversion: 831926d9b8bf8166fd87886c4abab286c2422662 - FBLazyVector: 2b47ff52037bd9ae07cc9b051c9975797814b736 - FBReactNativeSpec: 077145af227b87804441c945101b5587c04ad00c + FBLazyVector: ddb55c55295ea51ed98aa7e2e08add2f826309d5 + FBReactNativeSpec: a11dff868857a8444f7defde274215293413d93a fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 5337263514dd6f09803962437687240c5dc39aa4 - RCT-Folly: a21c126816d8025b547704b777a2ba552f3d9fa9 - RCTRequired: 0f06b6068f530932d10e1a01a5352fad4eaacb74 - RCTTypeSafety: b0ee81f10ef1b7d977605a2b266823dabd565e65 - React: 3becd12bd51ea8a43bdde7e09d0f40fba7820e03 - React-callinvoker: 11abfff50e6bf7a55b3a90b4dc2187f71f224593 - React-Codegen: f8946ce0768fb8e92e092e30944489c4b2955b2d - React-Core: 203cdb6ee2657b198d97d41031c249161060e6ca - React-CoreModules: 6eb0c06a4a223fde2cb6a8d0f44f58b67e808942 - React-cxxreact: afb0c6c07d19adbd850747fedeac20c6832d40b9 - React-jsi: 14d37a6db2af2c1a49f6f5c2e4ee667c364ae45c - React-jsiexecutor: 45c0496ca8cef6b02d9fa0274c25cf458fe91a56 - React-jsinspector: eb202e43b3879aba9a14f3f65788aec85d4e1ea9 - React-logger: 98f663b292a60967ebbc6d803ae96c1381183b6d - react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1 - React-perflogger: 0458a87ea9a7342079e7a31b0d32b3734fb8415f - React-RCTActionSheet: 22538001ea2926dea001111dd2846c13a0730bc9 - React-RCTAnimation: 732ce66878d4aa151d56a0d142b1105aa12fd313 - React-RCTBlob: 9cb9e3e9a41d27be34aaf89b0e0f52c7ca415d57 - React-RCTImage: 6bd16627eb9c4bb79903c4cdec7c551266ee1a5b - React-RCTLinking: e9edfc8919c8fa9a3f3c7b34362811f58a2ebba4 - React-RCTNetwork: 880eccd21bbe2660a0b63da5ccba75c46eceeaa6 - React-RCTSettings: 8c85d8188c97d6c6bd470af6631a6c4555b79bb3 - React-RCTText: bbd275ee287730c5acbab1aadc0db39c25c5c64e - React-RCTVibration: 9819a3bf6230e4b2a99877c21268b0b2416157a1 - React-runtimeexecutor: b1f1995089b90696dbc2a7ffe0059a80db5c8eb1 - ReactCommon: 149e2c0acab9bac61378da0db5b2880a1b5ff59b - ReactTestApp-DevSupport: 1646ce70be36400a60ca18608284f3f7099a35c1 + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: 8ef706f91e2b643cd32c26a57700b5f24fab0585 + RCTTypeSafety: 5fbddd8eb9242b91ac0d901c01da3673f358b1b7 + React: e5d2d559e89d256a1d6da64d51adaecda9c8ddae + React-callinvoker: 352ecbafbdccca5fdf4aed99c98ae5b7fc28e39b + React-Codegen: 522da503ff4f6db2b4596599875ef30b4cae4ebe + React-Core: 4c13dd381dfcb8264e8ee1b981ed4ead79b99b63 + React-CoreModules: 63f7f9fda3d4b214040a80e3f47ab4fb9a3e88e6 + React-cxxreact: 6a455b69788c129a4f8e0c82488511cfdd9cdfc5 + React-jsc: b2dfd6271a8842d445ec85f373c49c574f5a7fcd + React-jsi: d41d5574025585f1d71ced8aa8865c40d463a6cf + React-jsiexecutor: 634df557a683cab436e4b3bc46512a6e519d19e8 + React-jsinspector: cdc854f8b13abd202afa54bc12578e5afb9cfae1 + React-logger: ef2269b3afa6ba868da90496c3e17a4ec4f4cee0 + react-native-webview: b8ec89966713985111a14d6e4bf98d8b54bced0d + React-perflogger: 217095464d5c4bb70df0742fa86bf2a363693468 + React-RCTActionSheet: 8deae9b85a4cbc6a2243618ea62a374880a2c614 + React-RCTAnimation: 59c62353a8b59ce206044786c5d30e4754bffa64 + React-RCTAppDelegate: 0159735c684803f36c17f43443dbe8fb1c3822c4 + React-RCTBlob: dcb026643fafac22f257d996a9390db987822f7e + React-RCTImage: 36c0324ff499802b9874d6803ca72026e90434f6 + React-RCTLinking: 401aec3a01b18c2c8ed93bf3a6758b87e617c58d + React-RCTNetwork: cb25b9f2737c3aa2cde0fe0bd7ff7fabf7bf9ad0 + React-RCTSettings: cb6ae9f656e1c880500c2ecbe8e72861c2262afa + React-RCTText: 7404fd01809244d79d456f92cfe6f9fbadf69209 + React-RCTVibration: d13cc2d63286c633393d3a7f6f607cc2a09ec011 + React-runtimeexecutor: a9a1cd79996c9a0846e3232ecb25c64e1cc0172e + ReactCommon: 86289421205f793f8b50106aabca54f0b4abb574 + ReactTestApp-DevSupport: 1a9381b9b8323ec0c7c6153e175e44e4376c76a8 ReactTestApp-Resources: ff5f151e465e890010b417ce65ca6c5de6aeccbb - Yoga: c4d61225a466f250c35c1ee78d2d0b3d41fe661c + Yoga: e7ea9e590e27460d28911403b894722354d73479 PODFILE CHECKSUM: 8344c021910ed9b6a9bb9985ff8f7f05a68b19c1 diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index ffcf2fae1f..689d3ef2df 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -218,7 +218,7 @@ PODS: - React-jsinspector (0.68.62) - React-logger (0.68.62): - glog - - react-native-webview (11.26.0): + - react-native-webview (12.0.0-rc.0): - React-Core - React-perflogger (0.68.62) - React-RCTActionSheet (0.68.62): @@ -423,7 +423,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 1862151d3f809499c82d7f66a3ca624b4d6b49d9 React-jsinspector: 39348b9a3417419aea646f41cba625e1a7bbbd30 React-logger: 7a2e45e85d0fe59edb6d4fb2cbcbb9981ab9486e - react-native-webview: 994b9f8fbb504d6314dc40d83f94f27c6831b3bf + react-native-webview: bf1329769290feefad471977132b5fb6c8288f71 React-perflogger: 20ae52b52ce2c0e1e257e0c0502f8f08a0b43ff9 React-RCTActionSheet: 2a62f3135a621bbf90504a28205cf5ef05b27bea React-RCTAnimation: 219eb987ed34c38cbf13096062da7ddc142f0fac diff --git a/ios/RNCWebView.xcodeproj/project.pbxproj b/ios/RNCWebView.xcodeproj/project.pbxproj index 77cb5c80e3..a2d4d2d246 100644 --- a/ios/RNCWebView.xcodeproj/project.pbxproj +++ b/ios/RNCWebView.xcodeproj/project.pbxproj @@ -11,8 +11,6 @@ 40136746283E927300EAE5F2 /* RNCScriptMessageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40136745283E927300EAE5F2 /* RNCScriptMessageManager.m */; }; 40136749283E92C600EAE5F2 /* ScriptMessageEventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 40136748283E92C600EAE5F2 /* ScriptMessageEventEmitter.m */; }; 40EE00F6281AED0000A0BA29 /* RNCWKWebViewMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40EE00F5281AED0000A0BA29 /* RNCWKWebViewMapManager.m */; }; - E91B351D21446E6C00F9801F /* RNCWebViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E91B351B21446E6C00F9801F /* RNCWebViewManager.m */; }; - E91B351E21446E6C00F9801F /* RNCWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = E91B351C21446E6C00F9801F /* RNCWebView.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -39,8 +37,6 @@ 40EE00F5281AED0000A0BA29 /* RNCWKWebViewMapManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNCWKWebViewMapManager.m; path = ../apple/RNCWKWebViewMapManager.m; sourceTree = ""; }; E91B351921446E6C00F9801F /* RNCWebViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNCWebViewManager.h; path = ../apple/RNCWebViewManager.h; sourceTree = ""; }; E91B351A21446E6C00F9801F /* RNCWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNCWebView.h; path = ../apple/RNCWebView.h; sourceTree = ""; }; - E91B351B21446E6C00F9801F /* RNCWebViewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNCWebViewManager.m; path = ../apple/RNCWebViewManager.m; sourceTree = ""; }; - E91B351C21446E6C00F9801F /* RNCWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNCWebView.m; path = ../apple/RNCWebView.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,9 +68,7 @@ 40EE00F5281AED0000A0BA29 /* RNCWKWebViewMapManager.m */, 40EE00F4281AECE600A0BA29 /* RNCWKWebViewMapManager.h */, E91B351A21446E6C00F9801F /* RNCWebView.h */, - E91B351C21446E6C00F9801F /* RNCWebView.m */, E91B351921446E6C00F9801F /* RNCWebViewManager.h */, - E91B351B21446E6C00F9801F /* RNCWebViewManager.m */, 3515965F21A3C87E00623BFA /* RNCWKProcessPoolManager.h */, 3515965D21A3C86000623BFA /* RNCWKProcessPoolManager.m */, 134814211AA4EA7D00B7C361 /* Products */, @@ -139,10 +133,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 40EE00FC281C5D1200A0BA29 /* RNCWebViewMapManager.m in Sources */, - E91B351D21446E6C00F9801F /* RNCWebViewManager.m in Sources */, 40EE00F6281AED0000A0BA29 /* RNCWKWebViewMapManager.m in Sources */, - E91B351E21446E6C00F9801F /* RNCWebView.m in Sources */, 40136746283E927300EAE5F2 /* RNCScriptMessageManager.m in Sources */, 3515965E21A3C86000623BFA /* RNCWKProcessPoolManager.m in Sources */, 40136749283E92C600EAE5F2 /* ScriptMessageEventEmitter.m in Sources */, diff --git a/package.json b/package.json index 959e863d17..10b396a507 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,11 @@ "Thibault Malbranche " ], "license": "MIT", - "version": "11.26.1", + "version": "13.2.2", "homepage": "https://github.com/react-native-webview/react-native-webview#readme", "scripts": { "android": "react-native run-android", - "ios": "react-native run-ios --project-path example/ios", + "ios": "react-native run-ios", "macos": "react-native run-macos --scheme WebviewExample --project-path example/macos", "start": "cd example && react-native start", "windows": "install-windows-test-app --project-directory example/windows && react-native run-windows --root example --arch x64", @@ -23,7 +23,8 @@ "build": "yarn tsc", "prepare": "yarn build", "appium": "appium", - "test:windows": "yarn jest --setupFiles=./jest-setups/jest.setup.js" + "test:windows": "yarn jest --setupFiles=./jest-setups/jest.setup.js", + "add:macos": "yarn add react-native-macos@0.68.62" }, "rn-docs": { "title": "Webview", @@ -42,9 +43,8 @@ "@babel/runtime": "^7.0.0", "@semantic-release/git": "7.0.16", "@types/invariant": "^2.2.30", - "@types/jest": "^26.0.0", - "@types/react": "^17.0.0", - "@types/react-native": "^0.67.3", + "@types/jest": "^29.4.0", + "@types/react": "18.0.27", "@types/selenium-webdriver": "4.0.9", "@typescript-eslint/eslint-plugin": "2.1.0", "@typescript-eslint/parser": "2.1.0", @@ -57,13 +57,12 @@ "eslint-plugin-react": "7.14.3", "eslint-plugin-react-hooks": "^4.5.0", "eslint-plugin-react-native": "3.7.0", - "jest": "^26.6.3", - "metro-react-native-babel-preset": "^0.67.0", - "react": "17.0.2", - "react-native": "0.68.5", - "react-native-macos": "0.68.62", - "react-native-test-app": "2.3.2", - "react-native-windows": "0.68.4", + "jest": "^29.4.1", + "metro-react-native-babel-preset": "0.73.7", + "react": "18.2.0", + "react-native": "0.71.10", + "react-native-test-app": "2.3.18", + "react-native-windows": "0.71.0", "selenium-appium": "1.0.2", "selenium-webdriver": "4.0.0-alpha.7", "semantic-release": "15.13.24", @@ -75,15 +74,31 @@ "url": "https://github.com/react-native-webview/react-native-webview.git" }, "files": [ - "android", + "android/src", + "android/build.gradle", + "android/gradle.properties", "apple", "ios", "macos", "windows", "lib", + "src", "index.js", "index.d.ts", "react-native-webview.podspec", "react-native.config.js" - ] + ], + "resolutions": { + "@react-native-community/cli": "10.1.3", + "@react-native-community/cli-platform-android": "10.1.3", + "@react-native-community/cli-platform-ios": "10.1.1" + }, + "codegenConfig": { + "name": "RNCWebViewSpec", + "type": "all", + "jsSrcsDir": "./src", + "android": { + "javaPackageName": "com.reactnativecommunity.webview" + } + } } diff --git a/react-native-webview.podspec b/react-native-webview.podspec index 7ed0835d27..b6f164ada4 100644 --- a/react-native-webview.podspec +++ b/react-native-webview.podspec @@ -2,6 +2,8 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) +folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' + Pod::Spec.new do |s| s.name = package['name'] s.version = package['version'] @@ -13,7 +15,24 @@ Pod::Spec.new do |s| s.platforms = { :ios => "9.0", :osx => "10.13" } s.source = { :git => "https://github.com/react-native-webview/react-native-webview.git", :tag => "v#{s.version}" } - s.source_files = "apple/**/*.{h,m}" - s.dependency 'React-Core' + s.source_files = "apple/**/*.{h,m,mm,swift}" + + s.dependency "React-Core" + + if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then + s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", + "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + + s.dependency "React-RCTFabric" + s.dependency "React-Codegen" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + end end diff --git a/react-native.config.js b/react-native.config.js index 154ceaf956..2736685e79 100644 --- a/react-native.config.js +++ b/react-native.config.js @@ -4,7 +4,6 @@ const project = (() => { try { const { androidManifestPath, - iosProjectPath, windowsProjectPath, } = require('react-native-test-app'); return { @@ -15,7 +14,7 @@ const project = (() => { ), }, ios: { - project: iosProjectPath('example/ios'), + sourceDir: 'example/ios', }, windows: fs.existsSync('example/windows/WebviewExample.sln') && { sourceDir: path.join('example', 'windows'), diff --git a/src/NativeRNCWebView.ts b/src/NativeRNCWebView.ts new file mode 100644 index 0000000000..6497e7e861 --- /dev/null +++ b/src/NativeRNCWebView.ts @@ -0,0 +1,14 @@ +/* eslint-disable import/no-duplicates */ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; +import {Int32} from 'react-native/Libraries/Types/CodegenTypes'; + +export interface Spec extends TurboModule { + readonly getConstants: () => {}; + + // your module methods go here, for example: + isFileUploadSupported(): Promise; + shouldStartLoadWithLockIdentifier(shouldStart: boolean, lockIdentifier: Int32): void; +} + +export default TurboModuleRegistry.getEnforcing('RNCWebView'); \ No newline at end of file diff --git a/src/RNCWebViewNativeComponent.ts b/src/RNCWebViewNativeComponent.ts new file mode 100644 index 0000000000..9c09aa4db0 --- /dev/null +++ b/src/RNCWebViewNativeComponent.ts @@ -0,0 +1,276 @@ +import type { HostComponent, ViewProps } from 'react-native'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import {DirectEventHandler,Double, Int32, WithDefault} from 'react-native/Libraries/Types/CodegenTypes'; +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; + +export type WebViewNativeEvent = Readonly<{ + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; +}> +export type WebViewCustomMenuSelectionEvent = Readonly<{ + label: string; + key: string; + selectedText: string; +}> +export type WebViewMessageEvent = Readonly<{ + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + data: string; +}> +export type WebViewHttpErrorEvent = Readonly<{ + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + description: string; + statusCode: Int32; +}> + +export type WebViewErrorEvent = Readonly<{ + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + domain?: string; + code: Int32; + description: string; +}> + +export type WebViewNativeProgressEvent = Readonly< { + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + progress: Double; +}> + +export type WebViewNavigationEvent = Readonly< { + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + navigationType: + | 'click' + | 'formsubmit' + | 'backforward' + | 'reload' + | 'formresubmit' + | 'other'; + mainDocumentURL?: string; +}> + +export type ShouldStartLoadRequestEvent = Readonly<{ + url: string; + loading: boolean; + title: string; + canGoBack: boolean; + canGoForward: boolean; + lockIdentifier: Double; + navigationType: + | 'click' + | 'formsubmit' + | 'backforward' + | 'reload' + | 'formresubmit' + | 'other'; + mainDocumentURL?: string; + isTopFrame: boolean; +}> + +type ScrollEvent = Readonly<{ + contentInset: { + bottom: Double, + left: Double, + right: Double, + top: Double, + }, + contentOffset: { + y: Double, + x: Double, + }, + contentSize: { + height: Double, + width: Double, + }, + layoutMeasurement: { + height: Double, + width: Double, + }, + targetContentOffset?: { + y: Double, + x: Double, + }, + velocity?: { + y: Double, + x: Double, + }, + zoomScale?: Double, + responderIgnoreScroll?: boolean, +}> + +type WebViewRenderProcessGoneEvent = Readonly<{ + didCrash: boolean; +}> + +type WebViewDownloadEvent = Readonly<{ + downloadUrl: string; +}> + +// type MenuItem = Readonly<{label: string, key: string}>; + +export interface NativeProps extends ViewProps { + // Android only + allowFileAccess?: boolean; + allowsProtectedMedia?: boolean; + allowsFullscreenVideo?: boolean; + androidLayerType?: WithDefault<'none' | 'software' | 'hardware', 'none'>; + cacheMode?: WithDefault<'LOAD_DEFAULT' | 'LOAD_CACHE_ELSE_NETWORK' | 'LOAD_NO_CACHE' | 'LOAD_CACHE_ONLY', 'LOAD_DEFAULT'>; + domStorageEnabled?: boolean; + downloadingMessage?: string; + forceDarkOn?: boolean; + geolocationEnabled?: boolean; + lackPermissionToDownloadMessage?: string; + messagingModuleName: string; + minimumFontSize?: Int32; + mixedContentMode?: WithDefault<'never' | 'always' | 'compatibility', 'never'>; + nestedScrollEnabled?: boolean; + onContentSizeChange?: DirectEventHandler; + onRenderProcessGone?: DirectEventHandler; + overScrollMode?: string; + saveFormDataDisabled?: boolean; + scalesPageToFit?: boolean; + setBuiltInZoomControls?: boolean; + setDisplayZoomControls?: boolean; + setSupportMultipleWindows?: boolean; + textZoom?: Int32; + thirdPartyCookiesEnabled?: boolean; + // Workaround to watch if listener if defined + hasOnScroll?: boolean; + // !Android only + + // iOS only + allowingReadAccessToURL?: string; + allowsBackForwardNavigationGestures?: boolean; + allowsInlineMediaPlayback?: boolean; + allowsAirPlayForMediaPlayback?: boolean; + allowsLinkPreview?: boolean; + automaticallyAdjustContentInsets?: boolean; + autoManageStatusBarEnabled?: boolean; + bounces?: boolean; + contentInset?: Readonly<{ + top?: Double; + left?: Double; + bottom?: Double; + right?: Double; + }>; + contentInsetAdjustmentBehavior?: WithDefault<'never' | 'automatic' | 'scrollableAxes' | 'always', 'never'>; + contentMode?: WithDefault<'recommended' | 'mobile' | 'desktop', 'recommended'>; + dataDetectorTypes?: WithDefault< + // eslint-disable-next-line @typescript-eslint/array-type + ReadonlyArray<'address' | 'link' | 'calendarEvent' | 'trackingNumber' | 'flightNumber' | 'lookupSuggestion' | 'phoneNumber' | 'all' | 'none'>, + 'phoneNumber' + >; + decelerationRate?: Double; + directionalLockEnabled?: boolean; + enableApplePay?: boolean; + hideKeyboardAccessoryView?: boolean; + keyboardDisplayRequiresUserAction?: boolean; + limitsNavigationsToAppBoundDomains?: boolean; + mediaCapturePermissionGrantType?: WithDefault<'prompt' | 'grant' | 'deny' | 'grantIfSameHostElsePrompt' | 'grantIfSameHostElseDeny', 'prompt'>; + pagingEnabled?: boolean; + pullToRefreshEnabled?: boolean; + scrollEnabled?: boolean; + sharedCookiesEnabled?: boolean; + textInteractionEnabled?: boolean; + useSharedProcessPool?: boolean; + onContentProcessDidTerminate?: DirectEventHandler; + onCustomMenuSelection?: DirectEventHandler; + onFileDownload?: DirectEventHandler; + // eslint-disable-next-line @typescript-eslint/array-type + menuItems?: ReadonlyArray>; + // Workaround to watch if listener if defined + hasOnFileDownload?: boolean; + fraudulentWebsiteWarningEnabled?: boolean; + // !iOS only + + allowFileAccessFromFileURLs?: boolean; + allowUniversalAccessFromFileURLs?: boolean; + applicationNameForUserAgent?: string; + basicAuthCredential?: Readonly<{ + username: string; + password: string; + }>; + cacheEnabled?: boolean; + incognito?: boolean; + injectedJavaScript?: string; + injectedJavaScriptBeforeContentLoaded?: string; + injectedJavaScriptForMainFrameOnly?: boolean; + injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean; + javaScriptCanOpenWindowsAutomatically?: boolean; + javaScriptEnabled?: boolean; + webviewDebuggingEnabled?: boolean; + mediaPlaybackRequiresUserAction?: boolean; + messagingEnabled: boolean; + onLoadingError: DirectEventHandler; + onLoadingFinish: DirectEventHandler; + onLoadingProgress: DirectEventHandler; + onLoadingStart: DirectEventHandler; + onHttpError: DirectEventHandler; + onMessage: DirectEventHandler; + onScroll?: DirectEventHandler; + onShouldStartLoadWithRequest: DirectEventHandler; + showsHorizontalScrollIndicator?: boolean; + showsVerticalScrollIndicator?: boolean; + newSource: Readonly<{ + uri?: string + method?: string; + body?: string; + // eslint-disable-next-line @typescript-eslint/array-type + headers?: ReadonlyArray>; + html?: string; + baseUrl?: string; + }>; + userAgent?: string; + webViewKey?: string; + temporaryParentNodeTag?: number; +} + +export interface NativeCommands { + goBack: (viewRef: React.ElementRef> ) => void; + goForward: (viewRef: React.ElementRef>) => void; + reload: (viewRef: React.ElementRef>) => void; + stopLoading: (viewRef: React.ElementRef>) => void; + injectJavaScript: (viewRef: React.ElementRef>, javascript: string) => void; + requestFocus: (viewRef: React.ElementRef>) => void; + postMessage: (viewRef: React.ElementRef>, data: string) => void; + // Android Only + loadUrl: (viewRef: React.ElementRef>, url: string) => void; + clearFormData: (viewRef: React.ElementRef>) => void; + clearCache: (viewRef: React.ElementRef>, includeDiskFiles: boolean) => void; + clearHistory: (viewRef: React.ElementRef>) => void; + // !Android Only +} + +export const Commands = codegenNativeCommands({ + supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', 'injectJavaScript', 'requestFocus', 'postMessage', 'loadUrl', 'clearFormData', 'clearCache', 'clearHistory'], +}); + +export default codegenNativeComponent( + 'RNCWebView' +) as HostComponent; \ No newline at end of file diff --git a/src/WebView.android.tsx b/src/WebView.android.tsx index bfd76c118d..3692641f86 100644 --- a/src/WebView.android.tsx +++ b/src/WebView.android.tsx @@ -1,10 +1,10 @@ -import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; +import React, { forwardRef, ReactElement, useCallback, useEffect, useImperativeHandle, useMemo, useRef } from 'react'; import { Image, View, - NativeModules, ImageSourcePropType, + HostComponent, } from 'react-native'; import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge'; @@ -13,26 +13,20 @@ import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codeg import invariant from 'invariant'; -import RNCWebViewContainer from "./WebViewNativeComponent.android"; +import RNCWebView, {Commands, NativeProps} from "./RNCWebViewNativeComponent"; +import RNCWebViewModule from "./NativeRNCWebView"; import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, - useWebWiewLogic, + useWebViewLogic, } from './WebViewShared'; import { - AndroidWebViewProps, - NativeWebViewAndroid, + AndroidWebViewProps, WebViewSourceUri, } from './WebViewTypes'; import styles from './WebView.styles'; -const codegenNativeCommands = codegenNativeCommandsUntyped as (options: { supportedCommands: (keyof T)[] }) => T; - -const Commands = codegenNativeCommands({ - supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', 'injectJavaScript', 'requestFocus', 'postMessage', 'clearFormData', 'clearCache', 'clearHistory', 'loadUrl'], -}); - const { resolveAssetSource } = Image; /** @@ -49,7 +43,6 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ allowFileAccess = false, saveFormDataDisabled = false, cacheEnabled = true, - androidHardwareAccelerationDisabled = false, androidLayerType = "none", originWhitelist = defaultOriginWhitelist, setSupportMultipleWindows = true, @@ -77,19 +70,19 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ ...otherProps }, ref) => { const messagingModuleName = useRef(`WebViewMessageHandler${uniqueRef += 1}`).current; - const webViewRef = useRef(null); + const webViewRef = useRef> | null>(null); const onShouldStartLoadWithRequestCallback = useCallback((shouldStart: boolean, url: string, lockIdentifier?: number) => { if (lockIdentifier) { - NativeModules.RNCWebView.onShouldStartLoadWithRequestCallback(shouldStart, lockIdentifier); - } else if (shouldStart) { + RNCWebViewModule.shouldStartLoadWithLockIdentifier(shouldStart, lockIdentifier); + } else if (shouldStart && webViewRef.current) { Commands.loadUrl(webViewRef.current, url); } }, []); - const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onRenderProcessGone } = useWebWiewLogic({ + const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onRenderProcessGone } = useWebViewLogic({ onNavigationStateChange, onLoad, onError, @@ -106,20 +99,23 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ }) useImperativeHandle(ref, () => ({ - goForward: () => Commands.goForward(webViewRef.current), - goBack: () => Commands.goBack(webViewRef.current), + goForward: () => webViewRef.current && Commands.goForward(webViewRef.current), + goBack: () => webViewRef.current && Commands.goBack(webViewRef.current), reload: () => { setViewState( 'LOADING', - ); Commands.reload(webViewRef.current) + ); + if (webViewRef.current) { + Commands.reload(webViewRef.current) + } }, - stopLoading: () => Commands.stopLoading(webViewRef.current), - postMessage: (data: string) => Commands.postMessage(webViewRef.current, data), - injectJavaScript: (data: string) => Commands.injectJavaScript(webViewRef.current, data), - requestFocus: () => Commands.requestFocus(webViewRef.current), - clearFormData: () => Commands.clearFormData(webViewRef.current), - clearCache: (includeDiskFiles: boolean) => Commands.clearCache(webViewRef.current, includeDiskFiles), - clearHistory: () => Commands.clearHistory(webViewRef.current), + stopLoading: () => webViewRef.current && Commands.stopLoading(webViewRef.current), + postMessage: (data: string) => webViewRef.current && Commands.postMessage(webViewRef.current, data), + injectJavaScript: (data: string) => webViewRef.current && Commands.injectJavaScript(webViewRef.current, data), + requestFocus: () => webViewRef.current && Commands.requestFocus(webViewRef.current), + clearFormData: () => webViewRef.current && Commands.clearFormData(webViewRef.current), + clearCache: (includeDiskFiles: boolean) => webViewRef.current && Commands.clearCache(webViewRef.current, includeDiskFiles), + clearHistory: () => webViewRef.current && Commands.clearHistory(webViewRef.current), }), [setViewState, webViewRef]); const directEventCallbacks = useMemo(() => ({ @@ -131,16 +127,18 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ BatchedBridge.registerCallableModule(messagingModuleName, directEventCallbacks); }, [messagingModuleName, directEventCallbacks]) - let otherView = null; + let otherView: ReactElement | undefined; if (viewState === 'LOADING') { otherView = (renderLoading || defaultRenderLoading)(); } else if (viewState === 'ERROR') { invariant(lastErrorEvent != null, 'lastErrorEvent expected to be non-null'); - otherView = (renderError || defaultRenderError)( - lastErrorEvent.domain, - lastErrorEvent.code, - lastErrorEvent.description, - ); + if (lastErrorEvent) { + otherView = (renderError || defaultRenderError)( + lastErrorEvent.domain, + lastErrorEvent.code, + lastErrorEvent.description, + ); + } } else if (viewState !== 'IDLE') { console.error(`RNCWebView invalid state encountered: ${viewState}`); } @@ -158,16 +156,29 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ } } - const NativeWebView - = (nativeConfig?.component as (typeof NativeWebViewAndroid | undefined)) || RNCWebViewContainer; + = (nativeConfig?.component as (typeof RNCWebView | undefined)) || RNCWebView; + + const sourceResolved = resolveAssetSource(source as ImageSourcePropType) + const newSource = typeof sourceResolved === "object" ? Object.entries(sourceResolved as WebViewSourceUri).reduce((prev, [currKey, currValue]) => { + return { + ...prev, + [currKey]: currKey === "headers" && currValue && typeof currValue === "object" ? Object.entries(currValue).map( + ([key, value]) => { + return { + name: key, + value + } + }) : currValue + } + }, {}) : sourceResolved const webView = (({ onRenderProcessGone={onRenderProcessGone} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} - ref={webViewRef} // TODO: find a better way to type this. - source={resolveAssetSource(source as ImageSourcePropType)} + // @ts-expect-error source is old arch + source={sourceResolved} + newSource={newSource} style={webViewStyles} overScrollMode={overScrollMode} javaScriptEnabled={javaScriptEnabled} @@ -189,7 +201,6 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ allowFileAccess={allowFileAccess} saveFormDataDisabled={saveFormDataDisabled} cacheEnabled={cacheEnabled} - androidHardwareAccelerationDisabled={androidHardwareAccelerationDisabled} androidLayerType={androidLayerType} setSupportMultipleWindows={setSupportMultipleWindows} setBuiltInZoomControls={setBuiltInZoomControls} @@ -207,9 +218,8 @@ const WebViewComponent = forwardRef<{}, AndroidWebViewProps>(({ }); // native implementation should return "true" only for Android 5+ -const isFileUploadSupported: () => Promise - = NativeModules.RNCWebView.isFileUploadSupported(); +const { isFileUploadSupported } = RNCWebViewModule; -const WebView = Object.assign(WebViewComponent, {isFileUploadSupported}); +const WebView = Object.assign(WebViewComponent, { isFileUploadSupported }); export default WebView; diff --git a/src/WebView.ios.tsx b/src/WebView.ios.tsx index 0cbfabb4f8..03ac4b02d9 100644 --- a/src/WebView.ios.tsx +++ b/src/WebView.ios.tsx @@ -2,35 +2,29 @@ import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'rea import { Image, View, - NativeModules, ImageSourcePropType, + HostComponent, } from 'react-native'; import invariant from 'invariant'; -// @ts-expect-error react-native doesn't have this type -import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands'; -import RNCWebView from "./WebViewNativeComponent.ios"; +import RNCWebView, {Commands, NativeProps} from "./RNCWebViewNativeComponent"; +import RNCWebViewModule from "./NativeRNCWebView"; + import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, - useWebWiewLogic, + useWebViewLogic, } from './WebViewShared'; import { IOSWebViewProps, DecelerationRateConstant, - NativeWebViewIOS, - ViewManager, + WebViewSourceUri, } from './WebViewTypes'; import styles from './WebView.styles'; -const codegenNativeCommands = codegenNativeCommandsUntyped as (options: { supportedCommands: (keyof T)[] }) => T; - -const Commands = codegenNativeCommands({ - supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', 'injectJavaScript', 'requestFocus', 'postMessage', 'loadUrl'], -}); const { resolveAssetSource } = Image; const processDecelerationRate = ( @@ -45,8 +39,6 @@ const processDecelerationRate = ( return newDecelerationRate; }; -const RNCWebViewManager = NativeModules.RNCWebViewManager as ViewManager; - const useWarnIfChanges = (value: T, name: string) => { const ref = useRef(value); if (ref.current !== value) { @@ -56,6 +48,7 @@ const useWarnIfChanges = (value: T, name: string) => { } const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({ + fraudulentWebsiteWarningEnabled = true, javaScriptEnabled = true, cacheEnabled = true, originWhitelist = defaultOriginWhitelist, @@ -92,21 +85,17 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({ onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, ...otherProps }, ref) => { - const webViewRef = useRef(null); + const webViewRef = useRef> | null>(null); const onShouldStartLoadWithRequestCallback = useCallback(( shouldStart: boolean, _url: string, lockIdentifier = 0, ) => { - const viewManager - = (nativeConfig?.viewManager) - || RNCWebViewManager; - - viewManager.startLoadWithResult(!!shouldStart, lockIdentifier); - }, [nativeConfig?.viewManager]); + RNCWebViewModule.shouldStartLoadWithLockIdentifier(shouldStart, lockIdentifier); + }, []); - const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebWiewLogic({ + const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebViewLogic({ onNavigationStateChange, onLoad, onError, @@ -123,17 +112,20 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({ }); useImperativeHandle(ref, () => ({ - goForward: () => Commands.goForward(webViewRef.current), - goBack: () => Commands.goBack(webViewRef.current), + goForward: () => webViewRef.current && Commands.goForward(webViewRef.current), + goBack: () => webViewRef.current && Commands.goBack(webViewRef.current), reload: () => { setViewState( 'LOADING', - ); Commands.reload(webViewRef.current) + ); + if (webViewRef.current) { + Commands.reload(webViewRef.current) + } }, - stopLoading: () => Commands.stopLoading(webViewRef.current), - postMessage: (data: string) => Commands.postMessage(webViewRef.current, data), - injectJavaScript: (data: string) => Commands.injectJavaScript(webViewRef.current, data), - requestFocus: () => Commands.requestFocus(webViewRef.current), + stopLoading: () => webViewRef.current && Commands.stopLoading(webViewRef.current), + postMessage: (data: string) => webViewRef.current && Commands.postMessage(webViewRef.current, data), + injectJavaScript: (data: string) => webViewRef.current && Commands.injectJavaScript(webViewRef.current, data), + requestFocus: () => webViewRef.current && Commands.requestFocus(webViewRef.current), }), [setViewState, webViewRef]); @@ -149,9 +141,9 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({ } else if (viewState === 'ERROR') { invariant(lastErrorEvent != null, 'lastErrorEvent expected to be non-null'); otherView = (renderError || defaultRenderError)( - lastErrorEvent.domain, - lastErrorEvent.code, - lastErrorEvent.description, + lastErrorEvent?.domain, + lastErrorEvent?.code ?? 0, + lastErrorEvent?.description ?? '', ); } else if (viewState !== 'IDLE') { console.error(`RNCWebView invalid state encountered: ${viewState}`); @@ -163,19 +155,35 @@ const WebViewComponent = forwardRef<{}, IOSWebViewProps>(({ const decelerationRate = processDecelerationRate(decelerationRateProp); const NativeWebView - = (nativeConfig?.component as typeof NativeWebViewIOS | undefined) + = (nativeConfig?.component as typeof RNCWebView | undefined) || RNCWebView; + const sourceResolved = resolveAssetSource(source as ImageSourcePropType) + const newSource = typeof sourceResolved === "object" ? Object.entries(sourceResolved as WebViewSourceUri).reduce((prev, [currKey, currValue]) => { + return { + ...prev, + [currKey]: currKey === "headers" && currValue && typeof currValue === "object" ? Object.entries(currValue).map( + ([key, value]) => { + return { + name: key, + value + } + }) : currValue + } + }, {}) : sourceResolved + const webView = ( (({ injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} injectedJavaScriptForMainFrameOnly={injectedJavaScriptForMainFrameOnly} injectedJavaScriptBeforeContentLoadedForMainFrameOnly={injectedJavaScriptBeforeContentLoadedForMainFrameOnly} - dataDetectorTypes={dataDetectorTypes} + dataDetectorTypes={!dataDetectorTypes || Array.isArray(dataDetectorTypes) ? dataDetectorTypes : [dataDetectorTypes]} allowsAirPlayForMediaPlayback={allowsAirPlayForMediaPlayback} allowsInlineMediaPlayback={allowsInlineMediaPlayback} incognito={incognito} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction} - ref={webViewRef} - // TODO: find a better way to type this. - source={resolveAssetSource(source as ImageSourcePropType)} + newSource={newSource} style={webViewStyles} + hasOnFileDownload={!!onFileDownload} + ref={webViewRef} + // @ts-expect-error old arch only + source={sourceResolved} {...nativeConfig?.props} /> ); diff --git a/src/WebView.macos.tsx b/src/WebView.macos.tsx index d4860be737..5e108ef2b3 100644 --- a/src/WebView.macos.tsx +++ b/src/WebView.macos.tsx @@ -2,39 +2,32 @@ import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'rea import { Image, View, - NativeModules, ImageSourcePropType, } from 'react-native'; import invariant from 'invariant'; -// @ts-expect-error react-native doesn't have this type -import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands'; +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; import RNCWebView from "./WebViewNativeComponent.macos"; +import RNCWebViewModule from "./NativeRNCWebView"; import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, - useWebWiewLogic, + useWebViewLogic, } from './WebViewShared'; import { MacOSWebViewProps, NativeWebViewMacOS, - ViewManager, } from './WebViewTypes'; import styles from './WebView.styles'; - -const codegenNativeCommands = codegenNativeCommandsUntyped as (options: { supportedCommands: (keyof T)[] }) => T; - const Commands = codegenNativeCommands({ supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', 'injectJavaScript', 'requestFocus', 'postMessage', 'loadUrl'], }); const { resolveAssetSource } = Image; -const RNCWebViewManager = NativeModules.RNCWebViewManager as ViewManager; - const useWarnIfChanges = (value: T, name: string) => { const ref = useRef(value); if (ref.current !== value) { @@ -79,14 +72,10 @@ const WebViewComponent = forwardRef<{}, MacOSWebViewProps>(({ _url: string, lockIdentifier = 0, ) => { - const viewManager - = (nativeConfig?.viewManager) - || RNCWebViewManager; - - viewManager.startLoadWithResult(!!shouldStart, lockIdentifier); - }, [nativeConfig?.viewManager]); + RNCWebViewModule.shouldStartLoadWithLockIdentifier(!!shouldStart, lockIdentifier); + }, []); - const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebWiewLogic({ + const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebViewLogic({ onNavigationStateChange, onLoad, onError, diff --git a/src/WebView.windows.tsx b/src/WebView.windows.tsx index 843c6ffacd..f39bcc1c89 100644 --- a/src/WebView.windows.tsx +++ b/src/WebView.windows.tsx @@ -17,11 +17,10 @@ import { ImageSourcePropType, NativeModules, } from 'react-native'; -// @ts-expect-error react-native doesn't have this type -import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands'; +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; import invariant from 'invariant'; import {RCTWebView, RCTWebView2} from "./WebViewNativeComponent.windows"; -import { useWebWiewLogic, defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, } from './WebViewShared'; +import { useWebViewLogic, defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, } from './WebViewShared'; import { NativeWebViewWindows, WindowsWebViewProps, @@ -29,8 +28,6 @@ import { import styles from './WebView.styles'; -const codegenNativeCommands = codegenNativeCommandsUntyped as (options: { supportedCommands: (keyof T)[] }) => T; - const Commands = codegenNativeCommands({ supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', 'injectJavaScript', 'requestFocus', 'postMessage', 'loadUrl'], }); @@ -59,7 +56,6 @@ const WebViewComponent = forwardRef<{}, WindowsWebViewProps>(({ ...otherProps }, ref) => { const webViewRef = useRef(null); - const RCTWebViewString = useWebView2 ? 'RCTWebView2' : 'RCTWebView'; const onShouldStartLoadWithRequestCallback = useCallback((shouldStart: boolean, url: string, lockIdentifier?: number) => { @@ -74,7 +70,7 @@ const WebViewComponent = forwardRef<{}, WindowsWebViewProps>(({ } }, [RCTWebViewString]); - const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress } = useWebWiewLogic({ + const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress } = useWebViewLogic({ onNavigationStateChange, onLoad, onError, diff --git a/src/WebViewNativeComponent.android.ts b/src/WebViewNativeComponent.android.ts deleted file mode 100644 index fe583114af..0000000000 --- a/src/WebViewNativeComponent.android.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { requireNativeComponent } from "react-native"; -import type { NativeWebViewAndroid } from "./WebViewTypes"; - -const RNCWebViewContainer: typeof NativeWebViewAndroid = requireNativeComponent( - 'RNCWebViewContainer', -); - -export default RNCWebViewContainer; diff --git a/src/WebViewNativeComponent.ios.ts b/src/WebViewNativeComponent.ios.ts deleted file mode 100644 index 96d03d543a..0000000000 --- a/src/WebViewNativeComponent.ios.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { requireNativeComponent } from "react-native"; -import type { NativeWebViewIOS } from "./WebViewTypes"; - -const RNCWebView: typeof NativeWebViewIOS = requireNativeComponent( - 'RNCWebView', -); - -export default RNCWebView; diff --git a/src/WebViewShared.tsx b/src/WebViewShared.tsx index f10476ecde..7e4bc18e48 100644 --- a/src/WebViewShared.tsx +++ b/src/WebViewShared.tsx @@ -96,7 +96,7 @@ export { defaultRenderError, }; -export const useWebWiewLogic = ({ +export const useWebViewLogic = ({ startInLoadingState, onNavigationStateChange, onLoadStart, diff --git a/src/WebViewTypes.ts b/src/WebViewTypes.ts index 28208a75cb..b331b60c49 100644 --- a/src/WebViewTypes.ts +++ b/src/WebViewTypes.ts @@ -1,17 +1,18 @@ /* eslint-disable react/no-multi-comp, max-classes-per-file */ -import { ReactElement, Component } from 'react'; +import { ReactElement, Component, ComponentProps } from 'react'; import { NativeSyntheticEvent, ViewProps, StyleProp, ViewStyle, NativeMethodsMixin, - Constructor, UIManagerStatic, NativeScrollEvent, } from 'react-native'; +import type NativeWebViewComponent from './RNCWebViewNativeComponent' + type WebViewCommands = | 'goForward' | 'goBack' @@ -55,11 +56,8 @@ interface ErrorState extends BaseState { export type State = NormalState | ErrorState; -// eslint-disable-next-line react/prefer-stateless-function -declare class NativeWebViewIOSComponent extends Component {} -declare const NativeWebViewIOSBase: Constructor & - typeof NativeWebViewIOSComponent; -export class NativeWebViewIOS extends NativeWebViewIOSBase {} +// eslint-disable-next-line @typescript-eslint/no-type-alias, @typescript-eslint/no-explicit-any +type Constructor = new (...args: any[]) => T; // eslint-disable-next-line react/prefer-stateless-function declare class NativeWebViewMacOSComponent extends Component {} @@ -67,12 +65,6 @@ declare const NativeWebViewMacOSBase: Constructor & typeof NativeWebViewMacOSComponent; export class NativeWebViewMacOS extends NativeWebViewMacOSBase {} -// eslint-disable-next-line react/prefer-stateless-function -declare class NativeWebViewAndroidComponent extends Component {} -declare const NativeWebViewAndroidBase: Constructor & - typeof NativeWebViewAndroidComponent; -export class NativeWebViewAndroid extends NativeWebViewAndroidBase {} - // eslint-disable-next-line react/prefer-stateless-function declare class NativeWebViewWindowsComponent extends Component {} declare const NativeWebViewWindowsBase: Constructor & @@ -293,7 +285,7 @@ export interface WebViewCustomMenuItems { export type WebViewSource = WebViewSourceUri | WebViewSourceHtml; export interface ViewManager { - startLoadWithResult: Function; + shouldStartLoadWithLockIdentifier: Function; } export interface WebViewNativeConfig { @@ -301,9 +293,8 @@ export interface WebViewNativeConfig { * The native component used to render the WebView. */ component?: - | typeof NativeWebViewIOS | typeof NativeWebViewMacOS - | typeof NativeWebViewAndroid; + | typeof NativeWebViewComponent; /** * Set props directly on the native component WebView. Enables custom props which the * original WebView doesn't pass through. @@ -341,6 +332,7 @@ export interface CommonNativeWebViewProps extends ViewProps { injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean; javaScriptCanOpenWindowsAutomatically?: boolean; mediaPlaybackRequiresUserAction?: boolean; + webviewDebuggingEnabled?: boolean; messagingEnabled: boolean; onScroll?: (event: WebViewScrollEvent) => void; onLoadingError: (event: WebViewErrorEvent) => void; @@ -363,39 +355,6 @@ export interface CommonNativeWebViewProps extends ViewProps { basicAuthCredential?: BasicAuthCredential; } -export interface AndroidNativeWebViewProps extends CommonNativeWebViewProps { - cacheMode?: CacheMode; - allowFileAccess?: boolean; - scalesPageToFit?: boolean; - allowFileAccessFromFileURLs?: boolean; - allowsFullscreenVideo?: boolean; - allowUniversalAccessFromFileURLs?: boolean; - androidAssetLoaderConfig?: AndroidAssetLoaderConfig - androidHardwareAccelerationDisabled?: boolean; - androidLayerType?: AndroidLayerType; - domStorageEnabled?: boolean; - geolocationEnabled?: boolean; - javaScriptEnabled?: boolean; - mixedContentMode?: 'never' | 'always' | 'compatibility'; - onContentSizeChange?: (event: WebViewEvent) => void; - onRenderProcessGone?: (event: WebViewRenderProcessGoneEvent) => void; - overScrollMode?: OverScrollModeType; - saveFormDataDisabled?: boolean; - setSupportMultipleWindows?: boolean; - textZoom?: number; - thirdPartyCookiesEnabled?: boolean; - messagingModuleName?: string; - setBuiltInZoomControls?: boolean; - setDisplayZoomControls?: boolean; - nestedScrollEnabled?: boolean; - readonly urlPrefixesForDefaultIntent?: string[]; - forceDarkOn?: boolean; - minimumFontSize?: number; - downloadingMessage?: string; - lackPermissionToDownloadMessage?: string; - allowsProtectedMedia?: boolean; -} - export declare type ContentInsetAdjustmentBehavior = | 'automatic' | 'scrollableAxes' @@ -411,37 +370,6 @@ export declare type MediaCapturePermissionGrantType = export declare type ContentMode = 'recommended' | 'mobile' | 'desktop'; -export interface IOSNativeWebViewProps extends CommonNativeWebViewProps { - allowingReadAccessToURL?: string; - allowsBackForwardNavigationGestures?: boolean; - allowsInlineMediaPlayback?: boolean; - allowsAirPlayForMediaPlayback?: boolean; - allowsLinkPreview?: boolean; - allowFileAccessFromFileURLs?: boolean; - allowUniversalAccessFromFileURLs?: boolean; - automaticallyAdjustContentInsets?: boolean; - autoManageStatusBarEnabled?: boolean; - bounces?: boolean; - contentInset?: ContentInsetProp; - contentInsetAdjustmentBehavior?: ContentInsetAdjustmentBehavior; - contentMode?: ContentMode; - readonly dataDetectorTypes?: DataDetectorTypes | DataDetectorTypes[]; - decelerationRate?: number; - directionalLockEnabled?: boolean; - hideKeyboardAccessoryView?: boolean; - javaScriptEnabled?: boolean; - pagingEnabled?: boolean; - scrollEnabled?: boolean; - useSharedProcessPool?: boolean; - onContentProcessDidTerminate?: (event: WebViewTerminatedEvent) => void; - injectedJavaScriptForMainFrameOnly?: boolean; - injectedJavaScriptBeforeContentLoadedForMainFrameOnly?: boolean; - onFileDownload?: (event: FileDownloadEvent) => void; - limitsNavigationsToAppBoundDomains?: boolean; - textInteractionEnabled?: boolean; - mediaCapturePermissionGrantType?: MediaCapturePermissionGrantType; -} - export interface MacOSNativeWebViewProps extends CommonNativeWebViewProps { allowingReadAccessToURL?: string; allowFileAccessFromFileURLs?: boolean; @@ -613,6 +541,7 @@ export interface IOSWebViewProps extends WebViewSharedProps { /** * The custom user agent string. + * @platform ios */ userAgent?: string; @@ -797,11 +726,23 @@ export interface IOSWebViewProps extends WebViewSharedProps { * `selectedText`: the text selected on the document * @platform ios */ - onCustomMenuSelection?: (event: WebViewEvent) => void; + onCustomMenuSelection?: (event: {nativeEvent: { + label: string; + key: string; + selectedText: string; + } + }) => void; + + /** + * A Boolean value that indicates whether the webview shows warnings for suspected + * fraudulent content, such as malware or phishing attempts. + * @platform ios + */ + fraudulentWebsiteWarningEnabled?: boolean; /** - * If two React components use the same - * key for the WebView, they will use the same native WebView instance. + * By default, if this is undefined or false, the native WebView will get released when + * the React component unmounts. * * When this is set, the native WebView will not get released when the React component * unmounts. When a React component remounts, it can use a previous native WebView instance @@ -810,7 +751,7 @@ export interface IOSWebViewProps extends WebViewSharedProps { * If another WebView mounts with the same webViewKey while one is already mounted, the native WebView * will re-attach to the newly mounted react view. * - * It's important to call `releaseWebView` on the React WebView with the corresponding webViewKey + * It's important to call `releaseWebView` on the WebViewProxy with the corresponding webViewKey * when the native WebView is no longer needed. */ webViewKey?: string; @@ -818,10 +759,20 @@ export interface IOSWebViewProps extends WebViewSharedProps { /** * If a webViewKey is set, the onMessage callback will not work. * Instead, to handle messages, set messagingWithWebViewKeyEnabled - * to true, and call 'addOnMessageListenerWithWebViewKey' to listen to messages for a given + * to true, create a WebViewProxy instance with the webViewKey, and call + * WebViewProxy#addOnMessageListener' to listen to messages for a given * webViewKey */ messagingWithWebViewKeyEnabled?: boolean; + + /** + * If a webViewKey and temporaryParentNodeTag are set, the webview will reattach to a temporary parent + * specified by the tag if this view is ever unmounted by React + * + * A possible usecase is to ensure the webview stays attached to the window at all times, so the visibilityState + * on the document remains visible. + */ + temporaryParentNodeTag?: number; } export interface MacOSWebViewProps extends WebViewSharedProps { @@ -1065,22 +1016,6 @@ export interface AndroidWebViewProps extends WebViewSharedProps { */ setSupportMultipleWindows?: boolean; - /** - * Used on Android only, controls whether the given list of URL prefixes should - * make {@link com.facebook.react.views.webview.ReactWebViewClient} to launch a - * default activity intent for those URL instead of loading it within the webview. - * Use this to list URLs that WebView cannot handle, e.g. a PDF url. - * @platform android - */ - readonly urlPrefixesForDefaultIntent?: string[]; - - /** - * Boolean value to disable Hardware Acceleration in the `WebView`. Used on Android only - * as Hardware Acceleration is a feature only for Android. The default value is `false`. - * @platform android - */ - androidHardwareAccelerationDisabled?: boolean; - /** * https://developer.android.com/reference/android/webkit/WebView#setLayerType(int,%20android.graphics.Paint) * Sets the layerType. Possible values are: @@ -1223,7 +1158,7 @@ export interface AndroidWebViewProps extends WebViewSharedProps { * If another WebView mounts with the same webViewKey while one is already mounted, the native WebView * will re-attach to the newly mounted react view. * - * It's important to call `releaseWebView` on the React WebView with the corresponding webViewKey + * It's important to call `releaseWebView` on the WebViewProxy with the corresponding webViewKey * when the native WebView is no longer needed. */ webViewKey?: string; @@ -1231,13 +1166,14 @@ export interface AndroidWebViewProps extends WebViewSharedProps { /** * If a webViewKey is set, the onMessage callback will not work. * Instead, to handle messages, set messagingWithWebViewKeyEnabled - * to true, and call 'addOnMessageListenerWithWebViewKey' to listen to messages for a given + * to true, create a WebViewProxy instance with the webViewKey, and call + * WebViewProxy#addOnMessageListener' to listen to messages for a given * webViewKey */ messagingWithWebViewKeyEnabled?: boolean; /** - * If a webViewKey and temporaryParentNodeTags are set, the webview will reattach to a temporary parent + * If a webViewKey and temporaryParentNodeTag are set, the webview will reattach to a temporary parent * specified by the tag if this view is ever unmounted by React * * A possible usecase is to ensure the webview stays attached to the window at all times, so the visibilityState @@ -1287,7 +1223,7 @@ export interface WebViewSharedProps extends ViewProps { /** * Function that is invoked when the `WebView` scrolls. */ - onScroll?: (event: WebViewScrollEvent) => void; + onScroll?: ComponentProps['onScroll']; /** * Function that is invoked when the `WebView` has finished loading. @@ -1418,4 +1354,9 @@ export interface WebViewSharedProps extends ViewProps { * An object that specifies the credentials of a user to be used for basic authentication. */ basicAuthCredential?: BasicAuthCredential; + + /** + * Enables WebView remote debugging using Chrome (Android) or Safari (iOS). + */ + webviewDebuggingEnabled?: boolean; } diff --git a/src/__tests__/__snapshots__/WebViewShared-test.js.snap b/src/__tests__/__snapshots__/WebViewShared-test.js.snap index 57d8ea1917..dfc866c1d9 100644 --- a/src/__tests__/__snapshots__/WebViewShared-test.js.snap +++ b/src/__tests__/__snapshots__/WebViewShared-test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`WebViewShared exports defaultOriginWhitelist 1`] = ` -Array [ +[ "http://*", "https://*", ] diff --git a/windows/ReactNativeWebView/ReactNativeWebView.vcxproj b/windows/ReactNativeWebView/ReactNativeWebView.vcxproj index 9ecc62f5ef..9bd27c194d 100644 --- a/windows/ReactNativeWebView/ReactNativeWebView.vcxproj +++ b/windows/ReactNativeWebView/ReactNativeWebView.vcxproj @@ -15,7 +15,7 @@ Windows Store 10.0 10.0 - 10.0.15063.0 + 10.0.17763.0 diff --git a/windows/ReactNativeWebView/ReactWebView.idl b/windows/ReactNativeWebView/ReactWebView.idl index 54b0e626d7..51e95f914e 100644 --- a/windows/ReactNativeWebView/ReactWebView.idl +++ b/windows/ReactNativeWebView/ReactWebView.idl @@ -15,6 +15,7 @@ namespace ReactNativeWebView{ runtimeclass ReactWebView2 : Windows.UI.Xaml.Controls.ContentPresenter{ ReactWebView2(Microsoft.ReactNative.IReactContext context); void NavigateToHtml(String html); + void NavigateWithHeaders(String uri, Windows.Foundation.Collections.IMapView headers); Boolean MessagingEnabled; }; #endif diff --git a/windows/ReactNativeWebView/ReactWebView2.cpp b/windows/ReactNativeWebView/ReactWebView2.cpp index 4da23fb6d1..759aa04302 100644 --- a/windows/ReactNativeWebView/ReactWebView2.cpp +++ b/windows/ReactNativeWebView/ReactWebView2.cpp @@ -9,6 +9,11 @@ #include "ReactWebView2.g.cpp" #include #include +#include +#include +#include +#include + namespace winrt { using namespace Microsoft::ReactNative; @@ -22,9 +27,68 @@ namespace winrt { using namespace Windows::UI::Popups; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; + using namespace Windows::Storage::Streams; } // namespace winrt namespace winrt::ReactNativeWebView::implementation { + namespace helpers { + std::string trimString(const std::string& str) { + std::string trimmedString = str; + + // Trim from start + trimmedString.erase(0, trimmedString.find_first_not_of(" \t\n\r\f\v")); + + // Trim from end + trimmedString.erase(trimmedString.find_last_not_of(" \t\n\r\f\v") + 1); + + return trimmedString; + } + std::vector splitString( + const std::string& str, + const std::string& delim) { + std::vector tokens; + auto startPos = 0; + auto endPos = str.find(delim); + + while (endPos != std::string::npos) { + auto token = str.substr(startPos, endPos - startPos); + tokens.push_back(trimString(token)); + + startPos = endPos + delim.length(); + endPos = str.find(delim, startPos); + } + + auto lastToken = str.substr(startPos); + tokens.push_back(trimString(lastToken)); + + return tokens; + } + + std::map parseSetCookieHeader( + const std::string& setCookieHeader) { + std::map cookie; + + // Split the header into individual cookie strings + auto cookieStrings = splitString(setCookieHeader, ";"); + + // Extract the cookie name and value from the first string + auto nameValuePair = splitString(cookieStrings[0], "="); + cookie["Name"] = trimString(nameValuePair[0]); + cookie["Value"] = trimString(nameValuePair[1]); + + // Extract the attributes from the remaining strings + for (std::size_t i = 1; i < cookieStrings.size(); ++i) { + auto attributeValuePair = splitString(cookieStrings[i], "="); + auto attributeName = attributeValuePair[0]; + auto attributeValue = + attributeValuePair.size() > 1 ? attributeValuePair[1] : ""; + cookie[attributeName] = trimString(attributeValue); + } + + return cookie; + } + } // namespace HP + ReactWebView2::ReactWebView2(winrt::IReactContext const& reactContext) : m_reactContext(reactContext) { m_webView = winrt::WebView2(); @@ -32,23 +96,23 @@ namespace winrt::ReactNativeWebView::implementation { RegisterEvents(); } - ReactWebView2::~ReactWebView2(){} + ReactWebView2::~ReactWebView2() {} void ReactWebView2::RegisterEvents() { m_navigationStartingRevoker = m_webView.NavigationStarting( winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) { - if (auto self = ref.get()) { - self->OnNavigationStarting(sender, args); - } - - }); + if (auto self = ref.get()) { + self->OnNavigationStarting(sender, args); + } + + }); m_navigationCompletedRevoker = m_webView.NavigationCompleted( winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args) { - if (auto self = ref.get()) { - self->OnNavigationCompleted(sender, args); - } - }); + if (auto self = ref.get()) { + self->OnNavigationCompleted(sender, args); + } + }); m_CoreWebView2InitializedRevoker = m_webView.CoreWebView2Initialized( winrt::auto_revoke, [ref = get_weak()](auto const& sender, auto const& args){ @@ -56,13 +120,13 @@ namespace winrt::ReactNativeWebView::implementation { self->OnCoreWebView2Initialized(sender, args); } }); - } + } bool ReactWebView2::Is17763OrHigher() { static std::optional hasUniversalAPIContract_v7; if (!hasUniversalAPIContract_v7.has_value()) { - hasUniversalAPIContract_v7 = winrt::Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 7); + hasUniversalAPIContract_v7 = winrt::Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 7); } return hasUniversalAPIContract_v7.value(); } @@ -72,11 +136,11 @@ namespace winrt::ReactNativeWebView::implementation { WriteProperty(eventDataWriter, L"canGoBack", sender.CanGoBack()); WriteProperty(eventDataWriter, L"canGoForward", sender.CanGoForward()); if (Is17763OrHigher()) { - WriteProperty(eventDataWriter, L"loading", !sender.IsLoaded()); + WriteProperty(eventDataWriter, L"loading", !sender.IsLoaded()); } WriteProperty(eventDataWriter, L"target", tag); if (auto uri = sender.Source()) { - WriteProperty(eventDataWriter, L"url", uri.AbsoluteCanonicalUri()); + WriteProperty(eventDataWriter, L"url", uri.AbsoluteCanonicalUri()); } } @@ -90,9 +154,9 @@ namespace winrt::ReactNativeWebView::implementation { eventDataWriter.WriteObjectEnd(); }); - + if (m_messagingEnabled) { - m_messageToken = webView.WebMessageReceived([this](auto const& /* sender */ , winrt::CoreWebView2WebMessageReceivedEventArgs const& messageArgs) + m_messageToken = webView.WebMessageReceived([this](auto const& /* sender */, winrt::CoreWebView2WebMessageReceivedEventArgs const& messageArgs) { try { auto message = messageArgs.TryGetWebMessageAsString(); @@ -121,7 +185,7 @@ namespace winrt::ReactNativeWebView::implementation { }); if (m_messagingEnabled) { - winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)}; + winrt::hstring message = LR"(window.alert = function (msg) {window.chrome.webview.postMessage(`{"type":"__alert","message":"${msg}"}`)}; window.ReactNativeWebView = {postMessage: function (data) {window.chrome.webview.postMessage(String(data))}};)"; webView.ExecuteScriptAsync(message); } @@ -129,10 +193,40 @@ namespace winrt::ReactNativeWebView::implementation { void ReactWebView2::OnCoreWebView2Initialized(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::UI::Xaml::Controls::CoreWebView2InitializedEventArgs const& /* args */) { assert(sender.CoreWebView2()); + if (m_navigateToHtml != L"") { m_webView.NavigateToString(m_navigateToHtml); m_navigateToHtml = L""; } + else if (m_navigationWithHeaders.has_value()) { + auto headers = m_navigationWithHeaders.value().second; + + auto stream = InMemoryRandomAccessStream(); + + // construct headers string + winrt::hstring headers_str; + for (auto const& header : headers) { + if (header.Key() == L"cookie" || header.Key() == L"Cookie") { + WriteCookiesToWebView2(header.Value()); + } + else { + headers_str = headers_str + header.Key() + L": " + + header.Value() + L"\r\n"; + } + + } + + auto request = + m_webView.CoreWebView2().Environment().CreateWebResourceRequest( + m_navigationWithHeaders.value().first, + L"GET", + stream, + headers_str + ); + + m_webView.CoreWebView2().NavigateWithWebResourceRequest(request); + m_navigationWithHeaders.reset(); + } } void ReactWebView2::HandleMessageFromJS(winrt::hstring const& message) { @@ -161,11 +255,11 @@ namespace winrt::ReactNativeWebView::implementation { }); } - void ReactWebView2::MessagingEnabled(bool enabled) noexcept{ + void ReactWebView2::MessagingEnabled(bool enabled) noexcept { m_messagingEnabled = enabled; } - bool ReactWebView2::MessagingEnabled() const noexcept{ + bool ReactWebView2::MessagingEnabled() const noexcept { return m_messagingEnabled; } @@ -180,6 +274,35 @@ namespace winrt::ReactNativeWebView::implementation { } } + void ReactWebView2::NavigateWithHeaders(winrt::hstring uri, IMapView headers) { + m_navigationWithHeaders = std::make_pair(uri, headers); + m_webView.EnsureCoreWebView2Async(); + } + + void ReactWebView2::WriteCookiesToWebView2(winrt::hstring cookies) { + // Persisting cookies passed from JS + // Cookies are separated by ;, and adheres to the Set-Cookie HTTP header format of RFC-6265. + + auto cm = m_webView.CoreWebView2().CookieManager(); + auto cookies_list = + helpers::splitString(winrt::to_string(cookies), ";,"); + for (const auto& cookie_str : cookies_list) { + auto cookieData = helpers::parseSetCookieHeader(helpers::trimString(cookie_str)); + + if (!cookieData.count("Name") || !cookieData.count("Value")) { + continue; + } + auto cookie = cm.CreateCookie( + winrt::to_hstring(cookieData["Name"]), + winrt::to_hstring(cookieData["Value"]), + cookieData.count("Domain") + ? winrt::to_hstring(cookieData["Domain"]) + : L"", + cookieData.count("Path") + ? winrt::to_hstring(cookieData["Path"]) : L""); + cm.AddOrUpdateCookie(cookie); + } + } } // namespace winrt::ReactNativeWebView::implementation #endif // HAS_WEBVIEW2 diff --git a/windows/ReactNativeWebView/ReactWebView2.h b/windows/ReactNativeWebView/ReactWebView2.h index b84bf75c38..8404a83fa3 100644 --- a/windows/ReactNativeWebView/ReactWebView2.h +++ b/windows/ReactNativeWebView/ReactWebView2.h @@ -21,10 +21,12 @@ namespace winrt::ReactNativeWebView::implementation { void MessagingEnabled(bool enabled) noexcept; bool MessagingEnabled() const noexcept; void NavigateToHtml(winrt::hstring html); + void NavigateWithHeaders(winrt::hstring uri, IMapView headers); ~ReactWebView2(); private: winrt::hstring m_navigateToHtml = L""; + std::optional>> m_navigationWithHeaders; bool m_messagingEnabled{ true }; winrt::Microsoft::UI::Xaml::Controls::WebView2 m_webView{ nullptr }; @@ -35,6 +37,7 @@ namespace winrt::ReactNativeWebView::implementation { winrt::Microsoft::UI::Xaml::Controls::WebView2::CoreWebView2Initialized_revoker m_CoreWebView2InitializedRevoker{}; void HandleMessageFromJS(winrt::hstring const& message); void RegisterEvents(); + void WriteCookiesToWebView2(winrt::hstring cookies); void WriteWebViewNavigationEventArg(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::ReactNative::IJSValueWriter const& eventDataWriter); void OnNavigationStarting(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationStartingEventArgs const& args); void OnNavigationCompleted(winrt::Microsoft::UI::Xaml::Controls::WebView2 const& sender, winrt::Microsoft::Web::WebView2::Core::CoreWebView2NavigationCompletedEventArgs const& args); diff --git a/windows/ReactNativeWebView/ReactWebView2Manager.cpp b/windows/ReactNativeWebView/ReactWebView2Manager.cpp index c7ea87fd56..65e50d42f7 100644 --- a/windows/ReactNativeWebView/ReactWebView2Manager.cpp +++ b/windows/ReactNativeWebView/ReactWebView2Manager.cpp @@ -16,6 +16,8 @@ namespace winrt { using namespace Microsoft::UI::Xaml::Controls; using namespace Windows::Web::Http; using namespace Windows::Web::Http::Headers; + using namespace Microsoft::Web::WebView2::Core; + using namespace Windows::Storage::Streams; } namespace winrt::ReactNativeWebView::implementation { @@ -28,8 +30,8 @@ namespace winrt::ReactNativeWebView::implementation { } winrt::FrameworkElement ReactWebView2Manager::CreateView() noexcept { - auto view = winrt::ReactNativeWebView::ReactWebView2(m_reactContext); - return view; + auto view = winrt::ReactNativeWebView::ReactWebView2(m_reactContext); + return view; } // IViewManagerWithReactContext @@ -79,7 +81,29 @@ namespace winrt::ReactNativeWebView::implementation { auto bundleRootPath = winrt::to_string(ReactNativeHost().InstanceSettings().BundleRootPath()); uriString.replace(0, std::size(file), bundleRootPath.empty() ? "ms-appx-web:///Bundle/" : bundleRootPath); } - webView.Source(winrt::Uri(to_hstring(uriString))); + + if (uriString.find("ms-appdata://") == 0 || uriString.find("ms-appx-web://") == 0) { + webView.Source(winrt::Uri(to_hstring(uriString))); + } + else { + const auto hasHeaders = srcMap.find("headers") != srcMap.end(); + + if (hasHeaders) { + auto headers = winrt::single_threaded_map(); + + for (auto const& header : srcMap.at("headers").AsObject()) { + auto const& headerKey = header.first; + auto const& headerValue = header.second; + headers.Insert(winrt::to_hstring(headerKey), winrt::to_hstring(headerValue.AsString())); + } + + const auto reactWebView2 = view.as(); + reactWebView2.NavigateWithHeaders(to_hstring(uriString), headers.GetView()); + } + else { + webView.Source(winrt::Uri(to_hstring(uriString))); + } + } } else if (srcMap.find("html") != srcMap.end()) { auto htmlString = srcMap.at("html").AsString(); @@ -92,7 +116,7 @@ namespace winrt::ReactNativeWebView::implementation { auto reactWebView2 = view.as(); reactWebView2.MessagingEnabled(messagingEnabled); } - } + } } // IViewManagerWithExportedEventTypeConstants @@ -147,7 +171,7 @@ namespace winrt::ReactNativeWebView::implementation { } else if (commandId == L"injectJavaScript") { webView.ExecuteScriptAsync(winrt::to_hstring(commandArgs[0].AsString())); - } + } } } // namespace winrt::ReactNativeWebView::implementation diff --git a/windows/ReactNativeWebView/pch.h b/windows/ReactNativeWebView/pch.h index ac40d18ff9..5c8902bffb 100644 --- a/windows/ReactNativeWebView/pch.h +++ b/windows/ReactNativeWebView/pch.h @@ -29,4 +29,5 @@ #include #if HAS_WEBVIEW2 #include +#include #endif \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 717276e7d3..b0a437fa12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -68,19 +68,19 @@ dependencies: tslib "^2.2.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" + integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== dependencies: - "@babel/highlight" "^7.16.7" + "@babel/highlight" "^7.18.6" -"@babel/compat-data@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" - integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== +"@babel/compat-data@^7.20.5": + version "7.20.10" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.10.tgz#9d92fa81b87542fff50e848ed585b4212c1d34ec" + integrity sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg== -"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.7.5": +"@babel/core@^7.0.0", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== @@ -101,29 +101,51 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/generator@^7.14.0", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" - integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== +"@babel/core@^7.11.6", "@babel/core@^7.20.0": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.12.tgz#7930db57443c6714ad216953d1356dac0eb8496d" + integrity sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg== dependencies: - "@babel/types" "^7.17.0" + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-compilation-targets" "^7.20.7" + "@babel/helper-module-transforms" "^7.20.11" + "@babel/helpers" "^7.20.7" + "@babel/parser" "^7.20.7" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.12" + "@babel/types" "^7.20.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.0" + +"@babel/generator@^7.17.7", "@babel/generator@^7.7.2": + version "7.20.14" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.14.tgz#9fa772c9f86a46c6ac9b321039400712b96f64ce" + integrity sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg== + dependencies: + "@babel/types" "^7.20.7" + "@jridgewell/gen-mapping" "^0.3.2" jsesc "^2.5.1" - source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== +"@babel/generator@^7.20.0", "@babel/generator@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a" + integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.20.7" + "@jridgewell/gen-mapping" "^0.3.2" + jsesc "^2.5.1" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" - integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== +"@babel/helper-annotate-as-pure@^7.10.4", "@babel/helper-annotate-as-pure@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" + integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA== dependencies: - "@babel/helper-explode-assignable-expression" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/types" "^7.18.6" "@babel/helper-builder-react-jsx-experimental@^7.10.4": version "7.10.5" @@ -142,37 +164,51 @@ "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-compilation-targets@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" - integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== +"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz#a6cd33e93629f5eb473b021aac05df62c4cd09bb" + integrity sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ== dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.17.5" + "@babel/compat-data" "^7.20.5" + "@babel/helper-validator-option" "^7.18.6" + browserslist "^4.21.3" + lru-cache "^5.1.1" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.16.7": - version "7.17.1" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz#9699f14a88833a7e055ce57dcd3ffdcd25186b21" - integrity sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz#d802ee16a64a9e824fcbf0a2ffc92f19d58550ce" + integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.18.9" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-class-features-plugin@^7.20.12": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz#4349b928e79be05ed2d1643b20b99bb87c503819" + integrity sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-member-expression-to-functions" "^7.20.7" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/helper-replace-supers" "^7.20.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" + "@babel/helper-split-export-declaration" "^7.18.6" + +"@babel/helper-create-regexp-features-plugin@^7.10.4", "@babel/helper-create-regexp-features-plugin@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c" + integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + regexpu-core "^5.1.0" "@babel/helper-define-map@^7.10.4": version "7.10.5" @@ -183,82 +219,84 @@ "@babel/types" "^7.10.5" lodash "^4.17.19" -"@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-explode-assignable-expression@^7.10.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" - integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ== - dependencies: - "@babel/types" "^7.10.4" +"@babel/helper-environment-visitor@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" + integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg== -"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== +"@babel/helper-function-name@^7.10.4", "@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c" + integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w== dependencies: - "@babel/helper-get-function-arity" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/template" "^7.18.10" + "@babel/types" "^7.19.0" -"@babel/helper-get-function-arity@^7.10.4", "@babel/helper-get-function-arity@^7.16.7": +"@babel/helper-get-function-arity@^7.10.4": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: "@babel/types" "^7.16.7" -"@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== +"@babel/helper-hoist-variables@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" + integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.6" -"@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== +"@babel/helper-member-expression-to-functions@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815" + integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.18.9" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== +"@babel/helper-member-expression-to-functions@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz#a6f26e919582275a93c3aa6594756d71b0bb7f05" + integrity sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw== dependencies: - "@babel/types" "^7.16.7" + "@babel/types" "^7.20.7" -"@babel/helper-module-transforms@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" - integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e" + integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA== dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/types" "^7.18.6" -"@babel/helper-optimise-call-expression@^7.10.4", "@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== +"@babel/helper-module-transforms@^7.17.7", "@babel/helper-module-transforms@^7.20.11": + version "7.20.11" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz#df4c7af713c557938c50ea3ad0117a7944b2f1b0" + integrity sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg== dependencies: - "@babel/types" "^7.16.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-module-imports" "^7.18.6" + "@babel/helper-simple-access" "^7.20.2" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/helper-validator-identifier" "^7.19.1" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.10" + "@babel/types" "^7.20.7" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" - integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== +"@babel/helper-optimise-call-expression@^7.10.4", "@babel/helper-optimise-call-expression@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" + integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.8.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" + integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== + +"@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" + integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== "@babel/helper-regex@^7.10.4": version "7.10.5" @@ -267,97 +305,151 @@ dependencies: lodash "^4.17.19" -"@babel/helper-remap-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" - integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-wrap-function" "^7.16.8" - "@babel/types" "^7.16.8" - -"@babel/helper-replace-supers@^7.10.4", "@babel/helper-replace-supers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" - integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" - -"@babel/helper-simple-access@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" - integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== - dependencies: - "@babel/types" "^7.17.0" - -"@babel/helper-skip-transparent-expression-wrappers@^7.11.0", "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== - dependencies: - "@babel/types" "^7.16.0" - -"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== +"@babel/helper-remap-async-to-generator@^7.16.8", "@babel/helper-remap-async-to-generator@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" + integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.18.6" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-wrap-function" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.10.4", "@babel/helper-replace-supers@^7.18.9": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6" + integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.18.9" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/traverse" "^7.18.9" + "@babel/types" "^7.18.9" + +"@babel/helper-replace-supers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" + integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-member-expression-to-functions" "^7.20.7" + "@babel/helper-optimise-call-expression" "^7.18.6" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/helper-simple-access@^7.17.7", "@babel/helper-simple-access@^7.20.2": + version "7.20.2" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" + integrity sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA== + dependencies: + "@babel/types" "^7.20.2" + +"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818" + integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw== + dependencies: + "@babel/types" "^7.18.9" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0", "@babel/helper-skip-transparent-expression-wrappers@^7.20.0": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" + integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== + dependencies: + "@babel/types" "^7.20.0" + +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" + integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA== + dependencies: + "@babel/types" "^7.18.6" + +"@babel/helper-string-parser@^7.19.4": + version "7.19.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" + integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== + +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@babel/helper-validator-option@^7.16.7", "@babel/helper-validator-option@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8" + integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw== + +"@babel/helper-wrap-function@^7.18.9": + version "7.18.11" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz#bff23ace436e3f6aefb61f85ffae2291c80ed1fb" + integrity sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w== + dependencies: + "@babel/helper-function-name" "^7.18.9" + "@babel/template" "^7.18.10" + "@babel/traverse" "^7.18.11" + "@babel/types" "^7.18.10" -"@babel/helper-wrap-function@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" - integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== +"@babel/helpers@^7.17.8": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.13.tgz#e3cb731fb70dc5337134cadc24cbbad31cc87ad2" + integrity sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg== dependencies: - "@babel/helper-function-name" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.8" - "@babel/types" "^7.16.8" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.13" + "@babel/types" "^7.20.7" -"@babel/helpers@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" - integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== +"@babel/helpers@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.20.7.tgz#04502ff0feecc9f20ecfaad120a18f011a8e6dce" + integrity sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA== dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/template" "^7.20.7" + "@babel/traverse" "^7.20.7" + "@babel/types" "^7.20.7" -"@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== +"@babel/highlight@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" + integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-validator-identifier" "^7.18.6" chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": +"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7": version "7.17.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== +"@babel/parser@^7.17.8", "@babel/parser@^7.20.13": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.13.tgz#ddf1eb5a813588d2fb1692b70c6fce75b945c088" + integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw== + +"@babel/parser@^7.20.0", "@babel/parser@^7.20.7": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.7.tgz#66fe23b3c8569220817d5feb8b9dcdc95bb4f71b" + integrity sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg== + +"@babel/plugin-proposal-async-generator-functions@^7.0.0": + version "7.18.10" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz#85ea478c98b0095c3e4102bff3b67d306ed24952" + integrity sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew== + dependencies: + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/helper-remap-async-to-generator" "^7.18.9" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.13.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" - integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" + integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-proposal-export-default-from@^7.0.0": version "7.10.4" @@ -436,12 +528,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.16.7", "@babel/plugin-syntax-flow@^7.2.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" - integrity sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ== +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.18.0", "@babel/plugin-syntax-flow@^7.18.6", "@babel/plugin-syntax-flow@^7.2.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" + integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" @@ -464,6 +556,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0" + integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.18.6" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -513,12 +612,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" - integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== +"@babel/plugin-syntax-typescript@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285" + integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-typescript@^7.20.0", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" + integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.19.0" "@babel/plugin-transform-arrow-functions@^7.0.0": version "7.10.4" @@ -578,21 +684,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-exponentiation-operator@^7.0.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" - integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.18.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.9.tgz#5b4cc521426263b5ce08893a2db41097ceba35bf" + integrity sha512-+G6rp2zRuOAInY5wcggsx4+QVao1qPM0osC9fTUVlAV3zOrzTCnrMAFVnR6+a3T8wz1wFIH7KhYMcMB3u1n80A== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-flow" "^7.18.6" -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz#291fb140c78dabbf87f2427e7c7c332b126964b8" - integrity sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg== +"@babel/plugin-transform-flow-strip-types@^7.16.7": + version "7.19.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz#e9e8606633287488216028719638cbbb2f2dde8f" + integrity sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-flow" "^7.16.7" + "@babel/helper-plugin-utils" "^7.19.0" + "@babel/plugin-syntax-flow" "^7.18.6" "@babel/plugin-transform-for-of@^7.0.0": version "7.10.4" @@ -633,12 +739,13 @@ "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-object-assign@^7.0.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.10.4.tgz#f7c8f54ce8052ccd8b9da9b3358848423221c338" - integrity sha512-6zccDhYEICfMeQqIjuY5G09/yhKzG30DKHJeYBQUHIsJH7c2jXSGvgwRalufLAXAq432OSlsEfAOLlzEsQzxVw== +"@babel/plugin-transform-named-capturing-groups-regex@^7.0.0": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d" + integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-object-super@^7.0.0": version "7.10.4" @@ -696,13 +803,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-regenerator@^7.0.0": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" - integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== - dependencies: - regenerator-transform "^0.14.2" - "@babel/plugin-transform-runtime@^7.0.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz#e27f78eb36f19448636e05c33c90fd9ad9b8bccf" @@ -744,14 +844,23 @@ "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-typescript@^7.16.7", "@babel/plugin-transform-typescript@^7.5.0": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" - integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== +"@babel/plugin-transform-typescript@^7.16.7": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.13.tgz#e3581b356b8694f6ff450211fe6774eaff8d25ab" + integrity sha512-O7I/THxarGcDZxkgWKMUrk7NK1/WbHAg3Xx86gqS6x9MTrNL6AwIluuZ96ms4xeDe6AVx6rjHbWHP7x26EPQBA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-typescript" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.20.12" + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-typescript" "^7.20.0" + +"@babel/plugin-transform-typescript@^7.5.0": + version "7.18.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.12.tgz#712e9a71b9e00fde9f8c0238e0cceee86ab2f8fd" + integrity sha512-2vjjam0cum0miPkenUbQswKowuxs/NjMwIKEq0zwegRxXk12C9YOF9STXnaUptITOtOJHKHpzvvWYOjbm6tc0w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.18.9" + "@babel/helper-plugin-utils" "^7.18.9" + "@babel/plugin-syntax-typescript" "^7.18.6" "@babel/plugin-transform-unicode-regex@^7.0.0": version "7.10.4" @@ -798,44 +907,61 @@ pirates "^4.0.5" source-map-support "^0.5.16" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.4.3", "@babel/runtime@^7.4.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.4.3", "@babel/runtime@^7.4.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" +"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.3.3": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" + integrity sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + +"@babel/traverse@^7.14.0", "@babel/traverse@^7.18.11", "@babel/traverse@^7.18.9", "@babel/traverse@^7.20.0", "@babel/traverse@^7.20.10", "@babel/traverse@^7.20.12", "@babel/traverse@^7.20.7": + version "7.20.12" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.12.tgz#7f0f787b3a67ca4475adef1f56cb94f6abd4a4b5" + integrity sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + debug "^4.1.0" + globals "^11.1.0" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" +"@babel/traverse@^7.17.3", "@babel/traverse@^7.20.13", "@babel/traverse@^7.7.2": + version "7.20.13" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.13.tgz#817c1ba13d11accca89478bd5481b2d168d07473" + integrity sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ== + dependencies: + "@babel/code-frame" "^7.18.6" + "@babel/generator" "^7.20.7" + "@babel/helper-environment-visitor" "^7.18.9" + "@babel/helper-function-name" "^7.19.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.20.13" + "@babel/types" "^7.20.7" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" + integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== dependencies: - "@babel/helper-validator-identifier" "^7.16.7" + "@babel/helper-string-parser" "^7.19.4" + "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -843,14 +969,6 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - "@dabh/diagnostics@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" @@ -897,172 +1015,221 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== +"@jest/console@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.4.1.tgz#cbc31d73f6329f693b3d34b365124de797704fff" + integrity sha512-m+XpwKSi3PPM9znm5NGS8bBReeAJJpSkL1OuFCqaMaJL2YX9YXLkkI+MBchMPwu+ZuM2rynL51sgfkQteQ1CKQ== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.4.1" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" + jest-message-util "^29.4.1" + jest-util "^29.4.1" slash "^3.0.0" -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== +"@jest/core@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.4.1.tgz#91371179b5959951e211dfaeea4277a01dcca14f" + integrity sha512-RXFTohpBqpaTebNdg5l3I5yadnKo9zLBajMT0I38D0tDhreVBYv3fA8kywthI00sWxPztWLD3yjiUkewwu/wKA== dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.4.1" + "@jest/reporters" "^29.4.1" + "@jest/test-result" "^29.4.1" + "@jest/transform" "^29.4.1" + "@jest/types" "^29.4.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" + ci-info "^3.2.0" exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" + graceful-fs "^4.2.9" + jest-changed-files "^29.4.0" + jest-config "^29.4.1" + jest-haste-map "^29.4.1" + jest-message-util "^29.4.1" + jest-regex-util "^29.2.0" + jest-resolve "^29.4.1" + jest-resolve-dependencies "^29.4.1" + jest-runner "^29.4.1" + jest-runtime "^29.4.1" + jest-snapshot "^29.4.1" + jest-util "^29.4.1" + jest-validate "^29.4.1" + jest-watcher "^29.4.1" + micromatch "^4.0.4" + pretty-format "^29.4.1" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/create-cache-key-function@^27.0.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz#7448fae15602ea95c828f5eceed35c202a820b31" - integrity sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ== +"@jest/create-cache-key-function@^29.2.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.3.1.tgz#3a0970ea595ab3d9507244edbcef14d6b016cdc9" + integrity sha512-4i+E+E40gK13K78ffD/8cy4lSSqeWwyXeTZoq16tndiCP12hC8uQsPJdIu5C6Kf22fD8UbBk71so7s/6VwpUOQ== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^29.3.1" -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== +"@jest/environment@^29.3.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.3.1.tgz#eb039f726d5fcd14698acd072ac6576d41cfcaa6" + integrity sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag== dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/fake-timers" "^29.3.1" + "@jest/types" "^29.3.1" "@types/node" "*" - jest-mock "^26.6.2" + jest-mock "^29.3.1" -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== +"@jest/environment@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.4.1.tgz#52d232a85cdc995b407a940c89c86568f5a88ffe" + integrity sha512-pJ14dHGSQke7Q3mkL/UZR9ZtTOxqskZaC91NzamEH4dlKRt42W+maRBXiw/LWkdJe+P0f/zDR37+SPMplMRlPg== dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" + "@jest/fake-timers" "^29.4.1" + "@jest/types" "^29.4.1" "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-mock "^29.4.1" -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== +"@jest/expect-utils@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.4.1.tgz#105b9f3e2c48101f09cae2f0a4d79a1b3a419cbb" + integrity sha512-w6YJMn5DlzmxjO00i9wu2YSozUYRBhIoJ6nQwpMYcBMtiqMGJm1QBzOf6DDgRao8dbtpDoaqLg6iiQTvv0UHhQ== dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" + jest-get-type "^29.2.0" -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== +"@jest/expect@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.4.1.tgz#3338fa20f547bb6e550c4be37d6f82711cc13c38" + integrity sha512-ZxKJP5DTUNF2XkpJeZIzvnzF1KkfrhEF6Rz0HGG69fHl6Bgx5/GoU3XyaeFYEjuuKSOOsbqD/k72wFvFxc3iTw== + dependencies: + expect "^29.4.1" + jest-snapshot "^29.4.1" + +"@jest/fake-timers@^29.3.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.3.1.tgz#b140625095b60a44de820876d4c14da1aa963f67" + integrity sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A== + dependencies: + "@jest/types" "^29.3.1" + "@sinonjs/fake-timers" "^9.1.2" + "@types/node" "*" + jest-message-util "^29.3.1" + jest-mock "^29.3.1" + jest-util "^29.3.1" + +"@jest/fake-timers@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.4.1.tgz#7b673131e8ea2a2045858f08241cace5d518b42b" + integrity sha512-/1joI6rfHFmmm39JxNfmNAO3Nwm6Y0VoL5fJDy7H1AtWrD1CgRtqJbN9Ld6rhAkGO76qqp4cwhhxJ9o9kYjQMw== + dependencies: + "@jest/types" "^29.4.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.4.1" + jest-mock "^29.4.1" + jest-util "^29.4.1" + +"@jest/globals@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.4.1.tgz#3cd78c5567ab0249f09fbd81bf9f37a7328f4713" + integrity sha512-znoK2EuFytbHH0ZSf2mQK2K1xtIgmaw4Da21R2C/NE/+NnItm5mPEFQmn8gmF3f0rfOlmZ3Y3bIf7bFj7DHxAA== + dependencies: + "@jest/environment" "^29.4.1" + "@jest/expect" "^29.4.1" + "@jest/types" "^29.4.1" + jest-mock "^29.4.1" + +"@jest/reporters@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.4.1.tgz#50d509c08575c75e3cd2176d72ec3786419d5e04" + integrity sha512-AISY5xpt2Xpxj9R6y0RF1+O6GRy9JsGa8+vK23Lmzdy1AYcpQn5ItX79wJSsTmfzPKSAcsY1LNt/8Y5Xe5LOSg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.4.1" + "@jest/test-result" "^29.4.1" + "@jest/transform" "^29.4.1" + "@jest/types" "^29.4.1" + "@jridgewell/trace-mapping" "^0.3.15" + "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" + glob "^7.1.3" + graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" + istanbul-lib-instrument "^5.1.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" + istanbul-reports "^3.1.3" + jest-message-util "^29.4.1" + jest-util "^29.4.1" + jest-worker "^29.4.1" slash "^3.0.0" - source-map "^0.6.0" string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/schemas@^29.4.0": + version "29.4.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.0.tgz#0d6ad358f295cc1deca0b643e6b4c86ebd539f17" + integrity sha512-0E01f/gOZeNTG76i5eWWSupvSHaIINrTie7vCyjiYFKgzNdyEGd12BUv4oNBFHOqlHDbtoJi3HrQ38KCC90NsQ== dependencies: + "@sinclair/typebox" "^0.25.16" + +"@jest/source-map@^29.2.0": + version "29.2.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.2.0.tgz#ab3420c46d42508dcc3dc1c6deee0b613c235744" + integrity sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" + graceful-fs "^4.2.9" -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== +"@jest/test-result@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.4.1.tgz#997f19695e13b34779ceb3c288a416bd26c3238d" + integrity sha512-WRt29Lwt+hEgfN8QDrXqXGgCTidq1rLyFqmZ4lmJOpVArC8daXrZWkWjiaijQvgd3aOUj2fM8INclKHsQW9YyQ== dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.4.1" + "@jest/types" "^29.4.1" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== +"@jest/test-sequencer@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.4.1.tgz#f7a006ec7058b194a10cf833c88282ef86d578fd" + integrity sha512-v5qLBNSsM0eHzWLXsQ5fiB65xi49A3ILPSFQKPXzGL4Vyux0DPZAIN7NAFJa9b4BiTDP9MBF/Zqc/QA1vuiJ0w== dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" + "@jest/test-result" "^29.4.1" + graceful-fs "^4.2.9" + jest-haste-map "^29.4.1" + slash "^3.0.0" -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== +"@jest/transform@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.4.1.tgz#e4f517841bb795c7dcdee1ba896275e2c2d26d4a" + integrity sha512-5w6YJrVAtiAgr0phzKjYd83UPbCXsBRTeYI4BXokv9Er9CcrH9hfXL/crCvP2d2nGOcovPUnlYiLPFLZrkG5Hg== dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" + "@babel/core" "^7.11.6" + "@jest/types" "^29.4.1" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.4.1" + jest-regex-util "^29.2.0" + jest-util "^29.4.1" + micromatch "^4.0.4" + pirates "^4.0.4" slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" + write-file-atomic "^5.0.0" "@jest/types@^26.6.2": version "26.6.2" @@ -1086,6 +1253,30 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^29.3.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.3.1.tgz#7c5a80777cb13e703aeec6788d044150341147e3" + integrity sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jest/types@^29.4.1": + version "29.4.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.4.1.tgz#f9f83d0916f50696661da72766132729dcb82ecb" + integrity sha512-zbrAXDUOnpJ+FMST2rV7QZOgec8rskg2zv8g2ajeqitp4tvZiyqTCYXANrKsM+ryj5o+LI+ZN2EgU9drrkiwSA== + dependencies: + "@jest/schemas" "^29.4.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jimp/bmp@^0.10.3": version "0.10.3" resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.10.3.tgz#79a23678e8389865c62e77b0dccc3e069dfc27f0" @@ -1658,24 +1849,64 @@ dependencies: core-js "^2.5.7" +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" + integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + "@jridgewell/resolve-uri@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.11" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== -"@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== +"@jridgewell/trace-mapping@^0.3.0", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -1835,184 +2066,179 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.3.0.tgz#0d740709fd65845c9cab215d5581e9fa80c59520" integrity sha512-7lmGpLL/7EHQcLVBxxOesgQQS7JSxzF/Xqx7VNMxAQbo14dzJEX6Ks0hb4LHqEMpCrKpErWXi4JxYCGrRJgx9A== -"@react-native-community/cli-debugger-ui@^7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-7.0.3.tgz#3eeeacc5a43513cbcae56e5e965d77726361bcb4" - integrity sha512-G4SA6jFI0j22o+j+kYP8/7sxzbCDqSp2QiHA/X5E0lsGEd2o9qN2zbIjiFr8b8k+VVAYSUONhoC0+uKuINvmkA== +"@react-native-community/cli-clean@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-clean/-/cli-clean-10.1.1.tgz#4c73ce93a63a24d70c0089d4025daac8184ff504" + integrity sha512-iNsrjzjIRv9yb5y309SWJ8NDHdwYtnCpmxZouQDyOljUdC9MwdZ4ChbtA4rwQyAwgOVfS9F/j56ML3Cslmvrxg== + dependencies: + "@react-native-community/cli-tools" "^10.1.1" + chalk "^4.1.2" + execa "^1.0.0" + prompts "^2.4.0" + +"@react-native-community/cli-config@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-config/-/cli-config-10.1.1.tgz#08dcc5d7ca1915647dc06507ed853fe0c1488395" + integrity sha512-p4mHrjC+s/ayiNVG6T35GdEGdP6TuyBUg5plVGRJfTl8WT6LBfLYLk+fz/iETrEZ/YkhQIsQcEUQC47MqLNHog== + dependencies: + "@react-native-community/cli-tools" "^10.1.1" + chalk "^4.1.2" + cosmiconfig "^5.1.0" + deepmerge "^3.2.0" + glob "^7.1.3" + joi "^17.2.1" + +"@react-native-community/cli-debugger-ui@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-10.0.0.tgz#4bb6d41c7e46449714dc7ba5d9f5b41ef0ea7c57" + integrity sha512-8UKLcvpSNxnUTRy8CkCl27GGLqZunQ9ncGYhSrWyKrU9SWBJJGeZwi2k2KaoJi5FvF2+cD0t8z8cU6lsq2ZZmA== dependencies: serve-static "^1.13.1" -"@react-native-community/cli-hermes@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-6.3.0.tgz#92b2f07d08626a60f6893c3e3d57c1538c8fb5a7" - integrity sha512-Uhbm9bubyZLZ12vFCIfWbE/Qi3SBTbYIN/TC08EudTLhv/KbPomCQnmFsnJ7AXQFuOZJs73mBxoEAYSbRbwyVA== +"@react-native-community/cli-doctor@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-10.1.1.tgz#6d60a2df74ea112d1f3b41491b6ee0948daa4fb3" + integrity sha512-9uvUhr6aJu4C7pCTsD9iRS/38tx1mzIrWuEQoh2JffTXg9MOq4jesvobkyKFRD90nOvqunEvfpnWnRdWcZO0Wg== dependencies: - "@react-native-community/cli-platform-android" "^6.3.0" - "@react-native-community/cli-tools" "^6.2.0" + "@react-native-community/cli-config" "^10.1.1" + "@react-native-community/cli-platform-ios" "^10.1.1" + "@react-native-community/cli-tools" "^10.1.1" chalk "^4.1.2" + command-exists "^1.2.8" + envinfo "^7.7.2" + execa "^1.0.0" hermes-profile-transformer "^0.0.6" ip "^1.1.5" + node-stream-zip "^1.9.1" + ora "^5.4.1" + prompts "^2.4.0" + semver "^6.3.0" + strip-ansi "^5.2.0" + sudo-prompt "^9.0.0" + wcwidth "^1.0.1" -"@react-native-community/cli-platform-android@^6.3.0": - version "6.3.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-6.3.0.tgz#ab7d156bd69a392493323eeaba839a874c0e201f" - integrity sha512-d5ufyYcvrZoHznYm5bjBXaiHIJv552t5gYtQpnUsxBhHSQ8QlaNmlLUyeSPRDfOw4ND9b0tPHqs4ufwx6vp/fQ== +"@react-native-community/cli-hermes@^10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-hermes/-/cli-hermes-10.1.3.tgz#440e2ff0f2ac9aba0ca1daee6ffaaf9c093437cc" + integrity sha512-uYl8MLBtuu6bj0tDUzVGf30nK5i9haBv7F0u+NCOq31+zVjcwiUplrCuLorb2dMLMF+Fno9wDxi66W9MxoW4nA== dependencies: - "@react-native-community/cli-tools" "^6.2.0" + "@react-native-community/cli-platform-android" "^10.1.3" + "@react-native-community/cli-tools" "^10.1.1" chalk "^4.1.2" - execa "^1.0.0" - fs-extra "^8.1.0" - glob "^7.1.3" - jetifier "^1.6.2" - lodash "^4.17.15" - logkitty "^0.7.1" - slash "^3.0.0" - xmldoc "^1.1.2" + hermes-profile-transformer "^0.0.6" + ip "^1.1.5" -"@react-native-community/cli-platform-android@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-7.0.1.tgz#d165897edf401f9bceff1f361ef446528133cb52" - integrity sha512-nOr0aMkxAymCnbtsQwXBlyoRN2Y+IzC7Qz5T+/zyWwEbTY8SKQI8uV+8+qttUvzSvuXa2PeXsTWluuliOS8KCw== +"@react-native-community/cli-platform-android@10.0.0", "@react-native-community/cli-platform-android@10.1.3", "@react-native-community/cli-platform-android@10.2.0", "@react-native-community/cli-platform-android@^10.1.3": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-10.1.3.tgz#8380799cd4d3f9a0ca568b0f5b4ae9e462ce3669" + integrity sha512-8YZEpBL6yd9l4CIoFcLOgrV8x2GDujdqrdWrNsNERDAbsiFwqAQvfjyyb57GAZVuEPEJCoqUlGlMCwOh3XQb9A== dependencies: - "@react-native-community/cli-tools" "^7.0.1" + "@react-native-community/cli-tools" "^10.1.1" chalk "^4.1.2" execa "^1.0.0" - fs-extra "^8.1.0" glob "^7.1.3" - jetifier "^1.6.2" - lodash "^4.17.15" logkitty "^0.7.1" - slash "^3.0.0" - xmldoc "^1.1.2" -"@react-native-community/cli-platform-ios@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-7.0.1.tgz#1c27af85229246b7a528e97f093e38859896cc93" - integrity sha512-PLRIbzrCzSedmpjuFtQqcqUD45G8q7sEciI1lf5zUbVMXqjIBwJWS7iz8235PyWwj8J4MNHohLC+oyRueFtbGg== +"@react-native-community/cli-platform-ios@10.0.0", "@react-native-community/cli-platform-ios@10.1.1", "@react-native-community/cli-platform-ios@10.2.1", "@react-native-community/cli-platform-ios@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.1.1.tgz#39ed6810117d8e7330d3aa4d85818fb6ae358785" + integrity sha512-EB9/L8j1LqrqyfJtLRixU+d8FIP6Pr83rEgUgXgya/u8wk3h/bvX70w+Ff2skwjdPLr5dLUQ/n5KFX4r3bsNmA== dependencies: - "@react-native-community/cli-tools" "^7.0.1" + "@react-native-community/cli-tools" "^10.1.1" chalk "^4.1.2" execa "^1.0.0" glob "^7.1.3" - js-yaml "^3.13.1" - lodash "^4.17.15" ora "^5.4.1" - plist "^3.0.2" - xcode "^3.0.0" -"@react-native-community/cli-plugin-metro@^7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-7.0.3.tgz#b381ed2f68a0b126e4fa238f1956a44846e1ef8a" - integrity sha512-HJrEkFbxv9DNixsGwO+Q0zCcZMghDltyzeB9yQ//D5ZR4ZUEuAIPrRDdEp9xVw0WkBxAIZs6KXLux2/yPMwLhA== +"@react-native-community/cli-plugin-metro@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-10.1.1.tgz#8b8689c921f6f0aeafa7ea9aabbde4c482b376b7" + integrity sha512-wEp47le4mzlelDF5sfkaaujUDYcuLep5HZqlcMx7PkL7BA3/fSHdDo1SblqaLgZ1ca6vFU+kfbHueLDct+xwFg== dependencies: - "@react-native-community/cli-server-api" "^7.0.3" - "@react-native-community/cli-tools" "^6.2.0" + "@react-native-community/cli-server-api" "^10.1.1" + "@react-native-community/cli-tools" "^10.1.1" chalk "^4.1.2" - metro "^0.67.0" - metro-config "^0.67.0" - metro-core "^0.67.0" - metro-react-native-babel-transformer "^0.67.0" - metro-resolver "^0.67.0" - metro-runtime "^0.67.0" + execa "^1.0.0" + metro "0.73.7" + metro-config "0.73.7" + metro-core "0.73.7" + metro-react-native-babel-transformer "0.73.7" + metro-resolver "0.73.7" + metro-runtime "0.73.7" readline "^1.3.0" -"@react-native-community/cli-server-api@^7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-7.0.3.tgz#ba9695a2fdfef22750d141153efd94baf641129b" - integrity sha512-JDrLsrkBgNxbG2u3fouoVGL9tKrXUrTsaNwr+oCV+3XyMwbVe42r/OaQ681/iW/7mHXjuVkDnMcp7BMg7e2yJg== +"@react-native-community/cli-server-api@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-server-api/-/cli-server-api-10.1.1.tgz#e382269de281bb380c2e685431364fbbb8c1cb3a" + integrity sha512-NZDo/wh4zlm8as31UEBno2bui8+ufzsZV+KN7QjEJWEM0levzBtxaD+4je0OpfhRIIkhaRm2gl/vVf7OYAzg4g== dependencies: - "@react-native-community/cli-debugger-ui" "^7.0.3" - "@react-native-community/cli-tools" "^6.2.0" + "@react-native-community/cli-debugger-ui" "^10.0.0" + "@react-native-community/cli-tools" "^10.1.1" compression "^1.7.1" connect "^3.6.5" errorhandler "^1.5.0" - nocache "^2.1.0" + nocache "^3.0.1" pretty-format "^26.6.2" serve-static "^1.13.1" ws "^7.5.1" -"@react-native-community/cli-tools@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-6.2.0.tgz#8f4adc2d83ab96e5654348533c8fa602742c4fce" - integrity sha512-08ssz4GMEnRxC/1FgTTN/Ud7mExQi5xMphItPjfHiTxpZPhrFn+IMx6mya0ncFEhhxQ207wYlJMRLPRRdBZ8oA== +"@react-native-community/cli-tools@^10.1.1": + version "10.1.1" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-10.1.1.tgz#fa66e509c0d3faa31f7bb87ed7d42ad63f368ddd" + integrity sha512-+FlwOnZBV+ailEzXjcD8afY2ogFEBeHOw/8+XXzMgPaquU2Zly9B+8W089tnnohO3yfiQiZqkQlElP423MY74g== dependencies: appdirsjs "^1.2.4" chalk "^4.1.2" - lodash "^4.17.15" + find-up "^5.0.0" mime "^2.4.1" node-fetch "^2.6.0" open "^6.2.0" + ora "^5.4.1" semver "^6.3.0" - shell-quote "1.6.1" + shell-quote "^1.7.3" -"@react-native-community/cli-tools@^7.0.1": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-7.0.1.tgz#73790d6ca2825e42a70a770c1b403a6777e690d6" - integrity sha512-0xra4hKNA5PR2zYVXsDMNiXMGaDNoNRYMY6eTP2aVIxQbqIcVMDWSyCA8wMWX5iOpMWg0cZGaQ6a77f3Rlb34g== +"@react-native-community/cli-types@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-10.0.0.tgz#046470c75ec18f8b3bd906e54e43a6f678e01a45" + integrity sha512-31oUM6/rFBZQfSmDQsT1DX/5fjqfxg7sf2u8kTPJK7rXVya5SRpAMaCXsPAG0omsmJxXt+J9HxUi3Ic+5Ux5Iw== dependencies: - appdirsjs "^1.2.4" + joi "^17.2.1" + +"@react-native-community/cli@10.0.0", "@react-native-community/cli@10.1.3", "@react-native-community/cli@10.2.2": + version "10.1.3" + resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-10.1.3.tgz#ad610c46da9fc7c717272024ec757dc646726506" + integrity sha512-kzh6bYLGN1q1q0IiczKSP1LTrovFeVzppYRTKohPI9VdyZwp7b5JOgaQMB/Ijtwm3MxBDrZgV9AveH/eUmUcKQ== + dependencies: + "@react-native-community/cli-clean" "^10.1.1" + "@react-native-community/cli-config" "^10.1.1" + "@react-native-community/cli-debugger-ui" "^10.0.0" + "@react-native-community/cli-doctor" "^10.1.1" + "@react-native-community/cli-hermes" "^10.1.3" + "@react-native-community/cli-plugin-metro" "^10.1.1" + "@react-native-community/cli-server-api" "^10.1.1" + "@react-native-community/cli-tools" "^10.1.1" + "@react-native-community/cli-types" "^10.0.0" chalk "^4.1.2" - lodash "^4.17.15" - mime "^2.4.1" - node-fetch "^2.6.0" - open "^6.2.0" - ora "^5.4.1" - semver "^6.3.0" - shell-quote "^1.7.3" - -"@react-native-community/cli-types@^6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-6.0.0.tgz#90269fbdc7229d5e3b8f2f3e029a94083551040d" - integrity sha512-K493Fk2DMJC0ZM8s8gnfseKxGasIhuDaCUDeLZcoCSFlrjKEuEs1BKKEJiev0CARhKEXKOyyp/uqYM9nWhisNw== - dependencies: - ora "^3.4.0" - -"@react-native-community/cli@^7.0.3": - version "7.0.3" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-7.0.3.tgz#1addb462d71786fcbbd266fbceb41819b8cf7839" - integrity sha512-WyJOA829KAhU1pw2MDQt0YhOS9kyR2KqyqgJyTuQhzFVCBPX4F5aDEkZYYn4jdldaDHCPrLJ3ho3gxYTXy+x7w== - dependencies: - "@react-native-community/cli-debugger-ui" "^7.0.3" - "@react-native-community/cli-hermes" "^6.3.0" - "@react-native-community/cli-plugin-metro" "^7.0.3" - "@react-native-community/cli-server-api" "^7.0.3" - "@react-native-community/cli-tools" "^6.2.0" - "@react-native-community/cli-types" "^6.0.0" - appdirsjs "^1.2.4" - chalk "^4.1.2" - command-exists "^1.2.8" - commander "^2.19.0" - cosmiconfig "^5.1.0" - deepmerge "^3.2.0" - envinfo "^7.7.2" + commander "^9.4.1" execa "^1.0.0" find-up "^4.1.0" fs-extra "^8.1.0" - glob "^7.1.3" graceful-fs "^4.1.3" - joi "^17.2.1" - leven "^3.1.0" - lodash "^4.17.15" - minimist "^1.2.0" - node-stream-zip "^1.9.1" - ora "^3.4.0" - pretty-format "^26.6.2" prompts "^2.4.0" semver "^6.3.0" - serve-static "^1.13.1" - strip-ansi "^5.2.0" - sudo-prompt "^9.0.0" - wcwidth "^1.0.1" -"@react-native-windows/cli@0.68.2": - version "0.68.2" - resolved "https://registry.yarnpkg.com/@react-native-windows/cli/-/cli-0.68.2.tgz#6c47f9e5c43a4132892a9bf1df5f58ead09b851e" - integrity sha512-hbWUy4EiWapkLfP5rouMb7yRiVvltOAJex1WlwfEfbVLWPg0WAf1mtMfc10VViorFk6xNL9JjVPzbaUO4tO58A== - dependencies: - "@react-native-windows/fs" "0.68.0" - "@react-native-windows/package-utils" "0.68.0" - "@react-native-windows/telemetry" "0.68.2" - "@xmldom/xmldom" "^0.7.5" +"@react-native-windows/cli@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/cli/-/cli-0.71.0.tgz#2e18423eeef6048b206edf7f14e4efe4610d6ff2" + integrity sha512-NlkapPGJGC4Gg6xW5gDqFziNbUFFCU3bXBwKVBt9WZeSrmxKfW1Nc0nSWVxt8Tn0pfF2480px0N/HDY/rfwpYg== + dependencies: + "@react-native-windows/codegen" "0.71.0" + "@react-native-windows/fs" "0.71.0" + "@react-native-windows/package-utils" "0.71.0" + "@react-native-windows/telemetry" "0.71.0" + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" + "@xmldom/xmldom" "^0.7.7" chalk "^4.1.0" cli-spinners "^2.2.0" envinfo "^7.5.0" @@ -2030,61 +2256,76 @@ xml-parser "^1.2.1" xpath "^0.0.27" -"@react-native-windows/find-repo-root@0.68.0": - version "0.68.0" - resolved "https://registry.yarnpkg.com/@react-native-windows/find-repo-root/-/find-repo-root-0.68.0.tgz#efbc5af3a4952a7e7712f8d6bd73b8de858f3d7d" - integrity sha512-YuSUlrRdr6SNPapf4b77yi3U/rfTeYhetBpSwm1L/jq3UT8Wm4Z/JSBZg2UioYIeQV6xrNRjlLQHKjDBzmxOkQ== +"@react-native-windows/codegen@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/codegen/-/codegen-0.71.0.tgz#f31aecc0c595642a073c2531ee3dab0469843ffd" + integrity sha512-sLheajiQwC3fXZDm9cZ6uZQQ3LrL2Mlm8t24FS6p7g3JqshyRvLeYr6EFaI7RzvWbvzAW1tBUTVVVMvhWrE2jQ== + dependencies: + "@react-native-windows/fs" "0.71.0" + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" + chalk "^4.1.0" + globby "^11.0.4" + mustache "^4.0.1" + source-map-support "^0.5.19" + yargs "^16.2.0" + +"@react-native-windows/find-repo-root@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/find-repo-root/-/find-repo-root-0.71.0.tgz#51faaa2406f180714433d6df71dedb7b3a98353a" + integrity sha512-znR9i2J7nA0C7OXOlDy8aHUL7eYHDZrn1CAv2VKyUC0aKxuA0MHT4sJaXLzUUknQu6XUjrK2eDLKaoaEfjE45Q== dependencies: + "@react-native-windows/fs" "0.71.0" + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" find-up "^4.1.0" -"@react-native-windows/fs@0.68.0": - version "0.68.0" - resolved "https://registry.yarnpkg.com/@react-native-windows/fs/-/fs-0.68.0.tgz#bdf722b9c7475e66de9a580b37cdb7136af797a4" - integrity sha512-2ZnL0NVs6zJQgXypyX1Arh7Xyo8mG1yKw1ephbOX5U6J7HLlnsx3X1sANGIz+JcAjA9jEJ08r9DHbH93NvzFWA== +"@react-native-windows/fs@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/fs/-/fs-0.71.0.tgz#7aaeb83c33a77dd032d987efdd0528e22430c2a1" + integrity sha512-hQkJ9nSUzBs+UUKJhhH4N+59lrcSws94x2kOu8EbjlK8ZNqQgwm6WPDmyKD10xdZnnuNs8xA47WZIUSn028nYw== dependencies: + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" graceful-fs "^4.2.8" -"@react-native-windows/package-utils@0.68.0": - version "0.68.0" - resolved "https://registry.yarnpkg.com/@react-native-windows/package-utils/-/package-utils-0.68.0.tgz#072b838fd106aedaff746ae6fab5173b6c61880a" - integrity sha512-IgcZib3Ydhosk8HoN/9l/im/EzeualqQPku/aRUyLehKjYEi7YksUDEM3un9bWyAwCeT9gpIjbEnEFwODQdvZg== +"@react-native-windows/package-utils@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/package-utils/-/package-utils-0.71.0.tgz#587900ddca58058633b7c990c15898ce4d1fbb0e" + integrity sha512-HBn8lTvCA6tf+yu3mrLvZzhsUtOPBrMSn9zSFL0f6LDI9C4CHaGIzEqRmAwfmG3CHB1xc2get9VGKRMKQqDmlQ== dependencies: - "@react-native-windows/find-repo-root" "0.68.0" - "@react-native-windows/fs" "0.68.0" + "@react-native-windows/find-repo-root" "0.71.0" + "@react-native-windows/fs" "0.71.0" + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" get-monorepo-packages "^1.2.0" lodash "^4.17.15" -"@react-native-windows/telemetry@0.68.2": - version "0.68.2" - resolved "https://registry.yarnpkg.com/@react-native-windows/telemetry/-/telemetry-0.68.2.tgz#c693f66e9e4032cce6256ef777c0033b7e5fb262" - integrity sha512-tkd7eJM3Jhs6aenL0Iz8msRbK22GGgYvaSViCLBkenlwOdF0AE/r0+NAGGXzOxHz89GIDYUhj5rtpln83NtWXA== +"@react-native-windows/telemetry@0.71.0": + version "0.71.0" + resolved "https://registry.yarnpkg.com/@react-native-windows/telemetry/-/telemetry-0.71.0.tgz#dd4997526d5fc08ad5de8e7db505d59b51a9d602" + integrity sha512-lVsAAhIz7CUX5yzONqIkl9zhgrIKSjfONWxVYoTUGTq/PPHqOfGNTw751DSWzlmvUZgxG1zzVfYPit1Blw07DA== dependencies: - "@react-native-windows/fs" "0.68.0" - "@xmldom/xmldom" "^0.7.5" + "@react-native-windows/fs" "0.71.0" + "@typescript-eslint/eslint-plugin" "^5.30.5" + "@typescript-eslint/parser" "^5.30.5" + "@xmldom/xmldom" "^0.7.7" applicationinsights "^2.3.1" ci-info "^3.2.0" envinfo "^7.8.1" lodash "^4.17.21" - node-machine-id "^1.1.12" os-locale "^5.0.0" xpath "^0.0.27" -"@react-native-windows/virtualized-list@0.68.0": - version "0.68.0" - resolved "https://registry.yarnpkg.com/@react-native-windows/virtualized-list/-/virtualized-list-0.68.0.tgz#06b63d21bad896c2bd37d6b5544f90f0f4fa838b" - integrity sha512-XKqwn7FWDUVanr42sNT+547je2YwCq38I3YR+iq1WcmH5TiQ5E+KF5jXvPv7oOFuWJzzXzjiRZUfEwMv2qqoMg== - dependencies: - invariant "^2.2.4" - "@react-native/assets@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@react-native/assets/-/assets-1.0.0.tgz#c6f9bf63d274bafc8e970628de24986b30a55c8e" integrity sha512-KrwSpS1tKI70wuKl68DwJZYEvXktDHdZMG0k2AXD/rJVSlB23/X2CB2cutVR0HwNMJIal9HOUOBB2rVfa6UGtQ== -"@react-native/normalize-color@*", "@react-native/normalize-color@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.0.0.tgz#da955909432474a9a0fe1cbffc66576a0447f567" - integrity sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw== +"@react-native/normalize-color@*", "@react-native/normalize-color@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.1.0.tgz#939b87a9849e81687d3640c5efa2a486ac266f91" + integrity sha512-Z1jQI2NpdFJCVgpY+8Dq/Bt3d+YUi1928Q+/CZm/oh66fzM0RUl54vvuXlPJKybH4pdCZey1eDTPaLHkMPNgWA== "@react-native/polyfills@2.0.0": version "2.0.0" @@ -2197,6 +2438,16 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sinclair/typebox@^0.24.1": + version "0.24.51" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" + integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== + +"@sinclair/typebox@^0.25.16": + version "0.25.21" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.21.tgz#763b05a4b472c93a8db29b2c3e359d55b29ce272" + integrity sha512-gFukHN4t8K4+wVC+ECqeqwzBDeFeTzBXroBTqE6vcWrQGbEUpHO7LYdG0f4xnvYq4VOEwITSlHlp0JBAIFMS/g== + "@sindresorhus/is@^3.0.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-3.1.2.tgz#548650de521b344e3781fbdb0ece4aa6f729afb8" @@ -2209,10 +2460,24 @@ dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== +"@sinonjs/commons@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" + integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" + integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== + dependencies: + "@sinonjs/commons" "^2.0.0" + +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== dependencies: "@sinonjs/commons" "^1.7.0" @@ -2223,18 +2488,13 @@ dependencies: defer-to-connect "^2.0.0" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.1.18" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" - integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== +"@types/babel__core@^7.1.14": + version "7.20.0" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" + integrity sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ== dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" "@types/babel__generator" "*" "@types/babel__template" "*" "@types/babel__traverse" "*" @@ -2254,7 +2514,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.14.2" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== @@ -2294,10 +2554,10 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/graceful-fs@^4.1.2": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== dependencies: "@types/node" "*" @@ -2330,18 +2590,18 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.0": - version "26.0.24" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.24.tgz#943d11976b16739185913a1936e0de0c4a7d595a" - integrity sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w== +"@types/jest@^29.4.0": + version "29.4.0" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206" + integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ== dependencies: - jest-diff "^26.0.0" - pretty-format "^26.0.0" + expect "^29.0.0" + pretty-format "^29.0.0" -"@types/json-schema@^7.0.3": - version "7.0.5" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" - integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/keyv@*": version "3.1.1" @@ -2378,10 +2638,10 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== -"@types/prettier@^2.0.0": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" - integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== +"@types/prettier@^2.1.5": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== "@types/prop-types@*": version "15.7.3" @@ -2395,17 +2655,10 @@ dependencies: "@types/node" "*" -"@types/react-native@^0.67.3": - version "0.67.3" - resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.67.3.tgz#baba111c8ce1a45a6034c15f6f0ad98826239780" - integrity sha512-hF4uOZFl2PPQtGWOtLoafrlCJeU815X3PgfVePM+7EhOIZhYXKH7+p3R3cZSnwVnrU5Ep/JfiHimMDliY3o8oQ== - dependencies: - "@types/react" "*" - -"@types/react@*", "@types/react@^17.0.0": - version "17.0.39" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce" - integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug== +"@types/react@18.0.27": + version "18.0.27" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.27.tgz#d9425abe187a00f8a5ec182b010d4fd9da703b71" + integrity sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2443,6 +2696,11 @@ resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.0.9.tgz#12621e55b2ef8f6c98bd17fe23fa720c6cba16bd" integrity sha512-HopIwBE7GUXsscmt/J0DhnFXLSmO04AfxT6b8HAprknwka7pqEWquWDMXxCjd+NUHK9MkCe1SDKKsMiNmCItbQ== +"@types/semver@^7.3.12": + version "7.3.13" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" + integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== + "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -2479,6 +2737,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.19" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.19.tgz#8dbecdc9ab48bee0cb74f6e3327de3fa0d0c98ae" + integrity sha512-cAx3qamwaYX9R0fzOIZAlFpo4A+1uBVCxqpKz9D26uTF4srRXaGTTsikQmaotCtNdbhzyUH7ft6p9ktz9s6UNQ== + dependencies: + "@types/yargs-parser" "*" + "@types/yauzl@^2.9.1": version "2.9.1" resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.1.tgz#d10f69f9f522eef3cf98e30afb684a1e1ec923af" @@ -2497,6 +2762,21 @@ regexpp "^2.0.1" tsutils "^3.14.0" +"@typescript-eslint/eslint-plugin@^5.30.5": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.0.tgz#54f8368d080eb384a455f60c2ee044e948a8ce67" + integrity sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ== + dependencies: + "@typescript-eslint/scope-manager" "5.48.0" + "@typescript-eslint/type-utils" "5.48.0" + "@typescript-eslint/utils" "5.48.0" + debug "^4.3.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/experimental-utils@2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.1.0.tgz#0837229f0e75a32db0db9bf662ad0eface914453" @@ -2516,6 +2796,39 @@ "@typescript-eslint/typescript-estree" "2.1.0" eslint-visitor-keys "^1.0.0" +"@typescript-eslint/parser@^5.30.5": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.48.0.tgz#02803355b23884a83e543755349809a50b7ed9ba" + integrity sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg== + dependencies: + "@typescript-eslint/scope-manager" "5.48.0" + "@typescript-eslint/types" "5.48.0" + "@typescript-eslint/typescript-estree" "5.48.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.48.0.tgz#607731cb0957fbc52fd754fd79507d1b6659cecf" + integrity sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow== + dependencies: + "@typescript-eslint/types" "5.48.0" + "@typescript-eslint/visitor-keys" "5.48.0" + +"@typescript-eslint/type-utils@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.48.0.tgz#40496dccfdc2daa14a565f8be80ad1ae3882d6d6" + integrity sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g== + dependencies: + "@typescript-eslint/typescript-estree" "5.48.0" + "@typescript-eslint/utils" "5.48.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.48.0.tgz#d725da8dfcff320aab2ac6f65c97b0df30058449" + integrity sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw== + "@typescript-eslint/typescript-estree@2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.1.0.tgz#88e676cc9760516711f6fe43958adc31b93de8e5" @@ -2526,6 +2839,41 @@ lodash.unescape "4.0.1" semver "^6.2.0" +"@typescript-eslint/typescript-estree@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.0.tgz#a7f04bccb001003405bb5452d43953a382c2fac2" + integrity sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw== + dependencies: + "@typescript-eslint/types" "5.48.0" + "@typescript-eslint/visitor-keys" "5.48.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.48.0.tgz#eee926af2733f7156ad8d15e51791e42ce300273" + integrity sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.48.0" + "@typescript-eslint/types" "5.48.0" + "@typescript-eslint/typescript-estree" "5.48.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.48.0": + version "5.48.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.0.tgz#4446d5e7f6cadde7140390c0e284c8702d944904" + integrity sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q== + dependencies: + "@typescript-eslint/types" "5.48.0" + eslint-visitor-keys "^3.3.0" + "@wdio/config@5.22.4": version "5.22.4" resolved "https://registry.yarnpkg.com/@wdio/config/-/config-5.22.4.tgz#053d4ba0a8b0dae6be740b1b7b9ab25abac2799e" @@ -2603,10 +2951,10 @@ dependencies: "@wdio/logger" "6.0.16" -"@xmldom/xmldom@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" - integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A== +"@xmldom/xmldom@^0.7.7": + version "0.7.9" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.9.tgz#7f9278a50e737920e21b297b8a35286e9942c056" + integrity sha512-yceMpm/xd4W2a85iqZyO09gTnHvXF6pyiWjD2jcOJs7hRoZtNNOO1eJlhHj1ixA+xip2hOyGn+LgcvLCMo5zXA== JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5: version "1.3.5" @@ -2616,11 +2964,6 @@ JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.3, abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - abbrev@1, abbrev@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -2646,33 +2989,20 @@ accepts@^1.3.7, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.34" negotiator "0.6.3" -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - acorn-jsx@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - acorn@^7.1.1: version "7.4.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== -acorn@^8.2.4: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +acorn@^8.5.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== adbkit-apkreader@^3.1.2: version "3.2.0" @@ -2695,13 +3025,6 @@ agent-base@5: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - agent-base@~4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -2799,10 +3122,10 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" @@ -2819,6 +3142,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + ansi-wrap@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" @@ -2839,14 +3167,6 @@ any-base@^1.1.0: resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - anymatch@^3.0.3: version "3.1.2" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" @@ -3565,11 +3885,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-filter@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" - integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -3589,16 +3904,6 @@ array-includes@^3.0.3, array-includes@^3.1.1: es-abstract "^1.17.0" is-string "^1.0.5" -array-map@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" - integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= - -array-reduce@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" - integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= - array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -3707,17 +4012,17 @@ async-lock@^1.0.0, async-lock@^1.2.2: resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.4.tgz#80d0d612383045dd0c30eb5aad08510c1397cb91" integrity sha512-UBQJC2pbeyGutIfYmErGc9RaJYnpZ1FHaxuKwb0ahvGiiCkPUf3p67Io+YLPmmv3RHY+mF6JEtNW8FlHsraAaA== -async@^2.4.0, async@^2.6.0, async@^2.6.2, async@^2.6.3: +async@^2.6.0, async@^2.6.2, async@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: lodash "^4.17.14" -async@^3.1.0, async@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" - integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== +async@^3.1.0, async@^3.2.0, async@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== asyncbox@2.x, asyncbox@^2.0.2, asyncbox@^2.0.4, asyncbox@^2.3.0, asyncbox@^2.3.1, asyncbox@^2.3.2, asyncbox@^2.5.2, asyncbox@^2.5.3, asyncbox@^2.6.0: version "2.6.0" @@ -3772,18 +4077,17 @@ babel-core@^7.0.0-bridge.0: resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== +babel-jest@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.4.1.tgz#01fa167e27470b35c2d4a1b841d9586b1764da19" + integrity sha512-xBZa/pLSsF/1sNpkgsiT3CmY7zV1kAsZ9OxxtrFqYucnOuRftXAfcJqcDVyOPeN4lttWTwhLdu0T9f8uvoPEUg== dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" + "@jest/transform" "^29.4.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.4.0" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" slash "^3.0.0" babel-plugin-dynamic-import-node@^2.3.3: @@ -3793,7 +4097,7 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" -babel-plugin-istanbul@^6.0.0: +babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== @@ -3804,14 +4108,14 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== +babel-plugin-jest-hoist@^29.4.0: + version "29.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.4.0.tgz#3fd3dfcedf645932df6d0c9fc3d9a704dd860248" + integrity sha512-a/sZRLQJEmsmejQ2rPEUe35nO1+C9dc9O1gplH1SXmJxveQSRUYdBk8yGZG/VOUuZs1u2aHZJusEGoRMbhhwCg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" + "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: @@ -3870,12 +4174,12 @@ babel-preset-fbjs@^3.4.0: "@babel/plugin-transform-template-literals" "^7.0.0" babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== +babel-preset-jest@^29.4.0: + version "29.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.4.0.tgz#c2b03c548b02dea0a18ae21d5759c136f9251ee4" + integrity sha512-fUB9vZflUSM3dO/6M2TCAepTzvA4VkOvl67PjErcrQMGt9Eve7uazaeyCZ2th3UtI7ljpiBJES0F7A1vBRsLZA== dependencies: - babel-plugin-jest-hoist "^26.6.2" + babel-plugin-jest-hoist "^29.4.0" babel-preset-current-node-syntax "^1.0.0" babel-runtime@^6.26.0: @@ -3891,7 +4195,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3933,7 +4237,7 @@ before-after-hook@^2.0.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== -big-integer@1.6.x, big-integer@^1.6.44: +big-integer@^1.6.44: version "1.6.51" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== @@ -4003,20 +4307,13 @@ boxen@^1.2.1: term-size "^1.2.0" widest-line "^2.0.0" -bplist-creator@0.1.0, bplist-creator@^0: +bplist-creator@^0: version "0.1.0" resolved "https://registry.yarnpkg.com/bplist-creator/-/bplist-creator-0.1.0.tgz#018a2d1b587f769e379ef5519103730f8963ba1e" integrity sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg== dependencies: stream-buffers "2.2.x" -bplist-parser@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.3.1.tgz#e1c90b2ca2a9f9474cc72f6862bbf3fee8341fd1" - integrity sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA== - dependencies: - big-integer "1.6.x" - bplist-parser@^0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" @@ -4055,21 +4352,15 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserslist@^4.17.5: - version "4.18.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" - integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== +browserslist@^4.21.3: + version "4.21.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987" + integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== dependencies: - caniuse-lite "^1.0.30001280" - electron-to-chromium "^1.3.896" - escalade "^3.1.1" - node-releases "^2.0.1" - picocolors "^1.0.0" + caniuse-lite "^1.0.30001400" + electron-to-chromium "^1.4.251" + node-releases "^2.0.6" + update-browserslist-db "^1.0.9" bser@2.1.1: version "2.1.1" @@ -4106,14 +4397,6 @@ buffer@^5.1.0, buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0: base64-js "^1.0.2" ieee754 "^1.1.4" -buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - bufferpack@0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/bufferpack/-/bufferpack-0.0.6.tgz#fb3d8738a0e1e4e03bcff99f9a75f9ec18a9d73e" @@ -4246,22 +4529,15 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.0.0: +camelcase@^6.0.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001280: - version "1.0.30001312" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz#e11eba4b87e24d22697dae05455d5aea28550d5f" - integrity sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ== - -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" +caniuse-lite@^1.0.30001400: + version "1.0.30001442" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz#40337f1cf3be7c637b061e2f78582dc1daec0614" + integrity sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow== capture-stack-trace@^1.0.0: version "1.0.1" @@ -4365,10 +4641,10 @@ circular-json@^0.5.9: resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== class-utils@^0.3.5: version "0.3.6" @@ -4484,6 +4760,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.0, cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4633,11 +4918,16 @@ command-exists@^1.2.8: resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== -commander@^2.11.0, commander@^2.19.0: +commander@^2.11.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +commander@^9.4.1: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -4846,13 +5136,18 @@ conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.0.7: through2 "^3.0.0" trim-off-newlines "^1.0.0" -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -4955,7 +5250,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -4979,23 +5274,6 @@ css-value@^0.0.1: resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" integrity sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo= -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - csstype@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.3.tgz#2b410bbeba38ba9633353aff34b05d9755d065f8" @@ -5018,15 +5296,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - dateformat@^3.0.0, dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -5051,12 +5320,12 @@ debug@3.1.0, debug@=3.1.0: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "^2.1.1" + ms "2.1.2" debug@^3.1.0, debug@^3.1.1: version "3.2.6" @@ -5065,6 +5334,13 @@ debug@^3.1.0, debug@^3.1.1: dependencies: ms "^2.1.1" +debug@~4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -5083,11 +5359,6 @@ decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -5100,6 +5371,11 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== + deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" @@ -5193,10 +5469,10 @@ depd@~2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== -deprecated-react-native-prop-types@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-2.3.0.tgz#c10c6ee75ff2b6de94bb127f142b814e6e08d9ab" - integrity sha512-pWD0voFtNYxrVqvBMYf5gq3NA2GCpfodS1yNynTPc93AYA/KEMGeWDqqeUB6R2Z9ZofVhks2aeJXiuQqKNpesA== +deprecated-react-native-prop-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deprecated-react-native-prop-types/-/deprecated-react-native-prop-types-3.0.1.tgz#a275f84cd8519cd1665e8df3c99e9067d57a23ec" + integrity sha512-J0jCJcsk4hMlIb7xwOZKLfMpuJn6l8UtrPEzzQV5ewz5gvKNYakhBuq9h2rWX7YwHHJZFhU5W8ye7dB9oN8VcQ== dependencies: "@react-native/normalize-color" "*" invariant "*" @@ -5266,10 +5542,10 @@ diagnostic-channel@1.1.0: dependencies: semver "^5.3.0" -diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +diff-sequences@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.3.1.tgz#104b5b95fe725932421a9c6e5b4bef84c3f2249e" + integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ== dir-glob@^2.0.0: version "2.2.2" @@ -5312,13 +5588,6 @@ dom-walk@^0.1.0: resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - dot-prop@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" @@ -5383,10 +5652,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.896: - version "1.4.75" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.75.tgz#d1ad9bb46f2f1bf432118c2be21d27ffeae82fdd" - integrity sha512-LxgUNeu3BVU7sXaKjUDD9xivocQLxFtq6wgERrutdY/yIOps3ODOZExK1jg8DTEg4U8TUCb5MLGeWFOYuxjF3Q== +electron-to-chromium@^1.4.251: + version "1.4.284" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz#61046d1e4cab3a25238f6bf7413795270f125592" + integrity sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA== emitter-listener@^1.0.1, emitter-listener@^1.1.1: version "1.1.2" @@ -5395,10 +5664,10 @@ emitter-listener@^1.0.1, emitter-listener@^1.1.1: dependencies: shimmer "^1.2.0" -emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" @@ -5561,18 +5830,6 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - eslint-config-airbnb-base@^14.0.0: version "14.2.0" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz#fe89c24b3f9dc8008c9c0d0d88c28f95ed65e9c4" @@ -5686,12 +5943,12 @@ eslint-scope@^4.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-scope@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" - integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: - esrecurse "^4.1.0" + esrecurse "^4.3.0" estraverse "^4.1.1" eslint-utils@^1.4.0, eslint-utils@^1.4.2: @@ -5701,11 +5958,28 @@ eslint-utils@^1.4.0, eslint-utils@^1.4.2: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + eslint@6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.3.0.tgz#1f1a902f67bfd4c354e7288b81e40654d927eb6a" @@ -5758,7 +6032,7 @@ espree@^6.1.1: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: +esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -5770,14 +6044,14 @@ esquery@^1.0.1: dependencies: estraverse "^5.1.0" -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== +esrecurse@^4.1.0, esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: - estraverse "^4.1.0" + estraverse "^5.2.0" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -5807,16 +6081,6 @@ eventemitter3@^3.1.2: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== - execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -5887,6 +6151,21 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exif-parser@^0.1.12: version "0.1.12" resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" @@ -5910,17 +6189,16 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== +expect@^29.0.0, expect@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.4.1.tgz#58cfeea9cbf479b64ed081fd1e074ac8beb5a1fe" + integrity sha512-OKrGESHOaMxK3b6zxIq9SOW8kEXztKff/Dvg88j4xIJxur1hspEbedVkR3GpHe5LO+WB2Qw7OWN0RMTdp6as5A== dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" + "@jest/expect-utils" "^29.4.1" + jest-get-type "^29.2.0" + jest-matcher-utils "^29.4.1" + jest-message-util "^29.4.1" + jest-util "^29.4.1" express@^4.16.2: version "4.17.1" @@ -6042,19 +6320,18 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.0.3: - version "3.2.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" - integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== +fast-glob@^3.0.3, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" + glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -6204,6 +6481,14 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-versions@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" @@ -6238,15 +6523,10 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flow-parser@0.*: - version "0.171.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.171.0.tgz#5ffae78f050e43513abc86add9f19a97fcbabcdb" - integrity sha512-cqEsgic6HH81Pz0IQLeyuoh0O8Y7ECAIdZ0idPQ9P1jZ/kHB9KK0hwqnjVtqTGog15JURkIxvyXm+9pAb6uuSQ== - -flow-parser@^0.121.0: - version "0.121.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.121.0.tgz#9f9898eaec91a9f7c323e9e992d81ab5c58e618f" - integrity sha512-1gIBiWJNR0tKUNv8gZuk7l9rVX06OuLzY9AoGio7y/JT4V1IZErEMEq2TJS+PFcw/y0RshZ1J/27VfK1UQzYVg== +flow-parser@0.*, flow-parser@^0.185.0: + version "0.185.2" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.185.2.tgz#cb7ee57f77377d6c5d69a469e980f6332a15e492" + integrity sha512-2hJ5ACYeJCzNtiVULov6pljKOLygy0zddoqSI1fFetM+XRPpRshFdGEijtqlamA1XwyZ+7rhryI6FQFzvtLWUQ== flush-write-stream@^1.0.0: version "1.1.1" @@ -6352,15 +6632,6 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" - integrity sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA= - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - fs-extra@^8.0.0, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -6401,7 +6672,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@2.x, fsevents@^2.1.2, fsevents@^2.3.2: +fsevents@2.x, fsevents@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -6521,6 +6792,11 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -6545,10 +6821,10 @@ git-log-parser@^1.2.0: through2 "~2.0.0" traverse "~0.6.6" -glob-parent@^5.0.0, glob-parent@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== +glob-parent@^5.0.0, glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -6609,6 +6885,18 @@ globby@^10.0.0: merge2 "^1.2.3" slash "^3.0.0" +globby@^11.0.4, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + globby@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/globby/-/globby-7.1.1.tgz#fb2ccff9401f8600945dfada97440cca972b8680" @@ -6665,11 +6953,6 @@ grapheme-splitter@^1.0.2: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - handlebars@^4.7.6: version "4.7.6" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" @@ -6763,22 +7046,17 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hermes-engine@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.11.0.tgz#bb224730d230a02a5af02c4e090d1f52d57dd3db" - integrity sha512-7aMUlZja2IyLYAcZ69NBnwJAR5ZOYlSllj0oMpx08a8HzxHOys0eKCzfphrf6D0vX1JGO1QQvVsQKe6TkYherw== - -hermes-estree@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.5.0.tgz#36432a2b12f01b217244da098924efdfdfc12327" - integrity sha512-1h8rvG23HhIR5K6Kt0e5C7BC72J1Ath/8MmSta49vxXp/j6wl7IMHvIRFYBQr35tWnQY97dSGR2uoAJ5pHUQkg== +hermes-estree@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.8.0.tgz#530be27243ca49f008381c1f3e8b18fb26bf9ec0" + integrity sha512-W6JDAOLZ5pMPMjEiQGLCXSSV7pIBEgRR5zGkxgmzGSXHOxqV5dC/M1Zevqpbm9TZDE5tu358qZf8Vkzmsc+u7Q== -hermes-parser@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.5.0.tgz#8b678dd8b29a08b57cbaf60adba4896494c59a53" - integrity sha512-ARnJBScKAkkq8j3BHrNGBUv/4cSpZNbKDsVizEtzmsFeqC67Dopa5s4XRe+e3wN52Dh5Mj2kDB5wJvhcxwDkPg== +hermes-parser@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.8.0.tgz#116dceaba32e45b16d6aefb5c4c830eaeba2d257" + integrity sha512-yZKalg1fTYG5eOiToLUaw69rQfZq/fi+/NtEXRU7N87K/XobNRhRWorh80oSge2lWUiZfTgUvRJH+XgZWrhoqA== dependencies: - hermes-estree "0.5.0" + hermes-estree "0.8.0" hermes-profile-transformer@^0.0.6: version "0.0.6" @@ -6804,13 +7082,6 @@ hosted-git-info@^3.0.0: dependencies: lru-cache "^6.0.0" -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -6864,15 +7135,6 @@ http-proxy-agent@^3.0.0: agent-base "5" debug "4" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -6911,19 +7173,16 @@ https-proxy-agent@^4.0.0: agent-base "5" debug "4" -https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -6945,7 +7204,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.4: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6977,10 +7236,10 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.1: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.1.1, ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== image-size@^0.6.0: version "0.6.3" @@ -7200,13 +7459,6 @@ is-ci@^1.0.10: dependencies: ci-info "^1.5.0" -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - is-cidr@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/is-cidr/-/is-cidr-3.1.1.tgz#e92ef121bdec2782271a77ce487a8b8df3718ab7" @@ -7226,6 +7478,13 @@ is-core-module@^2.8.1: dependencies: has "^1.0.3" +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -7317,10 +7576,10 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -7395,11 +7654,6 @@ is-plain-object@^4.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-4.1.1.tgz#1a14d6452cbd50790edc7fdaa0aed5a40a35ebb5" integrity sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA== -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - is-redirect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" @@ -7446,7 +7700,7 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -7521,16 +7775,6 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - istanbul-lib-instrument@^5.0.4: version "5.1.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" @@ -7542,6 +7786,17 @@ istanbul-lib-instrument@^5.0.4: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -7560,10 +7815,10 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== +istanbul-reports@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" + integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -7573,328 +7828,327 @@ java-properties@^1.0.0: resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ== -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== +jest-changed-files@^29.4.0: + version "29.4.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.4.0.tgz#ac2498bcd394228f7eddcadcf928b3583bf2779d" + integrity sha512-rnI1oPxgFghoz32Y8eZsGJMjW54UlqT17ycQeCEktcxxwqqKdlj9afl8LNeO0Pbu+h2JQHThQP0BzS67eTRx4w== dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" + execa "^5.0.0" + p-limit "^3.1.0" -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== +jest-circus@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.4.1.tgz#ff1b63eb04c3b111cefea9489e8dbadd23ce49bd" + integrity sha512-v02NuL5crMNY4CGPHBEflLzl4v91NFb85a+dH9a1pUNx6Xjggrd8l9pPy4LZ1VYNRXlb+f65+7O/MSIbLir6pA== dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/environment" "^29.4.1" + "@jest/expect" "^29.4.1" + "@jest/test-result" "^29.4.1" + "@jest/types" "^29.4.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + is-generator-fn "^2.0.0" + jest-each "^29.4.1" + jest-matcher-utils "^29.4.1" + jest-message-util "^29.4.1" + jest-runtime "^29.4.1" + jest-snapshot "^29.4.1" + jest-util "^29.4.1" + p-limit "^3.1.0" + pretty-format "^29.4.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.4.1.tgz#7abef96944f300feb9b76f68b1eb2d68774fe553" + integrity sha512-jz7GDIhtxQ37M+9dlbv5K+/FVcIo1O/b1sX3cJgzlQUf/3VG25nvuWzlDC4F1FLLzUThJeWLu8I7JF9eWpuURQ== + dependencies: + "@jest/core" "^29.4.1" + "@jest/test-result" "^29.4.1" + "@jest/types" "^29.4.1" chalk "^4.0.0" exit "^0.1.2" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" + jest-config "^29.4.1" + jest-util "^29.4.1" + jest-validate "^29.4.1" prompts "^2.0.1" - yargs "^15.4.1" + yargs "^17.3.1" -jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== +jest-config@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.4.1.tgz#e62670c6c980ec21d75941806ec4d0c0c6402728" + integrity sha512-g7p3q4NuXiM4hrS4XFATTkd+2z0Ml2RhFmFPM8c3WyKwVDNszbl4E7cV7WIx1YZeqqCtqbtTtZhGZWJlJqngzg== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.4.1" + "@jest/types" "^29.4.1" + babel-jest "^29.4.1" chalk "^4.0.0" + ci-info "^3.2.0" deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.4.1" + jest-environment-node "^29.4.1" + jest-get-type "^29.2.0" + jest-regex-util "^29.2.0" + jest-resolve "^29.4.1" + jest-runner "^29.4.1" + jest-util "^29.4.1" + jest-validate "^29.4.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.4.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" -jest-diff@^26.0.0, jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== +jest-diff@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.4.1.tgz#9a6dc715037e1fa7a8a44554e7d272088c4029bd" + integrity sha512-uazdl2g331iY56CEyfbNA0Ut7Mn2ulAG5vUaEHXycf1L6IPyuImIxSz4F0VYBKi7LYIuxOwTZzK3wh5jHzASMw== dependencies: chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + diff-sequences "^29.3.1" + jest-get-type "^29.2.0" + pretty-format "^29.4.1" -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== +jest-docblock@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.2.0.tgz#307203e20b637d97cee04809efc1d43afc641e82" + integrity sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A== dependencies: detect-newline "^3.0.0" -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== +jest-each@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.4.1.tgz#05ce9979e7486dbd0f5d41895f49ccfdd0afce01" + integrity sha512-QlYFiX3llJMWUV0BtWht/esGEz9w+0i7BHwODKCze7YzZzizgExB9MOfiivF/vVT0GSQ8wXLhvHXh3x2fVD4QQ== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.4.1" chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" - -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + jest-get-type "^29.2.0" + jest-util "^29.4.1" + pretty-format "^29.4.1" + +jest-environment-node@^29.2.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.3.1.tgz#5023b32472b3fba91db5c799a0d5624ad4803e74" + integrity sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag== + dependencies: + "@jest/environment" "^29.3.1" + "@jest/fake-timers" "^29.3.1" + "@jest/types" "^29.3.1" "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" + jest-mock "^29.3.1" + jest-util "^29.3.1" -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== +jest-environment-node@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.4.1.tgz#22550b7d0f8f0b16228639c9f88ca04bbf3c1974" + integrity sha512-x/H2kdVgxSkxWAIlIh9MfMuBa0hZySmfsC5lCsWmWr6tZySP44ediRKDUiNggX/eHLH7Cd5ZN10Rw+XF5tXsqg== dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/environment" "^29.4.1" + "@jest/fake-timers" "^29.4.1" + "@jest/types" "^29.4.1" "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-mock "^29.4.1" + jest-util "^29.4.1" jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" +jest-get-type@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" + integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== -jest-haste-map@^27.3.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== +jest-haste-map@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.4.1.tgz#b0579dc82d94b40ed9041af56ad25c2f80bedaeb" + integrity sha512-imTjcgfVVTvg02khXL11NNLTx9ZaofbAWhilrMg/G8dIkp+HYCswhxf0xxJwBkfhWb3e8dwbjuWburvxmcr58w== dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" + "@jest/types" "^29.4.1" + "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" + jest-regex-util "^29.2.0" + jest-util "^29.4.1" + jest-worker "^29.4.1" micromatch "^4.0.4" - walker "^1.0.7" + walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== +jest-leak-detector@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.4.1.tgz#632186c546e084da2b490b7496fee1a1c9929637" + integrity sha512-akpZv7TPyGMnH2RimOCgy+hPmWZf55EyFUvymQ4LMsQP8xSPlZumCPtXGoDhFNhUE2039RApZkTQDKU79p/FiQ== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.6.2" - is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" + jest-get-type "^29.2.0" + pretty-format "^29.4.1" -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== +jest-matcher-utils@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.4.1.tgz#73d834e305909c3b43285fbc76f78bf0ad7e1954" + integrity sha512-k5h0u8V4nAEy6lSACepxL/rw78FLDkBnXhZVgFneVpnJONhb2DhZj/Gv4eNe+1XqQ5IhgUcqj745UwH0HJmMnA== dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + chalk "^4.0.0" + jest-diff "^29.4.1" + jest-get-type "^29.2.0" + pretty-format "^29.4.1" -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== +jest-message-util@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.3.1.tgz#37bc5c468dfe5120712053dd03faf0f053bd6adb" + integrity sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA== dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.3.1" + "@types/stack-utils" "^2.0.0" chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.3.1" + slash "^3.0.0" + stack-utils "^2.0.3" -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== +jest-message-util@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.4.1.tgz#522623aa1df9a36ebfdffb06495c7d9d19e8a845" + integrity sha512-H4/I0cXUaLeCw6FM+i4AwCnOwHRgitdaUFOdm49022YD5nfyr8C/DrbXOBEyJaj+w/y0gGJ57klssOaUiLLQGQ== dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.4.1" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.4.1" slash "^3.0.0" - stack-utils "^2.0.2" + stack-utils "^2.0.3" -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== +jest-mock@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.3.1.tgz#60287d92e5010979d01f218c6b215b688e0f313e" + integrity sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.3.1" + "@types/node" "*" + jest-util "^29.3.1" + +jest-mock@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.4.1.tgz#a218a2abf45c99c501d4665207748a6b9e29afbd" + integrity sha512-MwA4hQ7zBOcgVCVnsM8TzaFLVUD/pFWTfbkY953Y81L5ret3GFRZtmPmRFAjKQSdCKoJvvqOu6Bvfpqlwwb0dQ== + dependencies: + "@jest/types" "^29.4.1" "@types/node" "*" + jest-util "^29.4.1" jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - -jest-regex-util@^27.5.1: +jest-regex-util@^27.0.6: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== +jest-regex-util@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.2.0.tgz#82ef3b587e8c303357728d0322d48bbfd2971f7b" + integrity sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA== + +jest-resolve-dependencies@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.4.1.tgz#02420a2e055da105e5fca8218c471d8b9553c904" + integrity sha512-Y3QG3M1ncAMxfjbYgtqNXC5B595zmB6e//p/qpA/58JkQXu/IpLDoLeOa8YoYfsSglBKQQzNUqtfGJJT/qLmJg== dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" + jest-regex-util "^29.2.0" + jest-snapshot "^29.4.1" -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== +jest-resolve@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.4.1.tgz#4c6bf71a07b8f0b79c5fdf4f2a2cf47317694c5e" + integrity sha512-j/ZFNV2lm9IJ2wmlq1uYK0Y/1PiyDq9g4HEGsNTNr3viRbJdV+8Lf1SXIiLZXFvyiisu0qUyIXGBnw+OKWkJwQ== dependencies: - "@jest/types" "^26.6.2" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" + jest-haste-map "^29.4.1" jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" + jest-util "^29.4.1" + jest-validate "^29.4.1" + resolve "^1.20.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== +jest-runner@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.4.1.tgz#57460d9ebb0eea2e27eeddca1816cf8537469661" + integrity sha512-8d6XXXi7GtHmsHrnaqBKWxjKb166Eyj/ksSaUYdcBK09VbjPwIgWov1VwSmtupCIz8q1Xv4Qkzt/BTo3ZqiCeg== dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.4.1" + "@jest/environment" "^29.4.1" + "@jest/test-result" "^29.4.1" + "@jest/transform" "^29.4.1" + "@jest/types" "^29.4.1" "@types/node" "*" chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" - source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.2.0" + jest-environment-node "^29.4.1" + jest-haste-map "^29.4.1" + jest-leak-detector "^29.4.1" + jest-message-util "^29.4.1" + jest-resolve "^29.4.1" + jest-runtime "^29.4.1" + jest-util "^29.4.1" + jest-watcher "^29.4.1" + jest-worker "^29.4.1" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.4.1.tgz#9a50f9c69d3a391690897c01b0bfa8dc5dd45808" + integrity sha512-UXTMU9uKu2GjYwTtoAw5rn4STxWw/nadOfW7v1sx6LaJYa3V/iymdCLQM6xy3+7C6mY8GfX22vKpgxY171UIoA== + dependencies: + "@jest/environment" "^29.4.1" + "@jest/fake-timers" "^29.4.1" + "@jest/globals" "^29.4.1" + "@jest/source-map" "^29.2.0" + "@jest/test-result" "^29.4.1" + "@jest/transform" "^29.4.1" + "@jest/types" "^29.4.1" + "@types/node" "*" chalk "^4.0.0" - cjs-module-lexer "^0.6.0" + cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - exit "^0.1.2" glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.4.1" + jest-message-util "^29.4.1" + jest-mock "^29.4.1" + jest-regex-util "^29.2.0" + jest-resolve "^29.4.1" + jest-snapshot "^29.4.1" + jest-util "^29.4.1" + semver "^7.3.5" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.4.1" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" -jest-serializer@^27.5.1: +jest-serializer@^27.0.6: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== @@ -7902,41 +8156,37 @@ jest-serializer@^27.5.1: "@types/node" "*" graceful-fs "^4.2.9" -jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== +jest-snapshot@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.4.1.tgz#5692210b3690c94f19317913d4082b123bd83dd9" + integrity sha512-l4iV8EjGgQWVz3ee/LR9sULDk2pCkqb71bjvlqn+qp90lFwpnulHj4ZBT8nm1hA1C5wowXLc7MGnw321u0tsYA== dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.4.1" + "@jest/transform" "^29.4.1" + "@jest/types" "^29.4.1" + "@types/babel__traverse" "^7.0.6" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" + expect "^29.4.1" + graceful-fs "^4.2.9" + jest-diff "^29.4.1" + jest-get-type "^29.2.0" + jest-haste-map "^29.4.1" + jest-matcher-utils "^29.4.1" + jest-message-util "^29.4.1" + jest-util "^29.4.1" natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" - -jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" + pretty-format "^29.4.1" + semver "^7.3.5" -jest-util@^27.5.1: +jest-util@^27.2.0: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== @@ -7948,7 +8198,31 @@ jest-util@^27.5.1: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^26.5.2, jest-validate@^26.6.2: +jest-util@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.3.1.tgz#1dda51e378bbcb7e3bc9d8ab651445591ed373e1" + integrity sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ== + dependencies: + "@jest/types" "^29.3.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-util@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.4.1.tgz#2eeed98ff4563b441b5a656ed1a786e3abc3e4c4" + integrity sha512-bQy9FPGxVutgpN4VRc0hk6w7Hx/m6L53QxpDreTZgJd9gfx/AV2MjyPde9tGyZRINAUrSv57p2inGBu2dRLmkQ== + dependencies: + "@jest/types" "^29.4.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^26.5.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== @@ -7960,50 +8234,60 @@ jest-validate@^26.5.2, jest-validate@^26.6.2: leven "^3.1.0" pretty-format "^26.6.2" -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== +jest-validate@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.4.1.tgz#0d5174510415083ec329d4f981bf6779211f17e9" + integrity sha512-qNZXcZQdIQx4SfUB/atWnI4/I2HUvhz8ajOSYUu40CSmf9U5emil8EDHgE7M+3j9/pavtk3knlZBDsgFvv/SWw== dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/types" "^29.4.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.2.0" + leven "^3.1.0" + pretty-format "^29.4.1" + +jest-watcher@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.4.1.tgz#6e3e2486918bd778849d4d6e67fd77b814f3e6ed" + integrity sha512-vFOzflGFs27nU6h8dpnVRER3O2rFtL+VMEwnG0H3KLHcllLsU8y9DchSh0AL/Rg5nN1/wSiQ+P4ByMGpuybaVw== + dependencies: + "@jest/test-result" "^29.4.1" + "@jest/types" "^29.4.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.6.2" + emittery "^0.13.1" + jest-util "^29.4.1" string-length "^4.0.1" -jest-worker@^26.0.0, jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== +jest-worker@^27.2.0: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== dependencies: "@types/node" "*" merge-stream "^2.0.0" - supports-color "^7.0.0" + supports-color "^8.0.0" -jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== +jest-worker@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.4.1.tgz#7cb4a99a38975679600305650f86f4807460aab1" + integrity sha512-O9doU/S1EBe+yp/mstQ0VpPwpv0Clgn68TkNwGxL6/usX/KUW9Arnn4ag8C3jc6qHcXznhsT5Na1liYzAsuAbQ== dependencies: "@types/node" "*" + jest-util "^29.4.1" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== +jest@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.4.1.tgz#bb34baca8e05901b49c02c62f1183a6182ea1785" + integrity sha512-cknimw7gAXPDOmj0QqztlxVtBVCw2lYY9CeIE5N6kD+kET1H4H79HSNISJmijb1HF+qk+G+ploJgiDi5k/fRlg== dependencies: - "@jest/core" "^26.6.3" + "@jest/core" "^29.4.1" + "@jest/types" "^29.4.1" import-local "^3.0.2" - jest-cli "^26.6.3" - -jetifier@^1.6.2: - version "1.6.6" - resolved "https://registry.yarnpkg.com/jetifier/-/jetifier-1.6.6.tgz#fec8bff76121444c12dc38d2dad6767c421dab68" - integrity sha512-JNAkmPeB/GS2tCRqUzRPsTOHpGDah7xP18vGJfIjZC+W2sxEHbxgJxetIjIqhjQ3yYbYNEELkM/spKLtwoOSUQ== + jest-cli "^29.4.1" jimp@^0.10.0: version "0.10.3" @@ -8072,6 +8356,11 @@ jsc-android@^250230.2.1: resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250230.2.1.tgz#3790313a970586a03ab0ad47defbc84df54f1b83" integrity sha512-KmxeBlRjwoqCnBBKGsihFtvsBHyUFlBxJPK4FzeYcIuBfdjv6jFys44JITAgSTbQD+vIdwMEfyZklsuQX0yI1Q== +jsc-android@^250231.0.0: + version "250231.0.0" + resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" + integrity sha512-rS46PvsjYmdmuz1OAWXY/1kCYG7pnf1TBqeTiOJr1iDz7s5DLxxC9n/ZMknLDxzYzNVfI7R95MH10emSSG1Wuw== + jscodeshift@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.13.1.tgz#69bfe51e54c831296380585c6d9e733512aecdef" @@ -8097,39 +8386,6 @@ jscodeshift@^0.13.1: temp "^0.8.4" write-file-atomic "^2.3.0" -jsdom@^16.4.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -8192,19 +8448,10 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== - dependencies: - minimist "^1.2.5" - -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= - optionalDependencies: - graceful-fs "^4.1.6" +json5@^2.1.2, json5@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^4.0.0: version "4.0.0" @@ -8213,11 +8460,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -8289,13 +8531,6 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -klaw@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" - integrity sha1-QIhDO0azsbolnXh4XY6W9zugJDk= - optionalDependencies: - graceful-fs "^4.1.9" - klaw@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" @@ -8577,6 +8812,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lock-verify@^2.0.2, lock-verify@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.2.1.tgz#81107948c51ed16f97b96ff8b60675affb243fc1" @@ -8721,7 +8963,7 @@ lodash.zip@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA= -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.9, lodash@^4.2.1, lodash@^4.6.1, lodash@^4.7.0: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.17.9, lodash@^4.2.1, lodash@^4.6.1: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8861,6 +9103,13 @@ make-fetch-happen@^5.0.0: socks-proxy-agent "^4.0.0" ssri "^6.0.0" +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + makeerror@1.0.x: version "1.0.11" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" @@ -8963,6 +9212,11 @@ mem@^5.0.0: mimic-fn "^2.1.0" p-is-promise "^2.1.0" +memoize-one@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + meow@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.0.tgz#50ecbcdafa16f8b58fb7eb9675b933f6473b3a59" @@ -8990,7 +9244,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -9010,79 +9264,126 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -metro-babel-transformer@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.67.0.tgz#42fe82af9953e5c62d9a8d7d544eb7be9020dd18" - integrity sha512-SBqc4nq/dgsPNFm+mpWcQQzJaXnh0nrfz2pSnZC4i6zMtIakrTWb8SQ78jOU1FZVEZ3nu9xCYVHS9Tbr/LoEuw== +metro-babel-transformer@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.73.5.tgz#e7ebe371cd8bf5df90b0e9153587b4d5089d2ce7" + integrity sha512-G3awAJ9of/R2jEg+MRokYcq/TNvMSxJipwybQ2NfwwSj5iLEmRH2YbwTx5w8f5qKgs2K4SS2pmBIs8qjdV6p3Q== dependencies: "@babel/core" "^7.14.0" - hermes-parser "0.5.0" - metro-source-map "0.67.0" + hermes-parser "0.8.0" + metro-source-map "0.73.5" nullthrows "^1.1.1" -metro-cache-key@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.67.0.tgz#4df6a73cced199e1bddd0f3454bb931a27141eeb" - integrity sha512-FNJe5Rcb2uzY6G6tsqCf0RV4t2rCeX6vSHBxmP7k+4aI4NqX4evtPI0K82r221nBzm5DqNWCURZ0RYUT6jZMGA== +metro-babel-transformer@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.73.7.tgz#561ffa0336eb6d7d112e7128e957114c729fdb71" + integrity sha512-s7UVkwovGTEXYEQrv5hcmSBbFJ9s9lhCRNMScn4Itgj3UMdqRr9lU8DXKEFlJ7osgRxN6n5+eXqcvhE4B1H1VQ== + dependencies: + "@babel/core" "^7.20.0" + hermes-parser "0.8.0" + metro-source-map "0.73.7" + nullthrows "^1.1.1" -metro-cache@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.67.0.tgz#928db5742542719677468c4d22ea29b71c7ec8fc" - integrity sha512-IY5dXiR76L75b2ue/mv+9vW8g5hdQJU6YEe81lj6gTSoUrhcONT0rzY+Gh5QOS2Kk6z9utZQMvd9PRKL9/635A== +metro-babel-transformer@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.73.9.tgz#bec8aaaf1bbdc2e469fde586fde455f8b2a83073" + integrity sha512-DlYwg9wwYIZTHtic7dyD4BP0SDftoltZ3clma76nHu43blMWsCnrImHeHsAVne3XsQ+RJaSRxhN5nkG2VyVHwA== dependencies: - metro-core "0.67.0" - mkdirp "^0.5.1" - rimraf "^2.5.4" + "@babel/core" "^7.20.0" + hermes-parser "0.8.0" + metro-source-map "0.73.9" + nullthrows "^1.1.1" -metro-config@0.67.0, metro-config@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.67.0.tgz#5507d3b295bd10c87bd13dbe5a3033a357418786" - integrity sha512-ThAwUmzZwTbKyyrIn2bKIcJDPDBS0LKAbqJZQioflvBGfcgA21h3fdL3IxRmvCEl6OnkEWI0Tn1Z9w2GLAjf2g== +metro-cache-key@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.73.7.tgz#fa3b4ece5f3191ce238a623051a0d03bada2a153" + integrity sha512-GngYzrHwZU9U0Xl81H4aq9Tn5cjQyU12v9/flB0hzpeiYO5A89TIeilb4Kg8jtfC6JcmmsdK9nxYIGEq7odHhQ== + +metro-cache@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.73.7.tgz#dd2b6a791b2754eae9c0a86dcf714b98e025fd95" + integrity sha512-CPPgI+i9yVzOEDCdmEEZ67JgOvZyNDs8kStmGUFgDuLSjj3//HhkqT5XyfWjGeH6KmyGiS8ip3cgLOVn3IsOSA== + dependencies: + metro-core "0.73.7" + rimraf "^3.0.2" + +metro-config@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.73.7.tgz#8935054ece6155d214420c263272cd3a690a82e2" + integrity sha512-pD/F+vK3u37cbj1skYmI6cUsEEscqNRtW2KlDKu1m+n8nooDB2oGTOZatlS5WQa7Ga6jYQRydftlq4CLDexAfA== dependencies: cosmiconfig "^5.0.5" jest-validate "^26.5.2" - metro "0.67.0" - metro-cache "0.67.0" - metro-core "0.67.0" - metro-runtime "0.67.0" + metro "0.73.7" + metro-cache "0.73.7" + metro-core "0.73.7" + metro-runtime "0.73.7" -metro-core@0.67.0, metro-core@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.67.0.tgz#75066e11b4df220992abf9cd6200279dd87876c8" - integrity sha512-TOa/ShE1bUq83fGNfV6rFwyfZ288M8ydmWN3g9C2OW8emOHLhJslYD/SIU4DhDkP/99yaJluIALdZ2g0+pCrvQ== +metro-core@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.73.7.tgz#f5abe2448ea72a65f54db9bc90068f3308de1df2" + integrity sha512-H7j1Egj1VnNnsSYf9ZKv0SRwijgtRKIcaGNQq/T+er73vqqb4kR9H+2VIJYPXi6R8lT+QLIMfs6CWSUHAJUgtg== dependencies: - jest-haste-map "^27.3.1" lodash.throttle "^4.1.1" - metro-resolver "0.67.0" + metro-resolver "0.73.7" -metro-hermes-compiler@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-hermes-compiler/-/metro-hermes-compiler-0.67.0.tgz#9c1340f1882fbf535145868d0d28211ca15b0477" - integrity sha512-X5Pr1jC8/kO6d1EBDJ6yhtuc5euHX89UDNv8qdPJHAET03xfFnlojRPwOw6il2udAH20WLBv+F5M9VY+58zspQ== +metro-file-map@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-file-map/-/metro-file-map-0.73.7.tgz#709f33ac5ea6f87668d454c77973ab296b7a064b" + integrity sha512-BYaCo2e/4FMN4nOajeN+Za5cPfecfikzUYuFWWMyLAmHU6dj7B+PFkaJ4OEJO3vmRoeq5vMOmhpKXgysYbNXJg== + dependencies: + abort-controller "^3.0.0" + anymatch "^3.0.3" + debug "^2.2.0" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + invariant "^2.2.4" + jest-regex-util "^27.0.6" + jest-serializer "^27.0.6" + jest-util "^27.2.0" + jest-worker "^27.2.0" + micromatch "^4.0.4" + nullthrows "^1.1.1" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +metro-hermes-compiler@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-hermes-compiler/-/metro-hermes-compiler-0.73.7.tgz#d1b519c4040423240d89e7816340ca9635deeae8" + integrity sha512-F8PlJ8mWEEumGNH3eMRA3gjgP70ZvH4Ex5F1KY6ofD/gpn7w5HJHSPTeVw8gtUb1pYLN4nevptpyXGg04Jfcog== -metro-inspector-proxy@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.67.0.tgz#22b360a837b07e9e2bc87a71af6154dd8fcc02a5" - integrity sha512-5Ubjk94qpNaU3OT2IZa4/dec09bauic1hzWms4czorBzDenkp4kYXG9/aWTmgQLtCk92H3Q8jKl1PQRxUSkrOQ== +metro-inspector-proxy@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.73.7.tgz#edb966c1581a41a3302860d264f3228e1f57a220" + integrity sha512-TsAtQeKr9X7NaQHlpshu+ZkGWlPi5fFKNqieLkfqvT1oXN4PQF/4q38INyiZtWLPvoUzTR6PRnm4pcUbJ7+Nzg== dependencies: connect "^3.6.5" debug "^2.2.0" ws "^7.5.1" - yargs "^15.3.1" + yargs "^17.5.1" + +metro-minify-terser@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-minify-terser/-/metro-minify-terser-0.73.7.tgz#e45fc05eb2e3bc76c9b4fe4abccee0fffeedcf75" + integrity sha512-gbv1fmMOZm6gJ6dQoD+QktlCi2wk6nlTR8j8lQCjeeXGbs6O9e5XLWNPOexHqo7S69bdbohEnfZnLJFcxgHeNw== + dependencies: + terser "^5.15.0" -metro-minify-uglify@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.67.0.tgz#28a77dbd78d9e558dba8c2f31c2b9c6f939df966" - integrity sha512-4CmM5b3MTAmQ/yFEfsHOhD2SuBObB2YF6PKzXZc4agUsQVVtkrrNElaiWa8w26vrTzA9emwcyurxMf4Nl3lYPQ== +metro-minify-uglify@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.73.7.tgz#3dfd397e8202905731e4a519a58fc334d9232a15" + integrity sha512-DmDCzfdbaPExQuQ7NQozCNOSOAgp5Ux9kWzmKAT8seQ38/3NtUepW+PTgxXIHmwNjJV4oHsHwlBlTwJmYihKXg== dependencies: uglify-es "^3.1.9" -metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.67.0.tgz#53aec093f53a09b56236a9bb534d76658efcbec7" - integrity sha512-tgTG4j0SKwLHbLRELMmgkgkjV1biYkWlGGKOmM484/fJC6bpDikdaFhfjsyE+W+qt7I5szbCPCickMTNQ+zwig== +metro-react-native-babel-preset@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.5.tgz#9b92f1ebc2b3d96f511c45a03f8e35e0fc46cc19" + integrity sha512-Ej6J8ozWSs6nrh0nwX7hgX4oPXUai40ckah37cSLu8qeED2XiEtfLV1YksTLafFE8fX0EieiP97U97dkOGHP4w== dependencies: "@babel/core" "^7.14.0" + "@babel/plugin-proposal-async-generator-functions" "^7.0.0" "@babel/plugin-proposal-class-properties" "^7.0.0" "@babel/plugin-proposal-export-default-from" "^7.0.0" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" @@ -9100,19 +9401,60 @@ metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0: "@babel/plugin-transform-classes" "^7.0.0" "@babel/plugin-transform-computed-properties" "^7.0.0" "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" "@babel/plugin-transform-function-name" "^7.0.0" "@babel/plugin-transform-literals" "^7.0.0" "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-assign" "^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + +metro-react-native-babel-preset@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.7.tgz#78e1ce448aa9a5cf3651c0ebe73cb225465211b4" + integrity sha512-RKcmRZREjJCzHKP+JhC9QTCohkeb3xa/DtqHU14U5KWzJHdC0mMrkTZYNXhV0cryxsaVKVEw5873KhbZyZHMVw== + dependencies: + "@babel/core" "^7.20.0" + "@babel/plugin-proposal-async-generator-functions" "^7.0.0" + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.18.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" "@babel/plugin-transform-parameters" "^7.0.0" "@babel/plugin-transform-react-display-name" "^7.0.0" "@babel/plugin-transform-react-jsx" "^7.0.0" "@babel/plugin-transform-react-jsx-self" "^7.0.0" "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-regenerator" "^7.0.0" "@babel/plugin-transform-runtime" "^7.0.0" "@babel/plugin-transform-shorthand-properties" "^7.0.0" "@babel/plugin-transform-spread" "^7.0.0" @@ -9123,145 +9465,285 @@ metro-react-native-babel-preset@0.67.0, metro-react-native-babel-preset@^0.67.0: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-transformer@0.67.0, metro-react-native-babel-transformer@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.67.0.tgz#756d32eb3c05cab3d72fcb1700f8fd09322bb07f" - integrity sha512-P0JT09n7T01epUtgL9mH6BPat3xn4JjBakl4lWHdL61cvEGcrxuIom1eoFFKkgU/K5AVLU4aCAttHS7nSFCcEQ== +metro-react-native-babel-preset@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.73.9.tgz#ef54637dd20f025197beb49e71309a9c539e73e2" + integrity sha512-AoD7v132iYDV4K78yN2OLgTPwtAKn0XlD2pOhzyBxiI8PeXzozhbKyPV7zUOJUPETj+pcEVfuYj5ZN/8+bhbCw== + dependencies: + "@babel/core" "^7.20.0" + "@babel/plugin-proposal-async-generator-functions" "^7.0.0" + "@babel/plugin-proposal-class-properties" "^7.0.0" + "@babel/plugin-proposal-export-default-from" "^7.0.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-proposal-object-rest-spread" "^7.0.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" + "@babel/plugin-proposal-optional-chaining" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.0.0" + "@babel/plugin-syntax-export-default-from" "^7.0.0" + "@babel/plugin-syntax-flow" "^7.18.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.0.0" + "@babel/plugin-syntax-optional-chaining" "^7.0.0" + "@babel/plugin-transform-arrow-functions" "^7.0.0" + "@babel/plugin-transform-async-to-generator" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.0.0" + "@babel/plugin-transform-classes" "^7.0.0" + "@babel/plugin-transform-computed-properties" "^7.0.0" + "@babel/plugin-transform-destructuring" "^7.0.0" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/plugin-transform-function-name" "^7.0.0" + "@babel/plugin-transform-literals" "^7.0.0" + "@babel/plugin-transform-modules-commonjs" "^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.0.0" + "@babel/plugin-transform-parameters" "^7.0.0" + "@babel/plugin-transform-react-display-name" "^7.0.0" + "@babel/plugin-transform-react-jsx" "^7.0.0" + "@babel/plugin-transform-react-jsx-self" "^7.0.0" + "@babel/plugin-transform-react-jsx-source" "^7.0.0" + "@babel/plugin-transform-runtime" "^7.0.0" + "@babel/plugin-transform-shorthand-properties" "^7.0.0" + "@babel/plugin-transform-spread" "^7.0.0" + "@babel/plugin-transform-sticky-regex" "^7.0.0" + "@babel/plugin-transform-template-literals" "^7.0.0" + "@babel/plugin-transform-typescript" "^7.5.0" + "@babel/plugin-transform-unicode-regex" "^7.0.0" + "@babel/template" "^7.0.0" + react-refresh "^0.4.0" + +metro-react-native-babel-transformer@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.5.tgz#fb1d48cc73ce26371cf2a115f702b7bf3bb5516b" + integrity sha512-CZYgUguqFTzV9vSOZb60p8qlp31aWz8aBB6OqoZ2gJday+n/1k+Y0yy6VPr/tfXJheuQYVIXKvG1gMmUDyxt+Q== + dependencies: + "@babel/core" "^7.14.0" + babel-preset-fbjs "^3.4.0" + hermes-parser "0.8.0" + metro-babel-transformer "0.73.5" + metro-react-native-babel-preset "0.73.5" + metro-source-map "0.73.5" + nullthrows "^1.1.1" + +metro-react-native-babel-transformer@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.7.tgz#a92055fd564cd403255cc34f925c5e99ce457565" + integrity sha512-73HW8betjX+VPm3iqsMBe8F/F2Tt+hONO6YJwcF7FonTqQYW1oTz0dOp0dClZGfHUXxpJBz6Vuo7J6TpdzDD+w== + dependencies: + "@babel/core" "^7.20.0" + babel-preset-fbjs "^3.4.0" + hermes-parser "0.8.0" + metro-babel-transformer "0.73.7" + metro-react-native-babel-preset "0.73.7" + metro-source-map "0.73.7" + nullthrows "^1.1.1" + +metro-react-native-babel-transformer@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.73.9.tgz#4f4f0cfa5119bab8b53e722fabaf90687d0cbff0" + integrity sha512-DSdrEHuQ22ixY7DyipyKkIcqhOJrt5s6h6X7BYJCP9AMUfXOwLe2biY3BcgJz5GOXv8/Akry4vTCvQscVS1otQ== + dependencies: + "@babel/core" "^7.20.0" + babel-preset-fbjs "^3.4.0" + hermes-parser "0.8.0" + metro-babel-transformer "0.73.9" + metro-react-native-babel-preset "0.73.9" + metro-source-map "0.73.9" + nullthrows "^1.1.1" + +metro-resolver@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.73.7.tgz#1e174cf59eac84c0869172764316042b466daaa5" + integrity sha512-mGW3XPeKBCwZnkHcKo1dhFa9olcx7SyNzG1vb5kjzJYe4Qs3yx04r/qFXIJLcIgLItB69TIGvosznUhpeOOXzg== + dependencies: + absolute-path "^0.0.0" + +metro-runtime@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.73.5.tgz#8c92c3947e97a8dede6347ba6a9844bfb8be8258" + integrity sha512-8QJOS7bhJmR6r/Gkki/qY9oX/DdxnLhS8FpdG1Xmm2hDeUVAug12ekWTiCRMu7d1CDVv1F8WvUz09QckZ0dO0g== + dependencies: + "@babel/runtime" "^7.0.0" + react-refresh "^0.4.0" + +metro-runtime@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.73.7.tgz#9f3a7f3ff668c1a87370650e32b47d8f6329fd1e" + integrity sha512-2fxRGrF8FyrwwHY0TCitdUljzutfW6CWEpdvPilfrs8p0PI5X8xOWg8ficeYtw+DldHtHIAL2phT59PqzHTyVA== + dependencies: + "@babel/runtime" "^7.0.0" + react-refresh "^0.4.0" + +metro-runtime@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.73.9.tgz#0b24c0b066b8629ee855a6e5035b65061fef60d5" + integrity sha512-d5Hs83FpKB9r8q8Vb95+fa6ESpwysmPr4lL1I2rM2qXAFiO7OAPT9Bc23WmXgidkBtD0uUFdB2lG+H1ATz8rZg== + dependencies: + "@babel/runtime" "^7.0.0" + react-refresh "^0.4.0" + +metro-source-map@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.73.5.tgz#67e14bd1fcc1074b9623640ca311cd99d07426fa" + integrity sha512-58p3zNWgUrqYYjFJb0KkZ+uJurTL4oz7i5T7577b3kvTYuJ0eK4y7rtYf8EwOfMYxRAn/m20aH1Y1fHTsLUwjQ== + dependencies: + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.20.0" + invariant "^2.2.4" + metro-symbolicate "0.73.5" + nullthrows "^1.1.1" + ob1 "0.73.5" + source-map "^0.5.6" + vlq "^1.0.0" + +metro-source-map@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.73.7.tgz#8e9f850a72d60ea7ace05b984f981c8ec843e7a0" + integrity sha512-gbC/lfUN52TtQhEsTTA+987MaFUpQlufuCI05blLGLosDcFCsARikHsxa65Gtslm/rG2MqvFLiPA5hviONNv9g== dependencies: - "@babel/core" "^7.14.0" - babel-preset-fbjs "^3.4.0" - hermes-parser "0.5.0" - metro-babel-transformer "0.67.0" - metro-react-native-babel-preset "0.67.0" - metro-source-map "0.67.0" + "@babel/traverse" "^7.20.0" + "@babel/types" "^7.20.0" + invariant "^2.2.4" + metro-symbolicate "0.73.7" nullthrows "^1.1.1" + ob1 "0.73.7" + source-map "^0.5.6" + vlq "^1.0.0" -metro-resolver@0.67.0, metro-resolver@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.67.0.tgz#8143c716f77e468d1d42eca805243706eb349959" - integrity sha512-d2KS/zAyOA/z/q4/ff41rAp+1txF4H6qItwpsls/RHStV2j6PqgRHUzq/3ga+VIeoUJntYJ8nGW3+3qSrhFlig== +metro-source-map@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.73.9.tgz#89ca41f6346aeb12f7f23496fa363e520adafebe" + integrity sha512-l4VZKzdqafipriETYR6lsrwtavCF1+CMhCOY9XbyWeTrpGSNgJQgdeJpttzEZTHQQTLR0csQo0nD1ef3zEP6IQ== dependencies: - absolute-path "^0.0.0" + "@babel/traverse" "^7.20.0" + "@babel/types" "^7.20.0" + invariant "^2.2.4" + metro-symbolicate "0.73.9" + nullthrows "^1.1.1" + ob1 "0.73.9" + source-map "^0.5.6" + vlq "^1.0.0" -metro-runtime@0.67.0, metro-runtime@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.67.0.tgz#a8888dfd06bcebbac3c99dcac7cd622510dd8ee0" - integrity sha512-IFtSL0JUt1xK3t9IoLflTDft82bjieSzdIJWLzrRzBMlesz8ox5bVmnpQbVQEwfYUpEOxbM3VOZauVbdCmXA7g== +metro-symbolicate@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.73.5.tgz#8de118be231decd55c8c70ed54deb308fdffceda" + integrity sha512-aIC8sDlaEdtn0dTt+64IFZFEATatFx3GtzRbJi0+jJx47RjDRiuCt9fzmTMLuadWwnbFK9ZfVMuWEXM9sdtQ7w== + dependencies: + invariant "^2.2.4" + metro-source-map "0.73.5" + nullthrows "^1.1.1" + source-map "^0.5.6" + through2 "^2.0.1" + vlq "^1.0.0" -metro-source-map@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.67.0.tgz#e28db7253b9ca688e60d5710ebdccba60b45b2df" - integrity sha512-yxypInsRo3SfS00IgTuL6a2W2tfwLY//vA2E+GeqGBF5zTbJZAhwNGIEl8S87XXZhwzJcxf5/8LjJC1YDzabww== +metro-symbolicate@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.73.7.tgz#40e4cda81f8030b86afe391b5e686a0b06822b0a" + integrity sha512-571ThWmX5o8yGNzoXjlcdhmXqpByHU/bSZtWKhtgV2TyIAzYCYt4hawJAS5+/qDazUvjHdm8BbdqFUheM0EKNQ== dependencies: - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" invariant "^2.2.4" - metro-symbolicate "0.67.0" + metro-source-map "0.73.7" nullthrows "^1.1.1" - ob1 "0.67.0" source-map "^0.5.6" + through2 "^2.0.1" vlq "^1.0.0" -metro-symbolicate@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.67.0.tgz#16729d05663d28176895244b3d932a898fca2b45" - integrity sha512-ZqVVcfa0xSz40eFzA5P8pCF3V6Tna9RU1prFzAJTa3j9dCGqwh0HTXC8AIkMtgX7hNdZrCJI1YipzUBlwkT0/A== +metro-symbolicate@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.73.9.tgz#cb452299a36e5b86b2826e7426d51221635c48bf" + integrity sha512-4TUOwxRHHqbEHxRqRJ3wZY5TA8xq7AHMtXrXcjegMH9FscgYztsrIG9aNBUBS+VLB6g1qc6BYbfIgoAnLjCDyw== dependencies: invariant "^2.2.4" - metro-source-map "0.67.0" + metro-source-map "0.73.9" nullthrows "^1.1.1" source-map "^0.5.6" through2 "^2.0.1" vlq "^1.0.0" -metro-transform-plugins@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.67.0.tgz#6122aa4e5e5f9a767cebcc5af6fd1695666683ce" - integrity sha512-DQFoSDIJdTMPDTUlKaCNJjEXiHGwFNneAF9wDSJ3luO5gigM7t7MuSaPzF4hpjmfmcfPnRhP6AEn9jcza2Sh8Q== +metro-transform-plugins@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.73.7.tgz#49ff2571742d557f20301880f55b00054e468e52" + integrity sha512-M5isiWEau0jMudb5ezaNBZnYqXxcATMqnAYc+Cu25IahT1NHi5aWwLok9EBmBpN5641IZUZXScf+KnS7fPxPCQ== dependencies: - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" + "@babel/core" "^7.20.0" + "@babel/generator" "^7.20.0" "@babel/template" "^7.0.0" - "@babel/traverse" "^7.14.0" + "@babel/traverse" "^7.20.0" nullthrows "^1.1.1" -metro-transform-worker@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.67.0.tgz#5689553c25b0657aadefdf4ea2cd8dd06e18882a" - integrity sha512-29n+JdTb80ROiv/wDiBVlY/xRAF/nrjhp/Udv/XJl1DZb+x7JEiPxpbpthPhwwl+AYxVrostGB0W06WJ61hfiw== +metro-transform-worker@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro-transform-worker/-/metro-transform-worker-0.73.7.tgz#be111805e92ea48b7c76dd75830798f318e252e0" + integrity sha512-gZYIu9JAqEI9Rxi0xGMuMW6QsHGbMSptozlTOwOd7T7yXX3WwYS/I3yLPbLhbZTjOhwMHkTt8Nhm2qBo8nh14g== dependencies: - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" - "@babel/parser" "^7.14.0" - "@babel/types" "^7.0.0" + "@babel/core" "^7.20.0" + "@babel/generator" "^7.20.0" + "@babel/parser" "^7.20.0" + "@babel/types" "^7.20.0" babel-preset-fbjs "^3.4.0" - metro "0.67.0" - metro-babel-transformer "0.67.0" - metro-cache "0.67.0" - metro-cache-key "0.67.0" - metro-hermes-compiler "0.67.0" - metro-source-map "0.67.0" - metro-transform-plugins "0.67.0" + metro "0.73.7" + metro-babel-transformer "0.73.7" + metro-cache "0.73.7" + metro-cache-key "0.73.7" + metro-hermes-compiler "0.73.7" + metro-source-map "0.73.7" + metro-transform-plugins "0.73.7" nullthrows "^1.1.1" -metro@0.67.0, metro@^0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.67.0.tgz#8007a041d22de1cdb05184431c67eb7989eef6e0" - integrity sha512-DwuBGAFcAivoac/swz8Lp7Y5Bcge1tzT7T6K0nf1ubqJP8YzBUtyR4pkjEYVUzVu/NZf7O54kHSPVu1ibYzOBQ== +metro@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/metro/-/metro-0.73.7.tgz#435081339ac209e4d8802c57ac522638140c802b" + integrity sha512-pkRqFhuGUvkiu8HxKPUQelbCuyy6te6okMssTyLzQwsKilNLK4YMI2uD6PHnypg5SiMJ58lwfqkp/t5w72jEvw== dependencies: "@babel/code-frame" "^7.0.0" - "@babel/core" "^7.14.0" - "@babel/generator" "^7.14.0" - "@babel/parser" "^7.14.0" + "@babel/core" "^7.20.0" + "@babel/generator" "^7.20.0" + "@babel/parser" "^7.20.0" "@babel/template" "^7.0.0" - "@babel/traverse" "^7.14.0" - "@babel/types" "^7.0.0" + "@babel/traverse" "^7.20.0" + "@babel/types" "^7.20.0" absolute-path "^0.0.0" accepts "^1.3.7" - async "^2.4.0" + async "^3.2.2" chalk "^4.0.0" ci-info "^2.0.0" connect "^3.6.5" debug "^2.2.0" denodeify "^1.2.1" error-stack-parser "^2.0.6" - fs-extra "^1.0.0" - graceful-fs "^4.1.3" - hermes-parser "0.5.0" + graceful-fs "^4.2.4" + hermes-parser "0.8.0" image-size "^0.6.0" invariant "^2.2.4" - jest-haste-map "^27.3.1" - jest-worker "^26.0.0" + jest-worker "^27.2.0" lodash.throttle "^4.1.1" - metro-babel-transformer "0.67.0" - metro-cache "0.67.0" - metro-cache-key "0.67.0" - metro-config "0.67.0" - metro-core "0.67.0" - metro-hermes-compiler "0.67.0" - metro-inspector-proxy "0.67.0" - metro-minify-uglify "0.67.0" - metro-react-native-babel-preset "0.67.0" - metro-resolver "0.67.0" - metro-runtime "0.67.0" - metro-source-map "0.67.0" - metro-symbolicate "0.67.0" - metro-transform-plugins "0.67.0" - metro-transform-worker "0.67.0" + metro-babel-transformer "0.73.7" + metro-cache "0.73.7" + metro-cache-key "0.73.7" + metro-config "0.73.7" + metro-core "0.73.7" + metro-file-map "0.73.7" + metro-hermes-compiler "0.73.7" + metro-inspector-proxy "0.73.7" + metro-minify-terser "0.73.7" + metro-minify-uglify "0.73.7" + metro-react-native-babel-preset "0.73.7" + metro-resolver "0.73.7" + metro-runtime "0.73.7" + metro-source-map "0.73.7" + metro-symbolicate "0.73.7" + metro-transform-plugins "0.73.7" + metro-transform-worker "0.73.7" mime-types "^2.1.27" - mkdirp "^0.5.1" node-fetch "^2.2.0" nullthrows "^1.1.1" - rimraf "^2.5.4" + rimraf "^3.0.2" serialize-error "^2.1.0" source-map "^0.5.6" strip-ansi "^6.0.0" temp "0.8.3" throat "^5.0.0" ws "^7.5.1" - yargs "^15.3.1" + yargs "^17.5.1" -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -9280,7 +9762,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.0, micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -9363,11 +9845,16 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -9493,7 +9980,7 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@^2.0.0, ms@^2.1.1: +ms@2.1.2, ms@^2.0.0, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -9539,6 +10026,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -9569,10 +10061,10 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nocache@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" - integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== +nocache@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.4.tgz#5b37a56ec6e09fc7d401dceaed2eab40c8bfdf79" + integrity sha512-WDD0bdg9mbq6F4mRxEYcPWwfA1vxd0mrvKOyxI7Xj/atfRHVeutzuWByG//jfm4uPzp0y4Kj051EORCBSQMycw== node-dir@^0.1.17: version "0.1.17" @@ -9631,27 +10123,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= -node-machine-id@^1.1.12: - version "1.1.12" - resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" - integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ== - -node-notifier@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" - integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - -node-releases@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" - integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== +node-releases@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" + integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== node-simctl@^5.0.2: version "5.3.0" @@ -9707,13 +10182,6 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -9832,7 +10300,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^4.0.0: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -9985,20 +10453,25 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -ob1@0.67.0: - version "0.67.0" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.67.0.tgz#91f104c90641b1af8c364fc82a4b2c7d0801072d" - integrity sha512-YvZtX8HKYackQ5PwdFIuuNFVsMChRPHvnARRRT0Vk59xsBvL5t9U1Ock3M1sYrKj+Gp73+0q9xcHLAxI+xLi5g== +ob1@0.73.5: + version "0.73.5" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.5.tgz#b80dc4a6f787044e3d8afde3c2d034ae23d05a86" + integrity sha512-MxQH/rCq9/COvgTQbjCldArmesGEidZVVQIn4vDUJvJJ8uMphXOTCBsgWTief2ugvb0WUimIaslKSA+qryFjjQ== + +ob1@0.73.7: + version "0.73.7" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.7.tgz#14c9b6ddc26cf99144f59eb542d7ae956e6b3192" + integrity sha512-DfelfvR843KADhSUATGGhuepVMRcf5VQX+6MQLy5AW0BKDLlO7Usj6YZeAAZP7P86QwsoTxB0RXCFiA7t6S1IQ== + +ob1@0.73.9: + version "0.73.9" + resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.73.9.tgz#d5677a0dd3e2f16ad84231278d79424436c38c59" + integrity sha512-kHOzCOFXmAM26fy7V/YuXNKne2TyRiXbFAvPBIbuedJCZZWQZHLdPzMeXJI4Egt6IcfDttRzN3jQ90wOwq1iNw== object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" @@ -10128,7 +10601,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -10152,7 +10625,7 @@ openssl-wrapper@^0.3.4: resolved "https://registry.yarnpkg.com/openssl-wrapper/-/openssl-wrapper-0.3.4.tgz#c01ec98e4dcd2b5dfe0b693f31827200e3b81b07" integrity sha1-wB7Jjk3NK13+C2k/MYJyAOO4Gwc= -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.2: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -10254,11 +10727,6 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= -p-each-series@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" - integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== - p-filter@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" @@ -10300,6 +10768,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -10321,6 +10796,13 @@ p-locate@^4.0.0, p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -10464,6 +10946,16 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + parse-listing@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/parse-listing/-/parse-listing-1.1.3.tgz#aa546f57fdc129cfbf9945cd4b757b14b06182dd" @@ -10474,11 +10966,6 @@ parse-node-version@^1.0.0: resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== -parse5@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -10578,7 +11065,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -10605,7 +11092,7 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pirates@^4.0.1, pirates@^4.0.5: +pirates@^4.0.4, pirates@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== @@ -10646,7 +11133,7 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -plist@^3.0.1, plist@^3.0.2, plist@^3.0.5: +plist@^3.0.1: version "3.0.5" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.5.tgz#2cbeb52d10e3cdccccf0c11a63a85d830970a987" integrity sha512-83vX4eYdQp3vP9SxuYgEM/G/pJQqLUz/V/xzPrzruLs7fz7jxGQ1msZ/mg1nwZxUSuOp4sb+/bEIbRrbzZRxDA== @@ -10701,7 +11188,7 @@ prepend-http@^1.0.1: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -pretty-format@^26.0.0, pretty-format@^26.5.2, pretty-format@^26.6.2: +pretty-format@^26.5.2, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== @@ -10711,6 +11198,24 @@ pretty-format@^26.0.0, pretty-format@^26.5.2, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +pretty-format@^29.0.0, pretty-format@^29.4.1: + version "29.4.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.4.1.tgz#0da99b532559097b8254298da7c75a0785b1751c" + integrity sha512-dt/Z761JUVsrIKaY215o1xQJBGlSmTx/h4cSqXqjHLnU1+Kt+mavVE7UgqJJO5ukx5HjSswHfmXz4LjS2oIJfg== + dependencies: + "@jest/schemas" "^29.4.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +pretty-format@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.3.1.tgz#1841cac822b02b4da8971dacb03e8a871b4722da" + integrity sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/process-exists/-/process-exists-4.0.0.tgz#dc12d87798c17b3f129f716631e2ccdaf240b4ab" @@ -10751,7 +11256,7 @@ promise-retry@^1.1.1: err-code "^1.0.0" retry "^0.10.0" -promise@^8.0.3, promise@^8.2.0: +promise@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== @@ -10949,219 +11454,165 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-devtools-core@^4.23.0: - version "4.24.3" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.24.3.tgz#371fef3f5c639db0dc59eeef334dd5e10ac61661" - integrity sha512-+htKZxLxDN14jhRG3+IXRiJqNSGHUiPYrMtv9e7qlZxcbKeJjVs+C/hd8kZF5rydp3faBwFN6ZpTaZnLA3/ZGA== +react-devtools-core@^4.26.1: + version "4.27.1" + resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.27.1.tgz#167aa174383c65786cbb7e965a5b39c702f0a2d3" + integrity sha512-qXhcxxDWiFmFAOq48jts9YQYe1+wVoUXzJTlY4jbaATzyio6dd6CUGu3dXBhREeVgpZ+y4kg6vFJzIOZh6vY2w== dependencies: shell-quote "^1.6.1" ws "^7" -"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-native-codegen@*, react-native-codegen@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.18.tgz#99d6623d65292e8ce3fdb1d133a358caaa2145e7" - integrity sha512-XPI9aVsFy3dvgDZvyGWrFnknNiyb22kg5nHgxa0vjWTH9ENLBgVRZt9A64xHZ8BYihH+gl0p/1JNOCIEUzRPBg== - dependencies: - "@babel/parser" "^7.14.0" - flow-parser "^0.121.0" - jscodeshift "^0.13.1" - nullthrows "^1.1.1" - -react-native-codegen@^0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.13.tgz#4cc94546fc75a5dbe9350d59c10108f2efe6bc17" - integrity sha512-rCh1P+s0Q4N6vNgS97ckafbhJRztz22+0l0VZoyQC06F07J98kI5cUByH0ATypPRIdpkMbAZc59DoPdDFc01bg== - dependencies: - "@babel/parser" "^7.14.0" - flow-parser "^0.121.0" - jscodeshift "^0.13.1" - nullthrows "^1.1.1" +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-native-codegen@^0.0.17: - version "0.0.17" - resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.17.tgz#83fb814d94061cbd46667f510d2ddba35ffb50ac" - integrity sha512-7GIEUmAemH9uWwB6iYXNNsPoPgH06pxzGRmdBzK98TgFBdYJZ7CBuZFPMe4jmHQTPOkQazKZ/w5O6/71JBixmw== +react-native-codegen@^0.71.3, react-native-codegen@^0.71.5: + version "0.71.5" + resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.71.5.tgz#454a42a891cd4ca5fc436440d301044dc1349c14" + integrity sha512-rfsuc0zkuUuMjFnrT55I1mDZ+pBRp2zAiRwxck3m6qeGJBGK5OV5JH66eDQ4aa+3m0of316CqrJDRzVlYufzIg== dependencies: "@babel/parser" "^7.14.0" - flow-parser "^0.121.0" + flow-parser "^0.185.0" jscodeshift "^0.13.1" nullthrows "^1.1.1" -react-native-gradle-plugin@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.5.tgz#1f20d437b140eda65b6e3bdf6eb102bbab1a5a10" - integrity sha512-kGupXo+pD2mB6Z+Oyowor3qlCroiS32FNGoiGQdwU19u8o+NNhEZKwoKfC5Qt03bMZSmFlcAlTyf79vrS2BZKQ== - dependencies: - react-native-codegen "*" +react-native-gradle-plugin@^0.71.12: + version "0.71.13" + resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.13.tgz#6f60ff24ac712554903dfc0ae98475cb280c57a6" + integrity sha512-C66LNZAXbU0YDRkWx8d/8kjesdu7fsUAc/3QPJNftSXKEvEtnFZK2aH/rIgu1s5dbTcE0fjhdVPNJMRIfKo61w== -react-native-gradle-plugin@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.0.6.tgz#b61a9234ad2f61430937911003cddd7e15c72b45" - integrity sha512-eIlgtsmDp1jLC24dRn43hB3kEcZVqx6DUQbR0N1ABXGnMEafm9I3V3dUUeD1vh+Dy5WqijSoEwLNUPLgu5zDMg== - -react-native-macos@0.68.62: - version "0.68.62" - resolved "https://registry.yarnpkg.com/react-native-macos/-/react-native-macos-0.68.62.tgz#76785f42c1f3d37147c52ecdd1daf04331bab808" - integrity sha512-0IZ0ob8z6TUsENdbgWhKXdgn+HEYVPPPx3QU5WKkdpCoKuHFv9y9F+bPi4uMG36u2khF1eod1hkajXG3tOexDQ== - dependencies: - "@jest/create-cache-key-function" "^27.0.1" - "@react-native-community/cli" "^7.0.3" - "@react-native-community/cli-platform-android" "^7.0.1" - "@react-native-community/cli-platform-ios" "^7.0.1" - "@react-native-community/cli-tools" "^7.0.1" - "@react-native/assets" "1.0.0" - "@react-native/normalize-color" "2.0.0" - "@react-native/polyfills" "2.0.0" - abort-controller "^3.0.0" - anser "^1.4.9" - base64-js "^1.1.2" - deprecated-react-native-prop-types "^2.3.0" - event-target-shim "^5.0.1" - hermes-engine "~0.11.0" - invariant "^2.2.4" - jsc-android "^250230.2.1" - metro-react-native-babel-transformer "0.67.0" - metro-runtime "0.67.0" - metro-source-map "0.67.0" - nullthrows "^1.1.1" - pretty-format "^26.5.2" - promise "^8.0.3" - react-devtools-core "^4.23.0" - react-native-codegen "^0.0.17" - react-native-gradle-plugin "^0.0.6" - react-refresh "^0.4.0" - react-shallow-renderer "16.14.1" - readable-stream "^4.0.0" - regenerator-runtime "^0.13.2" - scheduler "^0.20.2" - stacktrace-parser "^0.1.3" - use-subscription ">=1.0.0 <1.6.0" - whatwg-fetch "^3.0.0" - ws "^6.1.4" +react-native-gradle-plugin@^0.71.19: + version "0.71.19" + resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.19.tgz#3379e28341fcd189bc1f4691cefc84c1a4d7d232" + integrity sha512-1dVk9NwhoyKHCSxcrM6vY6cxmojeATsBobDicX0ZKr7DgUF2cBQRTKsimQFvzH8XhOVXyH8p4HyDSZNIFI8OlQ== -react-native-test-app@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/react-native-test-app/-/react-native-test-app-2.3.2.tgz#4f9b003077f02837817ec86844e9175f0fec2d6a" - integrity sha512-xe9Fb4oHBSbEvzbGmmVxHoSNIXT26gfH1CvGyAiiWq9V485s9duQj72dwZKMQtnZGw3jjahafFhv2D49pzadOg== +react-native-test-app@2.3.18: + version "2.3.18" + resolved "https://registry.yarnpkg.com/react-native-test-app/-/react-native-test-app-2.3.18.tgz#3ea978f2d1941fceb552eb1c78e286e73d610f4f" + integrity sha512-LmAhwd3a4wkOnUVG047v80Cz2acbR5eAJS37NPNCLhGXRyx8nV8H/2+HrZHcxwOAZLLblvZ4LDjFiDzHO0V2cw== dependencies: ajv "^8.0.0" chalk "^4.1.0" + cliui "^8.0.0" fast-xml-parser "^4.0.0" + minimist "^1.2.8" prompts "^2.4.0" semver "^7.3.5" uuid "^8.3.2" - yargs "^16.0.0" -react-native-windows@0.68.4: - version "0.68.4" - resolved "https://registry.yarnpkg.com/react-native-windows/-/react-native-windows-0.68.4.tgz#8619b002c05d33e52c3aa0b871ad55789016d8d5" - integrity sha512-i4PMiFbbuKmCcYaMQs0YKpsxl9mn2m8Ij4BnOYtJji4eS108O3/bB/qLd3povWq5qu96D2anpw/KleVozvMBjw== +react-native-windows@0.71.0: + version "0.71.0" + resolved "https://registry.yarnpkg.com/react-native-windows/-/react-native-windows-0.71.0.tgz#d5514f2a85020985851c06f8fa482580c6a80a28" + integrity sha512-k56CKEJpIFA50LAT2JZJxz4EkTx1hkZLcQL/g3aMTAu9hwnKptQVaAMs8okhP1fgMoUbbZ1lQB+deYyHyJAr7Q== dependencies: "@babel/runtime" "^7.0.0" - "@jest/create-cache-key-function" "^27.0.1" - "@react-native-community/cli" "^7.0.3" - "@react-native-community/cli-platform-android" "^7.0.1" - "@react-native-community/cli-platform-ios" "^7.0.1" - "@react-native-windows/cli" "0.68.2" - "@react-native-windows/virtualized-list" "0.68.0" + "@jest/create-cache-key-function" "^29.2.1" + "@react-native-community/cli" "10.0.0" + "@react-native-community/cli-platform-android" "10.0.0" + "@react-native-community/cli-platform-ios" "10.0.0" + "@react-native-windows/cli" "0.71.0" "@react-native/assets" "1.0.0" - "@react-native/normalize-color" "2.0.0" + "@react-native/normalize-color" "2.1.0" "@react-native/polyfills" "2.0.0" abort-controller "^3.0.0" anser "^1.4.9" base64-js "^1.1.2" - deprecated-react-native-prop-types "^2.3.0" + deprecated-react-native-prop-types "^3.0.1" event-target-shim "^5.0.1" - hermes-engine "~0.11.0" invariant "^2.2.4" + jest-environment-node "^29.2.1" jsc-android "^250230.2.1" - metro-react-native-babel-transformer "0.67.0" - metro-runtime "0.67.0" - metro-source-map "0.67.0" + memoize-one "^5.0.0" + metro-react-native-babel-transformer "0.73.5" + metro-runtime "0.73.5" + metro-source-map "0.73.5" + mkdirp "^0.5.1" nullthrows "^1.1.1" pretty-format "^26.5.2" - promise "^8.0.3" - react-devtools-core "^4.23.0" - react-native-codegen "^0.0.13" - react-native-gradle-plugin "^0.0.5" + promise "^8.3.0" + react-devtools-core "^4.26.1" + react-native-codegen "^0.71.3" + react-native-gradle-plugin "^0.71.12" react-refresh "^0.4.0" - react-shallow-renderer "16.14.1" + react-shallow-renderer "^16.15.0" regenerator-runtime "^0.13.2" - scheduler "^0.20.2" + scheduler "^0.23.0" source-map-support "^0.5.19" stacktrace-parser "^0.1.3" - use-subscription "^1.0.0" + use-sync-external-store "^1.0.0" whatwg-fetch "^3.0.0" - ws "^6.1.4" + ws "^6.2.2" -react-native@0.68.5: - version "0.68.5" - resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.68.5.tgz#8ba7389e00b757c59b6ea23bf38303d52367d155" - integrity sha512-t3kiQ/gumFV+0r/NRSIGtYxanjY4da0utFqHgkMcRPJVwXFWC0Fr8YiOeRGYO1dp8EfrSsOjtfWic/inqVYlbQ== +react-native@0.71.10: + version "0.71.10" + resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.10.tgz#4294d289b4226a3f35bd627bb157fc1f18395d58" + integrity sha512-O+sWH9ln7euxhHdooVL8is2FiVc7CfAp2zsKgIRhbq/8lGbJr5ZyT6QkCQK0M8Sx1zNe9puebr+BE8uBFsartg== dependencies: - "@jest/create-cache-key-function" "^27.0.1" - "@react-native-community/cli" "^7.0.3" - "@react-native-community/cli-platform-android" "^7.0.1" - "@react-native-community/cli-platform-ios" "^7.0.1" + "@jest/create-cache-key-function" "^29.2.1" + "@react-native-community/cli" "10.2.2" + "@react-native-community/cli-platform-android" "10.2.0" + "@react-native-community/cli-platform-ios" "10.2.1" "@react-native/assets" "1.0.0" - "@react-native/normalize-color" "2.0.0" + "@react-native/normalize-color" "2.1.0" "@react-native/polyfills" "2.0.0" abort-controller "^3.0.0" anser "^1.4.9" base64-js "^1.1.2" - deprecated-react-native-prop-types "^2.3.0" + deprecated-react-native-prop-types "^3.0.1" event-target-shim "^5.0.1" - hermes-engine "~0.11.0" invariant "^2.2.4" - jsc-android "^250230.2.1" - metro-react-native-babel-transformer "0.67.0" - metro-runtime "0.67.0" - metro-source-map "0.67.0" + jest-environment-node "^29.2.1" + jsc-android "^250231.0.0" + memoize-one "^5.0.0" + metro-react-native-babel-transformer "0.73.9" + metro-runtime "0.73.9" + metro-source-map "0.73.9" + mkdirp "^0.5.1" nullthrows "^1.1.1" pretty-format "^26.5.2" - promise "^8.2.0" - react-devtools-core "^4.23.0" - react-native-codegen "^0.0.18" - react-native-gradle-plugin "^0.0.6" + promise "^8.3.0" + react-devtools-core "^4.26.1" + react-native-codegen "^0.71.5" + react-native-gradle-plugin "^0.71.19" react-refresh "^0.4.0" - react-shallow-renderer "16.14.1" + react-shallow-renderer "^16.15.0" regenerator-runtime "^0.13.2" - scheduler "^0.20.2" + scheduler "^0.23.0" stacktrace-parser "^0.1.3" - use-subscription ">=1.0.0 <1.6.0" + use-sync-external-store "^1.0.0" whatwg-fetch "^3.0.0" - ws "^6.1.4" + ws "^6.2.2" react-refresh@^0.4.0: version "0.4.3" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.4.3.tgz#966f1750c191672e76e16c2efa569150cc73ab53" integrity sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA== -react-shallow-renderer@16.14.1: - version "16.14.1" - resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124" - integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg== +react-shallow-renderer@^16.15.0: + version "16.15.0" + resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz#48fb2cf9b23d23cde96708fe5273a7d3446f4457" + integrity sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA== dependencies: object-assign "^4.1.1" - react-is "^16.12.0 || ^17.0.0" + react-is "^16.12.0 || ^17.0.0 || ^18.0.0" -react@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== +react@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" read-cmd-shim@^1.0.1, read-cmd-shim@^1.0.5: version "1.0.5" @@ -11287,16 +11738,6 @@ readable-stream@^1.0.31, readable-stream@~1.1.10: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.3.0.tgz#0914d0c72db03b316c9733bb3461d64a3cc50cba" - integrity sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - readdir-glob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.0.0.tgz#a495436934bbe57be6a68039d16e8946621eb8c5" @@ -11351,17 +11792,17 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== +regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== dependencies: - regenerate "^1.4.0" + regenerate "^1.4.2" -regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== regenerator-runtime@^0.11.0: version "0.11.1" @@ -11373,13 +11814,6 @@ regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0 resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -11393,17 +11827,22 @@ regexpp@^2.0.1: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +regexpu-core@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d" + integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA== dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" registry-auth-token@^3.0.1: version "3.4.0" @@ -11427,23 +11866,18 @@ registry-url@^3.0.3: dependencies: rc "^1.0.1" -regjsgen@^0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== +regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== +regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== dependencies: jsesc "~0.5.0" -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - repeat-element@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" @@ -11549,7 +11983,12 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.18.1, resolve@^1.8.1: +resolve.exports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.0.tgz#c1a0028c2d166ec2fbf7d0644584927e76e7400e" + integrity sha512-6K/gDlqgQscOlg9fSRpWstA8sYe8rbELsSTNpx+3kTrsVCzvSl0zIvRErM7fdl9ERWDsKnrLnwB+Ne89918XOg== + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13.1, resolve@^1.8.1: version "1.22.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== @@ -11558,6 +11997,15 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.0, resolve@^1.13 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.20.0: + version "1.22.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" @@ -11664,11 +12112,6 @@ rpc-websockets@^5.1.1: uuid "^3.4.0" ws "^5.2.2" -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - run-async@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -11725,21 +12168,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - sanitize-filename@^1.6.1: version "1.6.3" resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" @@ -11747,25 +12175,17 @@ sanitize-filename@^1.6.1: dependencies: truncate-utf8-bytes "^1.0.0" -sax@>=0.6.0, sax@^1.2.1: +sax@>=0.6.0: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - -scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== dependencies: loose-envify "^1.1.0" - object-assign "^4.1.1" selenium-appium@1.0.2: version "1.0.2" @@ -11845,10 +12265,10 @@ semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.0.0, semver@^7.3.2, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== +semver@^7.0.0, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" @@ -11987,16 +12407,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c= - dependencies: - array-filter "~0.0.0" - array-map "~0.0.0" - array-reduce "~0.0.0" - jsonify "~0.0.0" - shell-quote@^1.4.3, shell-quote@^1.6.1, shell-quote@^1.7.2, shell-quote@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" @@ -12011,11 +12421,6 @@ shelljs@0.8.x, shelljs@^0.8.4: interpret "^1.0.0" rechoir "^0.6.2" -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - shimmer@^1.1.0, shimmer@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" @@ -12026,6 +12431,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signale@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1" @@ -12035,15 +12445,6 @@ signale@^1.2.1: figures "^2.0.0" pkg-conf "^2.1.0" -simple-plist@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.3.1.tgz#16e1d8f62c6c9b691b8383127663d834112fb017" - integrity sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw== - dependencies: - bplist-creator "0.1.0" - bplist-parser "0.3.1" - plist "^3.0.5" - simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -12155,7 +12556,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -"source-map-support@0.3.2 - 1.0.0", source-map-support@0.x, source-map-support@^0.5.12, source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.3, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@^0.5.8, source-map-support@^0.5.9: +"source-map-support@0.3.2 - 1.0.0", source-map-support@0.x, source-map-support@^0.5.12, source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.3, source-map-support@^0.5.5, source-map-support@^0.5.8, source-map-support@^0.5.9, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -12163,12 +12564,20 @@ source-map-resolve@^0.5.0: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.6: +source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -12284,10 +12693,10 @@ stack-trace@0.0.x: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= -stack-utils@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" - integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" @@ -12402,14 +12811,14 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" string.prototype.trimend@^1.0.1: version "1.0.1" @@ -12472,12 +12881,12 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -12506,7 +12915,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.0.1: +strip-json-comments@^3.0.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -12533,7 +12942,7 @@ supports-color@^5.0.0, supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -12555,24 +12964,11 @@ supports-hyperlinks@^1.0.1: has-flag "^2.0.0" supports-color "^5.0.0" -supports-hyperlinks@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" - integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -12672,13 +13068,15 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== +terser@^5.15.0: + version "5.16.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.1.tgz#5af3bc3d0f24241c7fb2024199d5c461a1075880" + integrity sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw== dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" test-exclude@^6.0.0: version "6.0.0" @@ -12769,6 +13167,11 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -12833,13 +13236,6 @@ tough-cookie@^4.0.0: punycode "^2.1.1" universalify "^0.1.2" -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -12882,10 +13278,10 @@ tslib@^2.0.1, tslib@^2.2.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tsutils@^3.14.0: - version "3.17.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" - integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== +tsutils@^3.14.0, tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" @@ -12966,13 +13362,6 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -13019,28 +13408,28 @@ unbzip2-stream@^1.3.3: buffer "^5.2.1" through "^2.3.8" -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" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== union-value@^1.0.0: version "1.0.1" @@ -13113,6 +13502,14 @@ unzip-response@^2.0.1: resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= +update-browserslist-db@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" + integrity sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + update-notifier@^2.2.0, update-notifier@^2.3.0, update-notifier@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" @@ -13153,12 +13550,10 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" -"use-subscription@>=1.0.0 <1.6.0", use-subscription@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" - integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== - dependencies: - object-assign "^4.1.1" +use-sync-external-store@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== use@^3.1.0: version "3.1.1" @@ -13224,11 +13619,6 @@ uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== - uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" @@ -13239,14 +13629,14 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== -v8-to-istanbul@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" - integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== dependencies: + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" - source-map "^0.7.3" validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" @@ -13287,27 +13677,20 @@ vlq@^1.0.0: resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: +walker@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -13393,33 +13776,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - whatwg-fetch@^3.0.0: version "3.4.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.0.tgz#e11de14f4878f773fbebcde8871b2c0699af8b30" integrity sha512-rsum2ulz2iuZH08mJkT0Yi6JnKhwdw4oeyMjokgxd+mmqYSd9cPpOQf01TIWgjxG/U4+QR+AwKq6lSbXVxkyoQ== -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -13428,15 +13789,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -13571,15 +13923,13 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.3: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== +write-file-atomic@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.0.tgz#54303f117e109bf3d540261125c8ea5a7320fab0" + integrity sha512-R7NYMnHSlV42K54lwY9lvW6MnSm1HSJqZL3xiSgi9E7//FYaI74r2G0rd+/X6VAMkHEdzxQaU5HUOXWUz5kA/w== dependencies: imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" + signal-exit "^3.0.7" write@1.0.3: version "1.0.3" @@ -13595,26 +13945,18 @@ ws@^5.2.2: dependencies: async-limiter "~1.0.0" -ws@^6.1.4: +ws@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== dependencies: async-limiter "~1.0.0" -ws@^7, ws@^7.0.0, ws@^7.2.3, ws@^7.4.6, ws@^7.5.1: +ws@^7, ws@^7.0.0, ws@^7.2.3, ws@^7.5.1: version "7.5.7" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -xcode@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c" - integrity sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA== - dependencies: - simple-plist "^1.1.0" - uuid "^7.0.3" - xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" @@ -13637,11 +13979,6 @@ xml-formatter@^2.4.0: dependencies: xml-parser-xo "^3.2.0" -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - xml-parse-from-string@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" @@ -13677,18 +14014,6 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xmldoc@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/xmldoc/-/xmldoc-1.1.2.tgz#6666e029fe25470d599cd30e23ff0d1ed50466d7" - integrity sha512-ruPC/fyPNck2BD1dpz0AZZyrEwMOrWTO5lDdIXS91rs3wtm4j+T8Rp2o+zoOYkkAxJTZRPOSnOGei1egoRmKMQ== - dependencies: - sax "^1.2.1" - xmldom@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.3.0.tgz#e625457f4300b5df9c2e1ecb776147ece47f3e5a" @@ -13768,6 +14093,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs-parser@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" @@ -13810,7 +14140,7 @@ yargs@^14.0.0, yargs@^14.2.3: y18n "^4.0.0" yargs-parser "^15.0.1" -yargs@^15.0.1, yargs@^15.1.0, yargs@^15.3.0, yargs@^15.3.1, yargs@^15.4.1: +yargs@^15.0.1, yargs@^15.1.0, yargs@^15.3.0: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== @@ -13827,7 +14157,7 @@ yargs@^15.0.1, yargs@^15.1.0, yargs@^15.3.0, yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -13840,6 +14170,19 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.3.1, yargs@^17.5.1: + version "17.6.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" + integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" @@ -13867,6 +14210,11 @@ yauzl@^2.10.0, yauzl@^2.7.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zip-stream@^2.1.2: version "2.1.3" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"