first commit

This commit is contained in:
2026-03-10 16:18:05 +00:00
commit 11f9c069b5
31635 changed files with 3187747 additions and 0 deletions

2
node_modules/@expo/dom-webview/.eslintrc.js generated vendored Normal file
View File

@@ -0,0 +1,2 @@
// @generated by expo-module-scripts
module.exports = require('expo-module-scripts/eslintrc.base.js');

30
node_modules/@expo/dom-webview/README.md generated vendored Normal file
View File

@@ -0,0 +1,30 @@
# @expo/dom-webview
The `@expo/dom-webview` module is a WebView specifically designed for DOM components. It creates a bridge between native code and the WebView, allowing you to import and use Expo modules within DOM components. While this WebView does not have full feature parity with `react-native-webview`, additional features may be added based on internal requests and evolving needs.
# API documentation
- [Documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/@expo/dom-webview/)
- [Documentation for the main branch](https://docs.expo.dev/versions/unversioned/sdk/@expo/dom-webview/)
# Installation in managed Expo projects
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
# Installation in bare React Native projects
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
### Add the package to your npm dependencies
```
npx expo install @expo/dom-webview
```
### Configure for iOS
Run `npx pod-install` after installing the npm package.
# Contributing
Contributions are very welcome! Please refer to guidelines described in the [contributing guide](https://github.com/expo/expo#contributing).

15
node_modules/@expo/dom-webview/android/build.gradle generated vendored Normal file
View File

@@ -0,0 +1,15 @@
plugins {
id 'com.android.library'
id 'expo-module-gradle-plugin'
}
group = 'expo.modules.webview'
version = '55.0.3'
android {
namespace "expo.modules.webview"
defaultConfig {
versionCode 1
versionName "55.0.3"
}
}

View File

@@ -0,0 +1,2 @@
<manifest>
</manifest>

View File

@@ -0,0 +1,176 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.view.ViewGroup
import android.webkit.WebView
import android.webkit.WebViewClient
import expo.modules.kotlin.AppContext
import expo.modules.kotlin.viewevent.EventDispatcher
import expo.modules.kotlin.views.ExpoView
import kotlinx.coroutines.runBlocking
import org.json.JSONObject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@SuppressLint("ViewConstructor")
internal class DomWebView(context: Context, appContext: AppContext) : ExpoView(context, appContext), OnTouchListener {
val webView: WebView
val webViewId = DomWebViewRegistry.add(this)
private var source: DomWebViewSource? = null
private var injectedJSBeforeContentLoaded: String? = null
var webviewDebuggingEnabled = false
var nestedScrollEnabled = true
private var needsResetupScripts = false
private val onMessage by EventDispatcher<OnMessageEvent>()
init {
this.webView = createWebView()
addView(
webView,
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
)
}
// region Public methods
fun reload() {
WebView.setWebContentsDebuggingEnabled(webviewDebuggingEnabled)
source?.uri?.let {
if (it != webView.url) {
webView.loadUrl(it)
}
return
}
if (needsResetupScripts) {
needsResetupScripts = false
webView.reload()
}
}
fun setSource(source: DomWebViewSource) {
this.source = source
}
fun setInjectedJSBeforeContentLoaded(script: String?) {
injectedJSBeforeContentLoaded = if (!script.isNullOrEmpty()) {
"(function() { $script; })();true;"
} else {
null
}
needsResetupScripts = true
}
fun injectJavaScript(script: String) {
webView.post {
webView.evaluateJavascript(script, null)
}
}
fun dispatchMessageEvent(message: String) {
webView.post {
val messageEvent = OnMessageEvent(
title = webView.title ?: "",
url = webView.url ?: "",
data = message
)
onMessage.invoke(messageEvent)
}
}
fun evalSync(data: String): String {
val json = JSONObject(data)
val deferredId = json.getInt("deferredId")
val source = json.getString("source")
return runBlocking {
nativeJsiEvalSync(deferredId, source)
}
}
fun scrollTo(param: ScrollToParam) {
webView.post {
if (!param.animated) {
webView.scrollTo(param.x.toInt(), param.y.toInt())
return@post
}
val duration = 250L
val animatorX = ObjectAnimator.ofInt(webView, "scrollX", webView.scrollX, param.x.toInt())
animatorX.setDuration(duration)
val animatorY = ObjectAnimator.ofInt(webView, "scrollY", webView.scrollY, param.y.toInt())
animatorY.setDuration(duration)
animatorX.start()
animatorY.start()
}
}
// endregion Public methods
// region Override methods
override fun onTouch(view: View?, event: MotionEvent?): Boolean {
if (nestedScrollEnabled) {
requestDisallowInterceptTouchEvent(true)
}
return false
}
// region Override methods
// region Internals
@SuppressLint("SetJavaScriptEnabled")
private fun createWebView(): WebView {
return WebView(context).apply {
setBackgroundColor(Color.TRANSPARENT)
settings.javaScriptEnabled = true
webViewClient = createWebViewClient()
addJavascriptInterface(RNCWebViewBridge(this@DomWebView), "ReactNativeWebView")
addJavascriptInterface(DomWebViewBridge(this@DomWebView), "ExpoDomWebViewBridge")
setOnTouchListener(this@DomWebView)
}
}
private fun createWebViewClient() = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
injectJavaScript(INSTALL_GLOBALS_SCRIPT.replace("\"%%WEBVIEW_ID%%\"", webViewId.toString()))
this@DomWebView.injectedJSBeforeContentLoaded?.let {
injectJavaScript(it)
}
}
}
private suspend fun nativeJsiEvalSync(deferredId: Int, source: String): String {
return suspendCoroutine { continuation ->
appContext.executeOnJavaScriptThread {
val wrappedSource = NATIVE_EVAL_WRAPPER_SCRIPT
.replace("\"%%DEFERRED_ID%%\"", deferredId.toString())
.replace("\"%%WEBVIEW_ID%%\"", webViewId.toString())
.replace("\"%%SOURCE%%\"", source)
try {
val result = appContext.runtime.eval(wrappedSource)
continuation.resume(result.getString())
} catch (e: Exception) {
continuation.resumeWithException(e)
}
}
}
}
// endregion Internals
}

View File

@@ -0,0 +1,12 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import android.webkit.JavascriptInterface
internal class DomWebViewBridge(private val webView: DomWebView) {
@JavascriptInterface
fun eval(params: String): String {
return webView.evalSync(params)
}
}

View File

