You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+52-4Lines changed: 52 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,24 @@ React Native WebView that auto-sizes to match its HTML content—whether you loa
12
12
> [!TIP]
13
13
> 💡 Works out-of-the-box with dynamic CMS pages, FAQs, marketing landers, local HTML snippets, or full external sites.
14
14
15
+
## 🚨 Upgrading to 1.1.0
16
+
17
+
Three defaults changed in the 1.1.x line. Each is a one-line migration:
18
+
19
+
-**Named import only.** The default export was removed to keep tree-shaking predictable across bundlers.
20
+
```diff
21
+
- import SizedWebView from 'react-native-sized-webview';
22
+
+ import { SizedWebView } from 'react-native-sized-webview';
23
+
```
24
+
-**`originWhitelist` now defaults to `['http://*', 'https://*']`.** Standard HTTP(S) navigation keeps working; non-web schemes (`file:`, `javascript:`, `data:`, `intent:`) are blocked by default. Tighten it for production if you only load a specific origin:
-**`javaScriptEnabled` is now respected.** Passing `false` disables auto-sizing; the container falls back to `minHeight` (or `containerStyle.height`). This unblocks rendering static HTML on iOS 26 ([#3](https://github.com/mCodex/react-native-sized-webview/issues/3)).
32
+
15
33
## ✨ Highlights
16
34
17
35
- 📐 Wrapper-based measurement keeps the WebView content in a dedicated container, so height always reflects the real DOM footprint.
@@ -80,14 +98,25 @@ The example showcases:
80
98
81
99
| Prop | Type | Default | Description |
82
100
| --- | --- | --- | --- |
83
-
|`minHeight`|`number`|`0`| Minimum height (dp) applied to the container to avoid layout jumps before content loads. |
84
-
|`containerStyle`|`StyleProp<ViewStyle>`| — | Styles applied to the wrapping `View`. Use it for padding, borders, or shadows. |
85
-
|`onHeightChange`|`(height: number) => void`| — | Callback fired whenever a new height is committed. Great for analytics or debugging. |
86
-
|`...WebViewProps`| — | — | All remaining props are forwarded to the underlying `react-native-webview`. |
101
+
|`minHeight`|`number`|`0`| Minimum height (dp) applied to the container. When `0`, the container is unsized until the first measurement arrives (avoids layout flicker and the iOS 26 WKWebView 1px feedback loop). |
102
+
|`containerStyle`|`StyleProp<ViewStyle>`| — | Styles applied to the wrapping `View`. Use it for padding, borders, or shadows. Do not set `height` — it is managed by the hook. |
103
+
|`onHeightChange`|`(height: number) => void`| — | Callback fired whenever a new height is committed. Great for analytics or debugging. Never fires for invalid or out-of-range values. |
104
+
|`originWhitelist`|`string[]`|`['http://*', 'https://*']`| Origins the WebView is allowed to navigate to. Blocks non-web schemes (`file:`, `javascript:`, `data:`, `intent:`) by default. Tighten it to a specific origin list for stricter environments. |
105
+
|`javaScriptEnabled`|`boolean`|`true`| When `false`, the auto-height bridge is **not** injected and the container falls back to `minHeight`. Use for static HTML that doesn't need JS. |
106
+
|`...WebViewProps`| — | — | All remaining props are forwarded to the underlying `react-native-webview`. User-supplied values always win over the defaults above. |
87
107
88
108
> [!NOTE]
89
109
> 🧩 `scrollEnabled` defaults to `false` so sizing remains deterministic. Only enable it if the WebView should manage its own scroll.
90
110
111
+
## 🛡️ Security
112
+
113
+
-**Namespaced message protocol.** The injected bridge posts values prefixed with `__RN_SIZED_WV__:` and the hook rejects everything else, so your own `onMessage` traffic cannot accidentally (or maliciously) mutate the container height.
114
+
-**Safe-by-default origin list.**`originWhitelist` defaults to `['http://*', 'https://*']` — HTTP(S) navigation works, but non-web schemes (`file:`, `javascript:`, `data:`, `intent:`) are blocked. Tighten to a specific origin for production apps that only load trusted content.
115
+
-**Respected JS toggle.**`javaScriptEnabled={false}` is honored; the bridge is not injected when you disable scripts.
116
+
-**Clamped heights.** A shared `MAX_COMMITTED_HEIGHT` (120 000 dp) caps both sides of the bridge to defend against runaway values from broken markup or third-party scripts.
117
+
-**No native code.** This package ships only JavaScript/TypeScript — there is no Objective-C, Swift, Java, or Kotlin to audit.
118
+
-**Warning.** Never interpolate untrusted strings into `injectedJavaScript` or `injectedJavaScriptBeforeContentLoaded`. Anything passed there runs inside the WebView page context and can reach React Native through `window.ReactNativeWebView`.
119
+
91
120
## 🧩 Edge Cases Covered
92
121
93
122
- Trailing `<br>` and empty `<p>` tags are stripped automatically so CMS exports don’t leave phantom padding.
@@ -114,6 +143,25 @@ The example showcases:
114
143
115
144
Benchmarks were captured on CMS articles up to 3k words in a 60 fps RN dev build. The bridge batches DOM mutations so even long documents resize without thrashing the JS thread.
116
145
146
+
### 🏎️ Built for speed
147
+
148
+
Every hot path is designed to run at its theoretical complexity floor — no allocations in steady state, no repeated DOM walks, and at most one forced layout per measurement frame.
| Height commit (rAF-batched) |**O(1)** amortized per frame | Sub-pixel diffs are dropped; at most one React render per animation frame. |
154
+
| DOM mutation callback |**O(added nodes)**| Scans only each mutation's `addedNodes`, not the whole tree. Media elements are deduped via a `WeakSet`. |
155
+
|`measureHeight`|**1 forced reflow / call**| Reads the wrapper element only — its box is authoritative because every `<body>` child lives inside it. |
156
+
| Trailing-node prune DFS | Runs only when the DOM is **dirty**| A mutation-driven dirty flag skips the recursive walk on resize / font / viewport ticks when nothing structural changed. |
157
+
158
+
The net effect: resize storms, font loads, and viewport changes cost a single `getBoundingClientRect()` per frame — nothing more. Paired with `sideEffects: false` and named-only exports, the library stays fast *and* small in the final bundle.
159
+
160
+
### 📦 Bundle & tree-shaking
161
+
162
+
- Ships as ESM-first (`lib/module/**`) with `"sideEffects": false`.
163
+
-**Named exports only** — no default export — so every bundler can drop what you don't use.
164
+
- Importing only `useAutoHeight` or `composeInjectedScript` does **not** pull the injected-bridge string into your bundle.
0 commit comments