# moonview

`moonview` is the native-only package for embedding a platform WebView in a
caller-owned native container. The host supplies the parent handle, owns the UI
thread and event loop, resizes the child, and destroys the child before its
parent. Every WebView command must run on that owner UI thread; Moonview does
not provide cross-thread dispatch.

## Minimal Use

```moonbit nocheck
let options = WebViewOptions::new(
  bounds=Rect::new(x=0, y=0, width=800, height=600),
  initial_html="<!doctype html><title>moonview</title>",
  on_event=event => match event {
    WebViewEvent::Ready => println("ready")
    WebViewEvent::CreationFailed(_error) => println("failed")
    WebViewEvent::ProcessFailed(_error) => println("browser process failed")
    _ => ()
  },
)

match WebView::create(parent_handle, options) {
  Ok(view) => ignore(view.post_message("host-ready"))
  Err(_error) => abort("create rejected")
}
```

Control methods return `Ok(())` only after the native backend accepts or queues
the command for a live view. Navigation and JavaScript outcomes remain
asynchronous and are reported through `WebViewEvent`.

`ProcessFailed` is terminal. On WebView2 runtime failures, Moonview stops
accepting commands for that view. Destroy it on its owner UI thread, then
create a replacement explicitly; Moonview never attempts background recovery.

## Resource Limits

Desktop backends limit each WebView to 256 commands queued before readiness,
4 MiB of queued command storage, and 4 MiB per custom-scheme request body.
Configure or disable individual limits with `WebViewResourceLimits`; `0`
disables one limit, while negative values cause `WebView::create` to return
`NativeFailure`. The limits currently apply to Windows, macOS, and Linux.

```moonbit nocheck
///|
let options = WebViewOptions::new(
  bounds=Rect::new(x=0, y=0, width=800, height=600),
  resource_limits=WebViewResourceLimits::new(
    max_pending_commands=64,
    max_pending_command_bytes=1024 * 1024,
    max_protocol_request_body_bytes=1024 * 1024,
  ),
)
```

Use `WebViewEvent::Ready` before relying on a loaded document. Page code sends
UTF-8 strings with `window.moonview.postMessage(...)`; native code receives
`PageMessage` and sends strings with `WebView::post_message(...)`. Page-side
`window.moonview.onmessage` receives an object whose `data` property contains
the UTF-8 message on every desktop backend.

## Browser Data Contexts

`WebView::create` uses the shared persistent context. Reuse a `WebContext`
when multiple views must share browser data:

```moonbit nocheck
let context = @moonview.WebContext::persistent(data_directory="F:/app-data/moonview")
match @moonview.WebView::create_in_context(context, parent_handle, options) {
  Ok(view) => ignore(view.set_visible(true))
  Err(_error) => abort("WebView creation rejected")
}
```

Custom data directories are supported on Windows and Linux. Ephemeral contexts
are supported on macOS and Linux. Unsupported combinations return `Unsupported`
rather than selecting another browser profile.

## OpenHarmony ArkWeb

OpenHarmony hosts `Web` in ArkUI rather than accepting an arbitrary native
parent handle. Create that component in ArkUI, then attach on its UI thread by
its stable `webTag`:

```moonbit nocheck
let options = OhosAttachOptions::new(
  on_event=event => match event {
    WebViewEvent::Ready => println("ArkWeb attached")
    _ => ()
  },
)

match WebView::attach_ohos("main-web", options) {
  Ok(view) => {
    ignore(view.reload())
    ignore(view.eval("console.log('moonview')", "startup"))
  }
  Err(_error) => abort("ArkWeb attach rejected")
}
```

The experimental API 12 adapter supports attach, `reload`, fire-and-forget
`eval`, and detachment. ArkUI owns source, layout, visibility, and permissions;
the remaining desktop-style controls return `Unsupported`. `destroy` detaches
Moonview and does not destroy the ArkUI `Web` component.

## Application Resources

Call `register_custom_scheme(...)` before the first `WebView::create`, then
respond to each `ProtocolRequest` with `WebView::respond_protocol(...)`. The
request callback carries method, URI, headers, and binary body data; unanswered
requests are cancelled after 30 seconds. Oversized request bodies are answered
with HTTP `413` locally and are not dispatched to MoonBit.

## Permissions

Camera and microphone requests are denied unless `on_media_permission` returns
`MediaPermissionDecision::Allow`. Other browser permission kinds are not part
of this cross-platform package API.

## Native File Dialogs

`WebView::show_file_dialog` presents a platform-native dialog from the owning
UI thread. Windows supports file open, multi-file open, save, and directory
selection. Other backends currently return `Unsupported` explicitly.

```moonbit nocheck
match view.show_file_dialog(
  FileDialogOptions::new(
    kind=FileDialogKind::OpenFile,
    title=Some("Open document"),
    filters=[
      FileDialogFilter::new(
        name="Text files",
        extensions=["txt", "md"],
      ),
    ],
  ),
) {
  Ok(FileDialogResult::Cancelled) => ()
  Ok(FileDialogResult::Selected(paths)) => println(paths)
  Err(error) => println(error)
}
```

The selected paths are native host data. Frameworks embedding MoonView should
apply their own capability policy before forwarding a selection to page code.

## Main Entry Points

- `WebViewOptions::new(...)` configures creation callbacks and initial content.
- `on_new_window` denies page-created windows by default, or can return
  `NewWindowDecision::NavigateCurrent` to redirect the requesting WebView.
- `WebView::create(...)` embeds an asynchronously-created native child view.
- `WebView::set_bounds(...)`, `navigate(...)`, `eval(...)`, and
  `post_message(...)` control a live view.
- `WebView::show_file_dialog(...)` presents a native file or directory dialog.
- `WebView::destroy(...)` releases the native child before the host parent.
- `register_custom_scheme(...)` and `WebView::respond_protocol(...)` serve
  application-owned resources.

See the repository README for platform prerequisites and host-handle details.