@@ -0,0 +1,264 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
/**
* This file contains the browser scripts that are injected into the WebView.
* @generated by buildBrowserScripts.ts
*/
internal const val INSTALL_GLOBALS_SCRIPT: String = """
// browserScripts/InstallGlobals/Deferred.ts
class Deferred {
promise;
resolveCallback;
rejectCallback;
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolveCallback = resolve;
this.rejectCallback = reject;
});
}
resolve(value) {
this.resolveCallback(value);
}
reject(reason) {
this.rejectCallback(reason);
}
getPromise() {
return this.promise;
}
}
// browserScripts/InstallGlobals/EventEmitterProxy.ts
class EventEmitterProxy {
moduleName;
listeners;
constructor(moduleName) {
this.moduleName = moduleName;
}
addListener = (eventName, listener) => {
if (!this.listeners) {
this.listeners = new Map;
}
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, new Set);
}
this.listeners.get(eventName)?.add(listener);
const nativeListenerId = window.ExpoDomWebView.nextEventListenerId++;
listener.${'$'}${'$'}nativeListenerId = nativeListenerId;
const source = `
globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap ||= {};
globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap['${'$'}{eventName}'] ||= new Map();
const listener = (...args) => {
const serializeArgs = args.map((arg) => JSON.stringify(arg)).join(',');
const script = 'window.ExpoDomWebView.eventEmitterProxy.${'$'}{this.moduleName}.emit("${'$'}{eventName}", ' + serializeArgs + ')';
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
};
globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap['${'$'}{eventName}'].set(${'$'}{nativeListenerId}, listener);
globalThis.expo.modules.${'$'}{this.moduleName}.addListener('${'$'}{eventName}', listener);
`;
window.ExpoDomWebView.eval(source);
return {
remove: () => {
this.removeListener(eventName, listener);
}
};
};
removeListener = (eventName, listener) => {
const nativeListenerId = listener.${'$'}${'$'}nativeListenerId;
if (nativeListenerId != null) {
const source = `(function() {
const nativeListener = globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap['${'$'}{eventName}'].get(${'$'}{nativeListenerId});
if (nativeListener != null) {
globalThis.expo.modules.${'$'}{this.moduleName}.removeListener('${'$'}{eventName}', nativeListener);
globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap['${'$'}{eventName}'].delete(${'$'}{nativeListenerId});
}
})();
true;
`;
window.ExpoDomWebView.eval(source);
}
this.listeners?.get(eventName)?.delete(listener);
};
removeAllListeners = (eventName) => {
const source = `
globalThis.expo.${'$'}${'$'}DomWebViewEventListenerMap['${'$'}{eventName}'].clear();
globalThis.expo.modules.${'$'}{this.moduleName}.removeAllListeners('${'$'}{eventName}');
`;
window.ExpoDomWebView.eval(source);
this.listeners?.get(eventName)?.clear();
};
emit = (eventName, ...args) => {
const listeners = new Set(this.listeners?.get(eventName));
listeners.forEach((listener) => {
try {
listener(...args);
} catch (error) {
console.error(error);
}
});
};
}
// browserScripts/InstallGlobals/utils.ts
function serializeArgs(args) {
return args.map((arg) => {
if (typeof arg === "object" && arg.sharedObjectId != null) {
return `globalThis.expo.sharedObjectRegistry.get(${'$'}{arg.sharedObjectId})`;
}
return JSON.stringify(arg);
}).join(",");
}
// browserScripts/InstallGlobals/proxies.ts
function createSharedObjectProxy(sharedObjectId) {
return new Proxy({}, {
get: (target, prop) => {
const name = String(prop);
if (name === "sharedObjectId") {
return sharedObjectId;
}
return function(...args) {
const serializedArgs = serializeArgs(args);
const source = `globalThis.expo.sharedObjectRegistry.get(${'$'}{sharedObjectId})?.${'$'}{name}?.call(globalThis.expo.sharedObjectRegistry.get(${'$'}{sharedObjectId}),${'$'}{serializedArgs})`;
return window.ExpoDomWebView.eval(source);
};
}
});
}
function createConstructorProxy(moduleName, property, propertyName) {
return new Proxy(function() {
}, {
construct(target, args) {
const serializedArgs = serializeArgs(args);
const sharedObjectId = window.ExpoDomWebView.nextSharedObjectId++;
const sharedObjectProxy = createSharedObjectProxy(sharedObjectId);
window.ExpoDomWebView.sharedObjectFinalizationRegistry.register(sharedObjectProxy, sharedObjectId);
const source = `globalThis.expo.sharedObjectRegistry ||= new Map(); globalThis.expo.sharedObjectRegistry.set(${'$'}{sharedObjectId}, new ${'$'}{property}(${'$'}{serializedArgs}));`;
window.ExpoDomWebView.eval(source);
return sharedObjectProxy;
}
});
}
function createPropertyProxy(propertyTypeCache, moduleName, propertyName) {
const property = `globalThis.expo.modules.${'$'}{moduleName}.${'$'}{propertyName}`;
let propertyType = propertyTypeCache[propertyName];
if (!propertyType) {
const typeCheck = `${'$'}{property}?.prototype?.__expo_shared_object_id__ != null ? 'sharedObject' : typeof ${'$'}{property}`;
propertyType = window.ExpoDomWebView.eval(typeCheck);
propertyTypeCache[propertyName] = propertyType;
}
if (propertyType === "sharedObject") {
return createConstructorProxy(moduleName, property, propertyName);
}
if (propertyType === "function") {
return function(...args) {
const serializedArgs = serializeArgs(args);
const source = `${'$'}{property}(${'$'}{serializedArgs})`;
return window.ExpoDomWebView.eval(source);
};
}
return window.ExpoDomWebView.eval(property);
}
function createExpoModuleProxy(moduleName) {
const propertyTypeCache = {};
return new Proxy({}, {
get: (target, prop) => {
const name = String(prop);
if (["addListener", "removeListener", "removeAllListeners"].includes(name)) {
return window.ExpoDomWebView.eventEmitterProxy[moduleName][name];
}
return createPropertyProxy(propertyTypeCache, moduleName, name);
}
});
}
// browserScripts/InstallGlobals/ExpoDomWebView.ts
class ExpoDomWebView {
nextDeferredId;
nextSharedObjectId;
nextEventListenerId;
deferredMap;
sharedObjectFinalizationRegistry;
expoModulesProxy;
eventEmitterProxy;
constructor() {
this.nextDeferredId = 0;
this.nextSharedObjectId = 0;
this.nextEventListenerId = 0;
this.deferredMap = new Map;
this.sharedObjectFinalizationRegistry = new FinalizationRegistry((sharedObjectId) => {
this.eval(`globalThis.expo.sharedObjectRegistry.delete(${'$'}{sharedObjectId})`);
});
const expoModules = {};
const eventEmitterProxy = {};
this.eval("Object.keys(globalThis.expo.modules)").forEach((name) => {
expoModules[name] = createExpoModuleProxy(name);
eventEmitterProxy[name] = new EventEmitterProxy(name);
});
this.expoModulesProxy = expoModules;
this.eventEmitterProxy = eventEmitterProxy;
}
eval(source) {
const { deferredId, deferred } = this.createDeferred();
const args = JSON.stringify({ source, deferredId });
const result = JSON.parse(window.ExpoDomWebViewBridge.eval(args));
if (result.isPromise) {
return deferred.getPromise();
}
this.removeDeferred(deferredId);
return result.value;
}
createDeferred() {
const deferred = new Deferred;
const deferredId = this.nextDeferredId;
this.deferredMap.set(deferredId, deferred);
this.nextDeferredId += 1;
return { deferredId, deferred };
}
resolveDeferred(deferredId, value) {
const deferred = this.deferredMap.get(deferredId);
if (deferred) {
deferred.resolve(value);
this.deferredMap.delete(deferredId);
}
}
rejectDeferred(deferredId, reason) {
const deferred = this.deferredMap.get(deferredId);
if (deferred) {
deferred.reject(reason);
this.deferredMap.delete(deferredId);
}
}
removeDeferred(deferredId) {
this.deferredMap.delete(deferredId);
}
}
// browserScripts/InstallGlobals/index.ts
window.ExpoDomWebView = new ExpoDomWebView;
"""
internal const val NATIVE_EVAL_WRAPPER_SCRIPT: String = """
// browserScripts/NativeEvalWrapper/index.ts
(function() {
const result = "%%SOURCE%%";
if (result instanceof Promise) {
result.then((resolved) => {
const resolvedString = JSON.stringify(resolved);
const script = 'window.ExpoDomWebView.resolveDeferred("%%DEFERRED_ID%%", ' + resolvedString + ")";
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
}).catch((error) => {
const errorString = JSON.stringify(error);
const script = 'window.ExpoDomWebView.rejectDeferred("%%DEFERRED_ID%%", ' + errorString + ")";
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
});
return JSON.stringify({ isPromise: true, value: null });
} else {
return JSON.stringify({ isPromise: false, value: result });
}
})();
"""

View File

@@ -0,0 +1,12 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import expo.modules.kotlin.records.Field
import expo.modules.kotlin.records.Record
internal data class OnMessageEvent(
@Field val title: String,
@Field val url: String,
@Field val data: String
) : Record

View File

@@ -0,0 +1,65 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
@Suppress("unused")
class DomWebViewModule : Module() {
override fun definition() = ModuleDefinition {
Name("ExpoDomWebViewModule")
OnDestroy {
DomWebViewRegistry.reset()
}
AsyncFunction("evalJsForWebViewAsync") { webViewId: Int, source: String ->
DomWebViewRegistry.get(webViewId)?.injectJavaScript(source)
}
View(DomWebView::class) {
Events("onMessage")
Prop("source") { view: DomWebView, source: DomWebViewSource ->
view.setSource(source)
}
Prop("injectedJavaScriptBeforeContentLoaded") { view: DomWebView, script: String ->
view.setInjectedJSBeforeContentLoaded(script)
}
Prop("webviewDebuggingEnabled") { view: DomWebView, enabled: Boolean ->
view.webviewDebuggingEnabled = enabled
}
Prop("showsHorizontalScrollIndicator") { view: DomWebView, enabled: Boolean ->
view.webView.post {
view.webView.isHorizontalScrollBarEnabled = enabled
}
}
Prop("showsVerticalScrollIndicator") { view: DomWebView, enabled: Boolean ->
view.webView.post {
view.webView.isVerticalScrollBarEnabled = enabled
}
}
Prop("nestedScrollEnabled") { view: DomWebView, enabled: Boolean ->
view.nestedScrollEnabled = enabled
}
AsyncFunction("scrollTo") { view: DomWebView, param: ScrollToParam ->
view.scrollTo(param)
}
AsyncFunction("injectJavaScript") { view: DomWebView, script: String ->
view.injectJavaScript(script)
}
OnViewDidUpdateProps { view: DomWebView ->
view.reload()
}
}
}
}

