Skip to main content

cranpose/
webview.rs

1use cranpose_ui::{Modifier, composable};
2
3/// An event from an embedded browser.
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub enum WebViewEvent {
6    /// A page finished loading. In browsers this reports the requested URL:
7    /// cross-origin navigation and HTTP status are not exposed by iframe events.
8    Loaded(String),
9    /// Creating the view or requesting navigation failed.
10    Failed(String),
11}
12
13/// Embeds a website inside the component's layout bounds.
14///
15/// Enable Cranpose's `webview` feature for application hosts, or register a
16/// `WebViewFactory` when embedding a component in Android/UIKit. The URL loads
17/// only when it changes; unrelated recompositions preserve the document.
18/// Desktop uses the system WebView (WebKit, WebView2 or WebKitGTK), Android uses
19/// WebView, iOS uses WKWebView, and browsers use an iframe. Browser sites must
20/// permit framing. Linux requires WebKitGTK 4.1 and X11 or XWayland.
21///
22/// Native views appear above Cranpose drawing. Use axis-aligned bounds without
23/// ancestor transforms or rounded clips, and remove the view before displaying
24/// an overlapping Cranpose popup. See [`crate::native_view::NativeViewLayout`].
25#[composable]
26pub fn WebView(url: &str, modifier: Modifier, on_event: impl Fn(WebViewEvent) + 'static) {
27    crate::native_view::NativeView(
28        crate::native_view::current_host(),
29        "web",
30        url,
31        modifier,
32        move |event| {
33            if let Some(url) = event.strip_prefix("loaded:") {
34                on_event(WebViewEvent::Loaded(url.to_owned()));
35            } else if let Some(message) = event.strip_prefix("error:") {
36                on_event(WebViewEvent::Failed(message.to_owned()));
37            }
38        },
39    );
40}