View File

@@ -0,0 +1,16 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import expo.modules.kotlin.records.Field
import expo.modules.kotlin.records.Record
internal data class DomWebViewSource(
@Field val uri: String?
) : Record
internal data class ScrollToParam(
@Field val x: Double = 0.0,
@Field val y: Double = 0.0,
@Field val animated: Boolean = true
) : Record

View File

@@ -0,0 +1,37 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import androidx.collection.ArrayMap
import java.lang.ref.WeakReference
internal typealias WebViewId = Int
internal object DomWebViewRegistry {
private val registry = ArrayMap<WebViewId, WeakDomWebViewRef>()
private var nextWebViewId: WebViewId = 0
@Synchronized
fun get(webViewId: WebViewId): DomWebView? {
return registry[webViewId]?.ref?.get()
}
@Synchronized
fun add(webView: DomWebView): WebViewId {
val webViewId = this.nextWebViewId
this.registry[webViewId] = WeakDomWebViewRef(WeakReference(webView))
this.nextWebViewId += 1
return webViewId
}
@Synchronized
fun remove(webViewId: WebViewId): DomWebView? {
return this.registry.remove(webViewId)?.ref?.get()
}
@Synchronized
fun reset() {
this.registry.clear()
this.nextWebViewId = 0
}
}

View File

@@ -0,0 +1,12 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import android.webkit.JavascriptInterface
internal class RNCWebViewBridge(private val webView: DomWebView) {
@JavascriptInterface
fun postMessage(message: String) {
webView.dispatchMessageEvent(message)
}
}

View File

@@ -0,0 +1,9 @@
// Copyright 2015-present 650 Industries. All rights reserved.
package expo.modules.webview
import java.lang.ref.WeakReference
internal data class WeakDomWebViewRef(
val ref: WeakReference<DomWebView>
)

5
node_modules/@expo/dom-webview/build/DomWebView.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import * as React from 'react';
import type { DomWebViewProps, DomWebViewRef } from './DomWebView.types';
declare const WebView: React.ForwardRefExoticComponent<DomWebViewProps & React.RefAttributes<DomWebViewRef>>;
export default WebView;
//# sourceMappingURL=DomWebView.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DomWebView.d.ts","sourceRoot":"","sources":["../src/DomWebView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AASzE,QAAA,MAAM,OAAO,uFAwBZ,CAAC;AAEF,eAAe,OAAO,CAAC"}

View File

@@ -0,0 +1,157 @@
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';
export interface DomWebViewProps extends ViewProps, AndroidProps, IosScrollViewProps, UnsupportedWebViewProps {
/**
* Loads static html or a uri (with optional headers) in the WebView.
*/
source: DomWebViewSource;
/**
* Stylesheet object to set the style of the container view.
*/
containerStyle?: StyleProp<ViewStyle>;
/**
* Set this to provide JavaScript that will be injected into the web page
* once the webview is initialized but before the view loads any content.
*/
injectedJavaScriptBeforeContentLoaded?: string;
/**
* Enables WebView remote debugging using Chrome (Android) or Safari (iOS).
*/
webviewDebuggingEnabled?: boolean;
/**
* Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`.
* Setting this property will inject this global into your webview.
*
* `window.ReactNativeWebView.postMessage` accepts one argument, `data`, which will be
* available on the event object, `event.nativeEvent.data`. `data` must be a string.
*/
onMessage?: (event: {
nativeEvent: MessageEventData;
}) => void;
/**
* Boolean value that determines whether a horizontal scroll indicator is
* shown in the `WebView`. The default value is `true`.
*/
showsHorizontalScrollIndicator?: boolean;
/**
* Boolean value that determines whether a vertical scroll indicator is
* shown in the `WebView`. The default value is `true`.
*/
showsVerticalScrollIndicator?: boolean;
}
interface IosScrollViewProps {
/**
* Boolean value that determines whether the web view bounces
* when it reaches the edge of the content. The default value is `true`.
* @platform ios
*/
bounces?: boolean;
/**
* 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:
*
* - normal: 0.998
* - fast: 0.99 (the default for iOS web view)
* @platform ios
*/
decelerationRate?: 'normal' | 'fast' | number;
/**
* Boolean value that determines whether scrolling is enabled in the
* `WebView`. The default value is `true`.
* @platform ios
*/
scrollEnabled?: boolean;
/**
* If the value of this property is true, the scroll view stops on multiples
* of the scroll views bounds when the user scrolls.
* The default value is false.
* @platform ios
*/
pagingEnabled?: boolean;
/**
* 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
* is `false`. (iOS 13+)
* @platform ios
*/
automaticallyAdjustsScrollIndicatorInsets?: boolean;
/**
* 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}.
* @platform ios
*/
contentInset?: ContentInsetProp;
/**
* 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.
*/
contentInsetAdjustmentBehavior?: 'automatic' | 'scrollableAxes' | 'never' | 'always';
/**
* A Boolean value that determines whether scrolling is disabled in a particular direction.
* The default value is `true`.
* @platform ios
*/
directionalLockEnabled?: boolean;
}
interface AndroidProps {
/**
* Allows to scroll inside the webview when used inside a scrollview.
* Behaviour already existing on iOS.
*
* @platform android
* @default true
*/
nestedScrollEnabled?: boolean;
}
/**
* Unsupported RNC WebView props that to suppress TypeScript errors.
*/
interface UnsupportedWebViewProps {
originWhitelist?: string[];
allowFileAccess?: boolean;
allowFileAccessFromFileURLs?: boolean;
allowsAirPlayForMediaPlayback?: boolean;
allowsFullscreenVideo?: boolean;
automaticallyAdjustContentInsets?: boolean;
}
export type DomWebViewRef = {
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
* Syntax:
*
* scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
*/
scrollTo({ x, y, animated, }: {
x?: number | undefined;
y?: number | undefined;
animated?: boolean | undefined;
}): void;
/**
* Injects a JavaScript string into the `WebView` and executes it.
*/
injectJavaScript: (script: string) => void;
};
export interface DomWebViewSource {
/**
* The URI to load in the `WebView`. Can be a local or remote file.
*/
uri: string;
}
export interface ContentInsetProp {
top?: number;
left?: number;
bottom?: number;
right?: number;
}
interface BaseEventData {
url: string;
title: string;
}
interface MessageEventData extends BaseEventData {
data: string;
}
export {};
//# sourceMappingURL=DomWebView.types.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DomWebView.types.d.ts","sourceRoot":"","sources":["../src/DomWebView.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,WAAW,eACf,SAAQ,SAAS,EACf,YAAY,EACZ,kBAAkB,EAClB,uBAAuB;IACzB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAC;IAEzB;;OAEG;IACH,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEtC;;;OAGG;IACH,qCAAqC,CAAC,EAAE,MAAM,CAAC;IAE/C;;OAEG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,gBAAgB,CAAA;KAAE,KAAK,IAAI,CAAC;IAE/D;;;OAGG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAEzC;;;OAGG;IACH,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,UAAU,kBAAkB;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAE9C;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;OAKG;IACH,yCAAyC,CAAC,EAAE,OAAO,CAAC;IAEpD;;;;OAIG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAEhC;;;;OAIG;IACH,8BAA8B,CAAC,EAAE,WAAW,GAAG,gBAAgB,GAAG,OAAO,GAAG,QAAQ,CAAC;IAErF;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,UAAU,YAAY;IACpB;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,UAAU,uBAAuB;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC,6BAA6B,CAAC,EAAE,OAAO,CAAC;IACxC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gCAAgC,CAAC,EAAE,OAAO,CAAC;CAC5C;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;OAKG;IACH,QAAQ,CAAC,EACP,CAAC,EACD,CAAC,EACD,QAAQ,GACT,EAAE;QACD,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACvB,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACvB,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KAChC,GAAG,IAAI,CAAC;IAET;;OAEG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,aAAa;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd"}

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
import { DomWebViewProps } from './DomWebView.types';
declare const WebView: React.ForwardRefExoticComponent<DomWebViewProps & React.RefAttributes<object>>;
export default WebView;
//# sourceMappingURL=DomWebView.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DomWebView.web.d.ts","sourceRoot":"","sources":["../src/DomWebView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrD,QAAA,MAAM,OAAO,gFAeZ,CAAC;AAEF,eAAe,OAAO,CAAC"}

View File

@@ -0,0 +1,2 @@
export declare function evalJsForWebViewAsync(webViewId: number, source: string): void;
//# sourceMappingURL=DomWebViewModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DomWebViewModule.d.ts","sourceRoot":"","sources":["../src/DomWebViewModule.ts"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE7E"}

View File

@@ -0,0 +1,3 @@
declare const _default: any;
export default _default;
//# sourceMappingURL=ExpoDomWebViewModule.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoDomWebViewModule.d.ts","sourceRoot":"","sources":["../src/ExpoDomWebViewModule.ts"],"names":[],"mappings":";AAEA,wBAA2D"}

View File

@@ -0,0 +1,3 @@
declare const _default: {};
export default _default;
//# sourceMappingURL=ExpoDomWebViewModule.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoDomWebViewModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoDomWebViewModule.web.ts"],"names":[],"mappings":";AAAA,wBAAkB"}

5
node_modules/@expo/dom-webview/build/index.d.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import DomWebView from './DomWebView';
export { DomWebView as WebView };
export { DomWebView };
export type { DomWebViewProps, DomWebViewRef } from './DomWebView.types';
//# sourceMappingURL=index.d.ts.map

1
node_modules/@expo/dom-webview/build/index.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}

10
node_modules/@expo/dom-webview/build/styles.d.ts generated vendored Normal file
View File

@@ -0,0 +1,10 @@
export declare const webviewStyles: {
container: {
flex: number;
overflow: "hidden";
};
webView: {
backgroundColor: string;
};
};
//# sourceMappingURL=styles.d.ts.map

1
node_modules/@expo/dom-webview/build/styles.d.ts.map generated vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa;;;;;;;;CAQxB,CAAC"}

15
node_modules/@expo/dom-webview/expo-module.config.json generated vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"platforms": ["apple", "android"],
"apple": {
"modules": ["DomWebViewModule"]
},
"android": {
"modules": ["expo.modules.webview.DomWebViewModule"],
"publication": {
"groupId": "expo.modules.webview",
"artifactId": "expo.modules.webview",
"version": "55.0.3",
"repository": "local-maven-repo"
}
}
}

225
node_modules/@expo/dom-webview/ios/DomWebView.swift generated vendored Normal file
View File

@@ -0,0 +1,225 @@
// Copyright 2015-present 650 Industries. All rights reserved.
import ExpoModulesCore
import WebKit
internal final class DomWebView: ExpoView, UIScrollViewDelegate, WKUIDelegate, WKScriptMessageHandler {
// swiftlint:disable implicitly_unwrapped_optional
private(set) var webView: WKWebView!
private(set) var id: WebViewId!
// swiftlint:enable implicitly_unwrapped_optional
private var source: DomWebViewSource?
private var injectedJSBeforeContentLoaded: WKUserScript?
var webviewDebuggingEnabled = false
var decelerationRate: UIScrollView.DecelerationRate = .normal
internal typealias SyncCompletionHandler = (String?) -> Void
private var needsResetupScripts = false
private static let EVAL_PROMPT_HEADER = "__EXPO_DOM_WEBVIEW_JS_EVAL__"
private static let POST_MESSAGE_HANDLER_NAME = "ReactNativeWebView"
private let onMessage = EventDispatcher()
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
super.backgroundColor = .clear
self.id = DomWebViewRegistry.shared.add(webView: self)
webView = createWebView()
resetupScripts()
addSubview(webView)
}
override func layoutSubviews() {
super.layoutSubviews()
webView.frame = bounds
}
override var backgroundColor: UIColor? {
get { webView.backgroundColor }
set {
let isOpaque = (newValue ?? UIColor.clear).cgColor.alpha == 1.0
self.isOpaque = isOpaque
webView.isOpaque = isOpaque
webView.scrollView.backgroundColor = newValue
webView.backgroundColor = newValue
}
}
override func removeFromSuperview() {
webView.removeFromSuperview()
webView = nil
DomWebViewRegistry.shared.remove(webViewId: self.id)
super.removeFromSuperview()
}
// MARK: - Public methods
func reload() {
if #available(iOS 16.4, *) {
webView.isInspectable = webviewDebuggingEnabled
}
if needsResetupScripts {
resetupScripts()
needsResetupScripts = false
}
if let source,
let request = RCTConvert.nsurlRequest(source.toDictionary(appContext: appContext)),
webView.url?.absoluteURL != request.url {
webView.load(request)
}
}
func scrollTo(offset: CGPoint, animated: Bool) {
webView.scrollView.setContentOffset(offset, animated: animated)
}
func injectJavaScript(_ script: String) {
DispatchQueue.main.async { [weak self] in
self?.webView.evaluateJavaScript(script)
}
}
func setSource(_ source: DomWebViewSource) {
self.source = source
}
func setInjectedJSBeforeContentLoaded(_ script: String?) {
if let script, !script.isEmpty {
injectedJSBeforeContentLoaded = WKUserScript(source: script, injectionTime: .atDocumentStart, forMainFrameOnly: false)
} else {
injectedJSBeforeContentLoaded = nil
}
needsResetupScripts = true
}
// MARK: - UIScrollViewDelegate implementations
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
scrollView.decelerationRate = decelerationRate
}
// MARK: - WKUIDelegate implementations
func webView(
_ webView: WKWebView,
runJavaScriptTextInputPanelWithPrompt prompt: String,
defaultText: String?,
initiatedByFrame frame: WKFrameInfo,
completionHandler: @escaping SyncCompletionHandler
) {
if !prompt.hasPrefix(Self.EVAL_PROMPT_HEADER) {
completionHandler(nil)
return
}
let script = String(prompt.dropFirst(Self.EVAL_PROMPT_HEADER.count))
if let data = script.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
let deferredId = json["deferredId"] as? Int,
let source = json["source"] as? String {
nativeJsiEvalSync(deferredId: deferredId, source: source, completionHandler: completionHandler)
} else {
completionHandler("Invalid parameters for nativeJsiEvalSync")
}
}
// MARK: - WKScriptMessageHandler implementations
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == Self.POST_MESSAGE_HANDLER_NAME {
var payload = createBaseEventPayload()
payload["data"] = message.body
onMessage(payload)
return
}
}
// MARK: - Internals
private func createWebView() -> WKWebView {
let config = WKWebViewConfiguration()
config.userContentController = WKUserContentController()
let webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
webView.backgroundColor = .clear
webView.scrollView.delegate = self
return webView
}
private func createBaseEventPayload() -> [String: Any] {
return [
"url": webView.url?.absoluteString ?? "",
"title": webView.title ?? ""
]
}
private func resetupScripts() {
let userContentController = webView.configuration.userContentController
userContentController.removeAllUserScripts()
userContentController.removeAllScriptMessageHandlers()
userContentController.add(self, name: Self.POST_MESSAGE_HANDLER_NAME)
if let injectedJSBeforeContentLoaded {
userContentController.addUserScript(injectedJSBeforeContentLoaded)
}
let addDomWebViewBridgeScript = """
window.ExpoDomWebViewBridge = {
eval: function eval(params) {
return window.prompt('\(Self.EVAL_PROMPT_HEADER)' + params);
},
};
true;
"""
userContentController.addUserScript(WKUserScript(source: addDomWebViewBridgeScript, injectionTime: .atDocumentStart, forMainFrameOnly: false))
let addRNWObjectScript = """
window.ReactNativeWebView ||= {};
window.ReactNativeWebView.postMessage = function postMessage(data) {
window.webkit.messageHandlers.\(Self.POST_MESSAGE_HANDLER_NAME).postMessage(String(data));
};
true;
"""
userContentController.addUserScript(WKUserScript(source: addRNWObjectScript, injectionTime: .atDocumentStart, forMainFrameOnly: false))
guard let webViewId = self.id else {
return
}
let addExpoDomWebViewObjectScript = "\(INSTALL_GLOBALS_SCRIPT);true;"
.replacingOccurrences(of: "\"%%WEBVIEW_ID%%\"", with: String(webViewId))
userContentController.addUserScript(WKUserScript(source: addExpoDomWebViewObjectScript, injectionTime: .atDocumentStart, forMainFrameOnly: false))
}
private func nativeJsiEvalSync(deferredId: Int, source: String, completionHandler: @escaping SyncCompletionHandler) {
guard let appContext else {
completionHandler("Missing AppContext")
return
}
guard let webViewId = self.id else {
completionHandler("Missing webViewId")
return
}
guard let runtime = try? appContext.runtime else {
completionHandler("Missing JS Runtime")
return
}
try? appContext.runtime.schedule {
let wrappedSource = NATIVE_EVAL_WRAPPER_SCRIPT
.replacingOccurrences(of: "\"%%DEFERRED_ID%%\"", with: String(deferredId))
.replacingOccurrences(of: "\"%%WEBVIEW_ID%%\"", with: String(webViewId))
.replacingOccurrences(of: "\"%%SOURCE%%\"", with: source)
do {
let result = try runtime.eval(wrappedSource)
completionHandler(result.getString())
} catch {
completionHandler("\(error)")
}
}
}
}

View File

@@ -0,0 +1,266 @@
// Copyright 2015-present 650 Industries. All rights reserved.
// swiftlint:disable line_length
/**
* This file contains the browser scripts that are injected into the WebView.
* @generated by buildBrowserScripts.ts
*/
internal let INSTALL_GLOBALS_SCRIPT: String = """
// browserScripts/InstallGlobals/Deferred.ts
class Deferred {
promise;
resolveCallback;
rejectCallback;
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolveCallback = resolve;
this.rejectCallback = reject;
});
}
resolve(value) {
this.resolveCallback(value);
}
reject(reason) {
this.rejectCallback(reason);
}
getPromise() {
return this.promise;
}
}
// browserScripts/InstallGlobals/EventEmitterProxy.ts
class EventEmitterProxy {
moduleName;
listeners;
constructor(moduleName) {
this.moduleName = moduleName;
}
addListener = (eventName, listener) => {
if (!this.listeners) {
this.listeners = new Map;
}
if (!this.listeners.has(eventName)) {
this.listeners.set(eventName, new Set);
}
this.listeners.get(eventName)?.add(listener);
const nativeListenerId = window.ExpoDomWebView.nextEventListenerId++;
listener.$$nativeListenerId = nativeListenerId;
const source = `
globalThis.expo.$$DomWebViewEventListenerMap ||= {};
globalThis.expo.$$DomWebViewEventListenerMap['${eventName}'] ||= new Map();
const listener = (...args) => {
const serializeArgs = args.map((arg) => JSON.stringify(arg)).join(',');
const script = 'window.ExpoDomWebView.eventEmitterProxy.${this.moduleName}.emit("${eventName}", ' + serializeArgs + ')';
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
};
globalThis.expo.$$DomWebViewEventListenerMap['${eventName}'].set(${nativeListenerId}, listener);
globalThis.expo.modules.${this.moduleName}.addListener('${eventName}', listener);
`;
window.ExpoDomWebView.eval(source);
return {
remove: () => {
this.removeListener(eventName, listener);
}
};
};
removeListener = (eventName, listener) => {
const nativeListenerId = listener.$$nativeListenerId;
if (nativeListenerId != null) {
const source = `(function() {
const nativeListener = globalThis.expo.$$DomWebViewEventListenerMap['${eventName}'].get(${nativeListenerId});
if (nativeListener != null) {
globalThis.expo.modules.${this.moduleName}.removeListener('${eventName}', nativeListener);
globalThis.expo.$$DomWebViewEventListenerMap['${eventName}'].delete(${nativeListenerId});
}
})();
true;
`;
window.ExpoDomWebView.eval(source);
}
this.listeners?.get(eventName)?.delete(listener);
};
removeAllListeners = (eventName) => {
const source = `
globalThis.expo.$$DomWebViewEventListenerMap['${eventName}'].clear();
globalThis.expo.modules.${this.moduleName}.removeAllListeners('${eventName}');
`;
window.ExpoDomWebView.eval(source);
this.listeners?.get(eventName)?.clear();
};
emit = (eventName, ...args) => {
const listeners = new Set(this.listeners?.get(eventName));
listeners.forEach((listener) => {
try {
listener(...args);
} catch (error) {
console.error(error);
}
});
};
}
// browserScripts/InstallGlobals/utils.ts
function serializeArgs(args) {
return args.map((arg) => {
if (typeof arg === "object" && arg.sharedObjectId != null) {
return `globalThis.expo.sharedObjectRegistry.get(${arg.sharedObjectId})`;
}
return JSON.stringify(arg);
}).join(",");
}
// browserScripts/InstallGlobals/proxies.ts
function createSharedObjectProxy(sharedObjectId) {
return new Proxy({}, {
get: (target, prop) => {
const name = String(prop);
if (name === "sharedObjectId") {
return sharedObjectId;
}
return function(...args) {
const serializedArgs = serializeArgs(args);
const source = `globalThis.expo.sharedObjectRegistry.get(${sharedObjectId})?.${name}?.call(globalThis.expo.sharedObjectRegistry.get(${sharedObjectId}),${serializedArgs})`;
return window.ExpoDomWebView.eval(source);
};
}
});
}
function createConstructorProxy(moduleName, property, propertyName) {
return new Proxy(function() {
}, {
construct(target, args) {
const serializedArgs = serializeArgs(args);
const sharedObjectId = window.ExpoDomWebView.nextSharedObjectId++;
const sharedObjectProxy = createSharedObjectProxy(sharedObjectId);
window.ExpoDomWebView.sharedObjectFinalizationRegistry.register(sharedObjectProxy, sharedObjectId);
const source = `globalThis.expo.sharedObjectRegistry ||= new Map(); globalThis.expo.sharedObjectRegistry.set(${sharedObjectId}, new ${property}(${serializedArgs}));`;
window.ExpoDomWebView.eval(source);
return sharedObjectProxy;
}
});
}
function createPropertyProxy(propertyTypeCache, moduleName, propertyName) {
const property = `globalThis.expo.modules.${moduleName}.${propertyName}`;
let propertyType = propertyTypeCache[propertyName];
if (!propertyType) {
const typeCheck = `${property}?.prototype?.__expo_shared_object_id__ != null ? 'sharedObject' : typeof ${property}`;
propertyType = window.ExpoDomWebView.eval(typeCheck);
propertyTypeCache[propertyName] = propertyType;
}
if (propertyType === "sharedObject") {
return createConstructorProxy(moduleName, property, propertyName);
}
if (propertyType === "function") {
return function(...args) {
const serializedArgs = serializeArgs(args);
const source = `${property}(${serializedArgs})`;
return window.ExpoDomWebView.eval(source);
};
}
return window.ExpoDomWebView.eval(property);
}
function createExpoModuleProxy(moduleName) {
const propertyTypeCache = {};
return new Proxy({}, {
get: (target, prop) => {
const name = String(prop);
if (["addListener", "removeListener", "removeAllListeners"].includes(name)) {
return window.ExpoDomWebView.eventEmitterProxy[moduleName][name];
}
return createPropertyProxy(propertyTypeCache, moduleName, name);
}
});
}
// browserScripts/InstallGlobals/ExpoDomWebView.ts
class ExpoDomWebView {
nextDeferredId;
nextSharedObjectId;
nextEventListenerId;
deferredMap;
sharedObjectFinalizationRegistry;
expoModulesProxy;
eventEmitterProxy;
constructor() {
this.nextDeferredId = 0;
this.nextSharedObjectId = 0;
this.nextEventListenerId = 0;
this.deferredMap = new Map;
this.sharedObjectFinalizationRegistry = new FinalizationRegistry((sharedObjectId) => {
this.eval(`globalThis.expo.sharedObjectRegistry.delete(${sharedObjectId})`);
});
const expoModules = {};
const eventEmitterProxy = {};
this.eval("Object.keys(globalThis.expo.modules)").forEach((name) => {
expoModules[name] = createExpoModuleProxy(name);
eventEmitterProxy[name] = new EventEmitterProxy(name);
});
this.expoModulesProxy = expoModules;
this.eventEmitterProxy = eventEmitterProxy;
}
eval(source) {
const { deferredId, deferred } = this.createDeferred();
const args = JSON.stringify({ source, deferredId });
const result = JSON.parse(window.ExpoDomWebViewBridge.eval(args));
if (result.isPromise) {
return deferred.getPromise();
}
this.removeDeferred(deferredId);
return result.value;
}
createDeferred() {
const deferred = new Deferred;
const deferredId = this.nextDeferredId;
this.deferredMap.set(deferredId, deferred);
this.nextDeferredId += 1;
return { deferredId, deferred };
}
resolveDeferred(deferredId, value) {
const deferred = this.deferredMap.get(deferredId);
if (deferred) {
deferred.resolve(value);
this.deferredMap.delete(deferredId);
}
}
rejectDeferred(deferredId, reason) {
const deferred = this.deferredMap.get(deferredId);
if (deferred) {
deferred.reject(reason);
this.deferredMap.delete(deferredId);
}
}
removeDeferred(deferredId) {
this.deferredMap.delete(deferredId);
}
}
// browserScripts/InstallGlobals/index.ts
window.ExpoDomWebView = new ExpoDomWebView;
"""
internal let NATIVE_EVAL_WRAPPER_SCRIPT: String = """
// browserScripts/NativeEvalWrapper/index.ts
(function() {
const result = "%%SOURCE%%";
if (result instanceof Promise) {
result.then((resolved) => {
const resolvedString = JSON.stringify(resolved);
const script = 'window.ExpoDomWebView.resolveDeferred("%%DEFERRED_ID%%", ' + resolvedString + ")";
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
}).catch((error) => {
const errorString = JSON.stringify(error);
const script = 'window.ExpoDomWebView.rejectDeferred("%%DEFERRED_ID%%", ' + errorString + ")";
globalThis.expo.modules.ExpoDomWebViewModule.evalJsForWebViewAsync("%%WEBVIEW_ID%%", script);
});
return JSON.stringify({ isPromise: true, value: null });
} else {
return JSON.stringify({ isPromise: false, value: result });
}
})();
"""
// swiftlint:enable line_length

View File

@@ -0,0 +1,23 @@
// Copyright 2015-present 650 Industries. All rights reserved.
import ExpoModulesCore
internal enum ContentInsetAdjustmentBehavior: String, Enumerable {
case automatic
case scrollableAxes
case never
case always
func toContentInsetAdjustmentBehavior() -> UIScrollView.ContentInsetAdjustmentBehavior {
switch self {
case .automatic:
return .automatic
case .scrollableAxes:
return .scrollableAxes
case .never:
return .never
case .always:
return .always
}
}
}

View File

@@ -0,0 +1,105 @@
// Copyright 2015-present 650 Industries. All rights reserved.
import ExpoModulesCore
public final class DomWebViewModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoDomWebViewModule")
OnDestroy {
DomWebViewRegistry.shared.reset()
}
AsyncFunction("evalJsForWebViewAsync") { (webViewId: Int, source: String) in
if let webView = DomWebViewRegistry.shared.get(webViewId: webViewId) {
webView.injectJavaScript(source)
}
}
// swiftlint:disable closure_body_length
View(DomWebView.self) {
Events("onMessage")
Prop("source") { (view: DomWebView, source: DomWebViewSource) in
view.setSource(source)
}
Prop("injectedJavaScriptBeforeContentLoaded") { (view: DomWebView, script: String) in
view.setInjectedJSBeforeContentLoaded(script)
}
Prop("webviewDebuggingEnabled") { (view: DomWebView, enabled: Bool) in
view.webviewDebuggingEnabled = enabled
}
// MARK: - IosScrollViewProps
Prop("bounces") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.bounces = enabled
}
Prop("decelerationRate") { (view: DomWebView, decelerationRate: Either<String, Double>) in
var newDecelerationRate: UIScrollView.DecelerationRate?
if let rateString: String = decelerationRate.get() {
if rateString == "normal" {
newDecelerationRate = .normal
} else if rateString == "fast" {
newDecelerationRate = .fast
}
} else if let rate: Double = decelerationRate.get() {
newDecelerationRate = UIScrollView.DecelerationRate(rawValue: rate)
}
if let newDecelerationRate {
view.decelerationRate = newDecelerationRate
}
}
Prop("scrollEnabled") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.isScrollEnabled = enabled
}
Prop("pagingEnabled") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.isPagingEnabled = enabled
}
Prop("automaticallyAdjustsScrollIndicatorInsets") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.automaticallyAdjustsScrollIndicatorInsets = enabled
}
Prop("contentInset") { (view: DomWebView, inset: ContentInset) in
view.webView.scrollView.contentInset = inset.toEdgeInsets()
}
Prop("contentInsetAdjustmentBehavior") { (view: DomWebView, value: ContentInsetAdjustmentBehavior) in
view.webView.scrollView.contentInsetAdjustmentBehavior = value.toContentInsetAdjustmentBehavior()
}
Prop("directionalLockEnabled") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.isDirectionalLockEnabled = enabled
}
Prop("showsHorizontalScrollIndicator") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.showsHorizontalScrollIndicator = enabled
}
Prop("showsVerticalScrollIndicator") { (view: DomWebView, enabled: Bool) in
view.webView.scrollView.showsVerticalScrollIndicator = enabled
}
// MARK: - Imperative methods
AsyncFunction("scrollTo") { (view: DomWebView, param: ScrollToParam) in
view.scrollTo(offset: CGPoint(x: param.x, y: param.y), animated: param.animated)
}
AsyncFunction("injectJavaScript") { (view: DomWebView, script: String) in
view.injectJavaScript(script)
}
OnViewDidUpdateProps { view in
view.reload()
}
}
// swiftlint:enable closure_body_length
}
}

View File

@@ -0,0 +1,42 @@
// Copyright 2015-present 650 Industries. All rights reserved.
import ExpoModulesCore
internal struct DomWebViewSource: Record {
@Field
var uri: String?
}
internal struct ContentInset: Record {
@Field
var top: Double? = 0
@Field
var left: Double? = 0
@Field
var bottom: Double? = 0
@Field
var right: Double? = 0
func toEdgeInsets() -> UIEdgeInsets {
var inset = UIEdgeInsets.zero
inset.top = CGFloat(self.top ?? 0)
inset.left = CGFloat(self.left ?? 0)
inset.bottom = CGFloat(self.bottom ?? 0)
inset.right = CGFloat(self.right ?? 0)
return inset
}
}
internal struct ScrollToParam: Record {
@Field
var x: Double = 0
@Field
var y: Double = 0
@Field
var animated: Bool = true
}

View File

@@ -0,0 +1,41 @@
// Copyright 2015-present 650 Industries. All rights reserved.
private let lockQueue = DispatchQueue(label: "expo.modules.domWebView.RegistryQueue")
internal typealias WebViewId = Int
internal final class DomWebViewRegistry {
static var shared = DomWebViewRegistry()
private var registry: [WebViewId: WeakDomWebViewRef] = [:]
private var nextWebViewId: WebViewId = 0
func get(webViewId: WebViewId) -> DomWebView? {
return lockQueue.sync {
return self.registry[webViewId]?.ref
}
}
func add(webView: DomWebView) -> WebViewId {
return lockQueue.sync {
let webViewId = self.nextWebViewId
self.registry[webViewId] = WeakDomWebViewRef(ref: webView)
self.nextWebViewId += 1
return webViewId
}
}
@discardableResult
func remove(webViewId: WebViewId) -> DomWebView? {
return lockQueue.sync {
return self.registry.removeValue(forKey: webViewId)?.ref
}
}
func reset() {
lockQueue.sync {
self.registry.removeAll()
self.nextWebViewId = 0
}
}
}

View File

@@ -0,0 +1,28 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
Pod::Spec.new do |s|
s.name = 'ExpoDomWebView'
s.version = package['version']
s.summary = package['description']
s.description = package['description']
s.license = package['license']
s.author = package['author']
s.homepage = package['homepage']
s.platforms = {
:ios => '15.1',
}
s.swift_version = '5.9'
s.source = { git: 'https://github.com/expo/expo.git' }
s.static_framework = true
s.dependency 'ExpoModulesCore'
# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'SWIFT_COMPILATION_MODE' => 'wholemodule'
}
s.source_files = "**/*.{h,m,swift}"
end

View File

@@ -0,0 +1,5 @@
// Copyright 2015-present 650 Industries. All rights reserved.
internal struct WeakDomWebViewRef {
weak var ref: DomWebView?
}

View File

@@ -0,0 +1 @@
f68f24a6fd847e9cf4a12f59da0c13a5a0040b47

View File

@@ -0,0 +1 @@
e497b23f615357cb685fe5431cffb7b294d03edb6de7117098b193857f5b5b17

View File

@@ -0,0 +1 @@
781fcbc55339a4121d78a2b5ce04888192ba46eef4c86ed8b177766b996d1aeaee0c7da50724d6a0d6b00255ed23f3970fcc0b00404269966e56c6136a547164

View File

@@ -0,0 +1 @@
46b203056d35a43f910bf9714b99ffdb

View File

@@ -0,0 +1 @@
19f2172aab7ebf8d488399949832fe02c1c75c4b

View File

@@ -0,0 +1 @@
cf72fee6fb2bfd3774aa5c47ada8d72a090b5becb21d69357cc9206ff80f141d

View File

@@ -0,0 +1 @@
77e16ee4fe3be9ebdb7d99e881b63a5b35c052fc28fdc6dfc5daf342bf41a6d05f147e5e9a38059acd428bd8f78623b1208a4a14eb25edf87544f7781de14442

View File

@@ -0,0 +1,87 @@
{
"formatVersion": "1.1",
"component": {
"group": "expo.modules.webview",
"module": "expo.modules.webview",
"version": "55.0.3",
"attributes": {
"org.gradle.status": "release"
}
},
"createdBy": {
"gradle": {
"version": "9.0.0"
}
},
"variants": [
{
"name": "releaseVariantReleaseApiPublication",
"attributes": {
"org.gradle.category": "library",
"org.gradle.dependency.bundling": "external",
"org.gradle.libraryelements": "aar",
"org.gradle.usage": "java-api"
},
"files": [
{
"name": "expo.modules.webview-55.0.3.aar",
"url": "expo.modules.webview-55.0.3.aar",
"size": 52120,
"sha512": "77e16ee4fe3be9ebdb7d99e881b63a5b35c052fc28fdc6dfc5daf342bf41a6d05f147e5e9a38059acd428bd8f78623b1208a4a14eb25edf87544f7781de14442",
"sha256": "cf72fee6fb2bfd3774aa5c47ada8d72a090b5becb21d69357cc9206ff80f141d",
"sha1": "19f2172aab7ebf8d488399949832fe02c1c75c4b",
"md5": "46b203056d35a43f910bf9714b99ffdb"
}
]
},
{
"name": "releaseVariantReleaseRuntimePublication",
"attributes": {
"org.gradle.category": "library",
"org.gradle.dependency.bundling": "external",
"org.gradle.libraryelements": "aar",
"org.gradle.usage": "java-runtime"
},
"dependencies": [
{
"group": "org.jetbrains.kotlin",
"module": "kotlin-stdlib-jdk7",
"version": {
"requires": "2.1.20"
}
}
],
"files": [
{
"name": "expo.modules.webview-55.0.3.aar",
"url": "expo.modules.webview-55.0.3.aar",
"size": 52120,
"sha512": "77e16ee4fe3be9ebdb7d99e881b63a5b35c052fc28fdc6dfc5daf342bf41a6d05f147e5e9a38059acd428bd8f78623b1208a4a14eb25edf87544f7781de14442",
"sha256": "cf72fee6fb2bfd3774aa5c47ada8d72a090b5becb21d69357cc9206ff80f141d",
"sha1": "19f2172aab7ebf8d488399949832fe02c1c75c4b",
"md5": "46b203056d35a43f910bf9714b99ffdb"
}
]
},
{
"name": "releaseVariantReleaseSourcePublication",
"attributes": {
"org.gradle.category": "documentation",
"org.gradle.dependency.bundling": "external",
"org.gradle.docstype": "sources",
"org.gradle.usage": "java-runtime"
},
"files": [
{
"name": "expo.modules.webview-55.0.3-sources.jar",
"url": "expo.modules.webview-55.0.3-sources.jar",
"size": 8174,
"sha512": "781fcbc55339a4121d78a2b5ce04888192ba46eef4c86ed8b177766b996d1aeaee0c7da50724d6a0d6b00255ed23f3970fcc0b00404269966e56c6136a547164",
"sha256": "e497b23f615357cb685fe5431cffb7b294d03edb6de7117098b193857f5b5b17",
"sha1": "f68f24a6fd847e9cf4a12f59da0c13a5a0040b47",
"md5": "0c82442d9916427fd08e758a557f26f2"
}
]
}
]
}

View File

@@ -0,0 +1 @@
14094ba2b24e0f9a68fe9f2d0ec992fe

View File

@@ -0,0 +1 @@
a71ecd2281b2ee071a636c66911f906111cbf98a

View File

@@ -0,0 +1 @@
b69617129bab83de60977dfaa32024fec030b2a6265855627a25d520a5da1091

View File

@@ -0,0 +1 @@
573e1d5c7b7a4eda9b054975b064c6f01b312981d3df133bd6e3c948511883b42e08524e9bd518fbc99ee8a3a24202a1732008afe6921c7b229fd81a5eaa8663

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!-- This module was also published with a richer model, Gradle metadata, -->
<!-- which should be used instead. Do not delete the following line which -->
<!-- is to indicate to Gradle or any Gradle module metadata file consumer -->
<!-- that they should prefer consuming it instead. -->
<!-- do_not_remove: published-with-gradle-metadata -->
<modelVersion>4.0.0</modelVersion>
<groupId>expo.modules.webview</groupId>
<artifactId>expo.modules.webview</artifactId>
<version>55.0.3</version>
<packaging>aar</packaging>
<name>expo.modules.webview</name>
<url>https://github.com/expo/expo</url>
<licenses>
<license>
<name>MIT License</name>
<url>https://github.com/expo/expo/blob/main/LICENSE</url>
</license>
</licenses>
<scm>
<connection>https://github.com/expo/expo.git</connection>
<developerConnection>https://github.com/expo/expo.git</developerConnection>
<url>https://github.com/expo/expo</url>
</scm>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk7</artifactId>
<version>2.1.20</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1 @@
e5ee708cb5e96ec9dcab792479203163

View File

@@ -0,0 +1 @@
a872d025ce5e283acbb0237a63695ee7c8f5977f

View File

@@ -0,0 +1 @@
46dc549fa9b615755fdb0c78f0eb45884cc518b1ed2e8c41855770b28c58370f

View File

@@ -0,0 +1 @@
6387d912c9e419da4bfe586d4bcf4d423ccae635d3ae3962eb74d443f4e12c3fe9adffd3211a45f8b02be328dace492795414a36d416b9a55d50fe05e73d6c11

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>expo.modules.webview</groupId>
<artifactId>expo.modules.webview</artifactId>
<versioning>
<latest>55.0.3</latest>
<release>55.0.3</release>
<versions>
<version>55.0.3</version>
</versions>
<lastUpdated>20260208025457</lastUpdated>
</versioning>
</metadata>

View File

@@ -0,0 +1 @@
9f352385c7764a528b49a5dfcd5b2f8b

View File

@@ -0,0 +1 @@
b2ff732c53b443c39b46db70a5b24299868ad5e5

View File

@@ -0,0 +1 @@
ed71ff006b1f073633c2b4df7bcd07541451d3ec586a9eb1f3340078c7acd686

View File

@@ -0,0 +1 @@
40d55db34198d68071b4319c7b7ffa5f1c168e82f18e8743fa182238559435bf867315348cf40afa7303964f023efc1972344893a126c8341d6efeeaa1e60826

48
node_modules/@expo/dom-webview/package.json generated vendored Normal file
View File

@@ -0,0 +1,48 @@
{
"name": "@expo/dom-webview",
"version": "55.0.3",
"description": "A WebView specifically designed for Expo DOM components",
"main": "src/index.ts",
"types": "build/index.d.ts",
"sideEffects": false,
"scripts": {
"build": "expo-module build",
"clean": "expo-module clean",
"lint": "expo-module lint",
"test": "expo-module test",
"prepare": "expo-module prepare",
"prepublishOnly": "expo-module prepublishOnly",
"expo-module": "expo-module",
"syncBrowserScripts": "./scripts/buildBrowserScripts.ts"
},
"keywords": [
"react-native",
"expo",
"dom",
"webview"
],
"repository": {
"type": "git",
"url": "https://github.com/expo/expo.git",
"directory": "packages/@expo/dom-webview"
},
"bugs": {
"url": "https://github.com/expo/expo/issues"
},
"author": "650 Industries, Inc.",
"license": "MIT",
"homepage": "https://github.com/expo/expo/tree/main/packages/@expo/dom-webview",
"jest": {
"preset": "expo-module-scripts"
},
"dependencies": {},
"devDependencies": {
"expo-module-scripts": "^55.0.2"
},
"peerDependencies": {
"expo": "*",
"react": "*",
"react-native": "*"
},
"gitHead": "cd3638bb85f9560392acfd5160a266cf97880b3b"
}

40
node_modules/@expo/dom-webview/src/DomWebView.tsx generated vendored Normal file
View File

@@ -0,0 +1,40 @@
import { requireNativeViewManager } from 'expo-modules-core';
import * as React from 'react';
import { Image, View } from 'react-native';
import type { DomWebViewProps, DomWebViewRef } from './DomWebView.types';
import { webviewStyles } from './styles';
const { resolveAssetSource } = Image;
const NativeWebView: React.ComponentType<
React.PropsWithoutRef<DomWebViewProps> & React.RefAttributes<DomWebViewRef>
> = requireNativeViewManager('ExpoDomWebViewModule');
const WebView = React.forwardRef<DomWebViewRef, DomWebViewProps>(
({ containerStyle, style, ...props }, ref) => {
const viewRef = React.useRef<DomWebViewRef>(null);
React.useImperativeHandle(
ref,
() => ({
scrollTo: (params) => viewRef.current?.scrollTo(params),
injectJavaScript: (script: string) => viewRef.current?.injectJavaScript(script),
}),
[]
);
const webViewStyles = [webviewStyles.container, webviewStyles.webView, style];
const webViewContainerStyle = [webviewStyles.container, containerStyle];
const resolvedSource = resolveAssetSource(props.source);
return (
<View style={webViewContainerStyle}>
<NativeWebView {...props} ref={viewRef} source={resolvedSource} style={webViewStyles} />
</View>
);
}
);
export default WebView;

184
node_modules/@expo/dom-webview/src/DomWebView.types.ts generated vendored Normal file
View File

@@ -0,0 +1,184 @@
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';
export interface DomWebViewProps
extends ViewProps,
AndroidProps,
IosScrollViewProps,
UnsupportedWebViewProps {
/**
* Loads static html or a uri (with optional headers) in the WebView.
*/
source: DomWebViewSource;
/**
* Stylesheet object to set the style of the container view.
*/
containerStyle?: StyleProp<ViewStyle>;
/**
* Set this to provide JavaScript that will be injected into the web page
* once the webview is initialized but before the view loads any content.
*/
injectedJavaScriptBeforeContentLoaded?: string;
/**
* Enables WebView remote debugging using Chrome (Android) or Safari (iOS).
*/
webviewDebuggingEnabled?: boolean;
/**
* Function that is invoked when the webview calls `window.ReactNativeWebView.postMessage`.
* Setting this property will inject this global into your webview.
*
* `window.ReactNativeWebView.postMessage` accepts one argument, `data`, which will be
* available on the event object, `event.nativeEvent.data`. `data` must be a string.
*/
onMessage?: (event: { nativeEvent: MessageEventData }) => void;
/**
* Boolean value that determines whether a horizontal scroll indicator is
* shown in the `WebView`. The default value is `true`.
*/
showsHorizontalScrollIndicator?: boolean;
/**
* Boolean value that determines whether a vertical scroll indicator is
* shown in the `WebView`. The default value is `true`.
*/
showsVerticalScrollIndicator?: boolean;
}
interface IosScrollViewProps {
/**
* Boolean value that determines whether the web view bounces
* when it reaches the edge of the content. The default value is `true`.
* @platform ios
*/
bounces?: boolean;
/**
* 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:
*
* - normal: 0.998
* - fast: 0.99 (the default for iOS web view)
* @platform ios
*/
decelerationRate?: 'normal' | 'fast' | number;
/**
* Boolean value that determines whether scrolling is enabled in the
* `WebView`. The default value is `true`.
* @platform ios
*/
scrollEnabled?: boolean;
/**
* If the value of this property is true, the scroll view stops on multiples
* of the scroll views bounds when the user scrolls.
* The default value is false.
* @platform ios
*/
pagingEnabled?: boolean;
/**
* 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
* is `false`. (iOS 13+)
* @platform ios
*/
automaticallyAdjustsScrollIndicatorInsets?: boolean;
/**
* 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}.
* @platform ios
*/
contentInset?: ContentInsetProp;
/**
* 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.
*/
contentInsetAdjustmentBehavior?: 'automatic' | 'scrollableAxes' | 'never' | 'always';
/**
* A Boolean value that determines whether scrolling is disabled in a particular direction.
* The default value is `true`.
* @platform ios
*/
directionalLockEnabled?: boolean;
}
interface AndroidProps {
/**
* Allows to scroll inside the webview when used inside a scrollview.
* Behaviour already existing on iOS.
*
* @platform android
* @default true
*/
nestedScrollEnabled?: boolean;
}
/**
* Unsupported RNC WebView props that to suppress TypeScript errors.
*/
interface UnsupportedWebViewProps {
originWhitelist?: string[];
allowFileAccess?: boolean;
allowFileAccessFromFileURLs?: boolean;
allowsAirPlayForMediaPlayback?: boolean;
allowsFullscreenVideo?: boolean;
automaticallyAdjustContentInsets?: boolean;
}
export type DomWebViewRef = {
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
* Syntax:
*
* scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})
*/
scrollTo({
x,
y,
animated,
}: {
x?: number | undefined;
y?: number | undefined;
animated?: boolean | undefined;
}): void;
/**
* Injects a JavaScript string into the `WebView` and executes it.
*/
injectJavaScript: (script: string) => void;
};
export interface DomWebViewSource {
/**
* The URI to load in the `WebView`. Can be a local or remote file.
*/
uri: string;
}
export interface ContentInsetProp {
top?: number;
left?: number;
bottom?: number;
right?: number;
}
interface BaseEventData {
url: string;
title: string;
}
interface MessageEventData extends BaseEventData {
data: string;
}

24
node_modules/@expo/dom-webview/src/DomWebView.web.tsx generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import * as React from 'react';
import { View } from 'react-native';
import { DomWebViewProps } from './DomWebView.types';
import { webviewStyles } from './styles';
const WebView = React.forwardRef<object, DomWebViewProps>(
({ containerStyle, style, ...props }, ref) => {
const viewRef = React.useRef(null);
const webViewStyles = [webviewStyles.container, webviewStyles.webView, style];
const webViewContainerStyle = [webviewStyles.container, containerStyle];
return (
<View style={webViewContainerStyle}>
<View {...props} ref={viewRef} style={webViewStyles}>
<iframe src={props.source.uri} />
</View>
</View>
);
}
);
export default WebView;

View File

@@ -0,0 +1,5 @@
import ExpoDomWebViewModule from './ExpoDomWebViewModule';
export function evalJsForWebViewAsync(webViewId: number, source: string): void {
ExpoDomWebViewModule.evalJsForWebViewAsync(webViewId, source);
}

View File

@@ -0,0 +1,3 @@
import { requireNativeModule } from 'expo-modules-core';
export default requireNativeModule('ExpoDomWebViewModule');

View File

@@ -0,0 +1 @@
export default {};

5
node_modules/@expo/dom-webview/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import DomWebView from './DomWebView';
export { DomWebView as WebView };
export { DomWebView };
export type { DomWebViewProps, DomWebViewRef } from './DomWebView.types';

11
node_modules/@expo/dom-webview/src/styles.ts generated vendored Normal file
View File

@@ -0,0 +1,11 @@
import { StyleSheet } from 'react-native';
export const webviewStyles = StyleSheet.create({
container: {
flex: 1,
overflow: 'hidden',
},
webView: {
backgroundColor: '#ffffff',
},
});

9
node_modules/@expo/dom-webview/tsconfig.json generated vendored Normal file
View File

@@ -0,0 +1,9 @@
{
"extends": "expo-module-scripts/tsconfig.base",
"compilerOptions": {
"outDir": "./build",
"emitDeclarationOnly": true
},
"include": ["./src"],
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
}