wasm_liveview/lib.rs
1//! Two-way bridge between wasm-bindgen Rust and a mounted Phoenix LiveView.
2//!
3//! Outbound, this crate wraps the [`Phoenix.LiveView.JS`] command set so
4//! Rust/wasm code can fire LV events, navigate, dispatch DOM events, run
5//! transitions, and manage focus -- without trampolining through hidden
6//! `phx-*` trigger elements. Inbound, it lets Rust subscribe to server-pushed
7//! events from `Phoenix.LiveView.push_event/3`.
8//!
9//! Written for game code that renders in wasm but wants the server to own
10//! state, routing, and persistence.
11//
12//! # Payload types
13//!
14//! Commands that carry a payload ([`push_event`], [`push_event_to`],
15//! [`dispatch_with`]) accept any `T: serde::Serialize`. Use
16//! [`serde_json::json!`] for ad-hoc payloads, or define a
17//! `#[derive(Serialize)]` struct for typed, compile-time-checked ones. Both
18//! styles are shown on each function's page.
19//!
20//! # Outbound example
21//!
22//! ```no_run
23//! use wasm_liveview as lv;
24//!
25//! #[derive(serde::Serialize)]
26//! struct Submit<'a> { word: &'a str, route: &'a [usize] }
27//!
28//! lv::push_event("submit_word", &Submit { word: "TRY", route: &[0, 1, 2] })?;
29//!
30//! // Client-side routing.
31//! lv::navigate("/room/42", false)?;
32//!
33//! // Run a CSS transition.
34//! lv::transition(
35//! lv::TransitionClasses {
36//! transition: &["fade-in"],
37//! start: &["opacity-0"],
38//! end: &["opacity-100"],
39//! },
40//! Some("#board"),
41//! Some(150),
42//! )?;
43//! # Ok::<(), lv::Error>(())
44//! ```
45//!
46//! # Inbound example
47//!
48//! ```no_run
49//! use wasm_liveview as lv;
50//!
51//! #[derive(serde::Deserialize)]
52//! struct Score { value: u32 }
53//!
54//! let sub = lv::subscribe::<Score, _>("score_update", |s| {
55//! // handler runs once per server push
56//! let _ = s.value;
57//! })?;
58//!
59//! // Drop the subscription to unsubscribe, or:
60//! sub.forget();
61//! # Ok::<(), lv::Error>(())
62//! ```
63//!
64//! # Target behavior
65//!
66//! On `wasm32-*` targets the crate pulls in `wasm-bindgen`, `js-sys`, and
67//! `web-sys` and calls `window.liveSocket.execJS` for real. On any other
68//! target every outbound function stubs to `Ok(())` and [`subscribe`] returns
69//! an inert handle, so the JSON wire-format encoders can be unit-tested
70//! without a browser.
71//!
72//! # Error model
73//!
74//! Every fallible call returns `Result<_, `[`Error`]`>`. See the [`Error`]
75//! enum for the failure modes (missing `window`, uninitialized `liveSocket`,
76//! JSON serialization failures, and JS exceptions thrown by `execJS`).
77//!
78//! [`Phoenix.LiveView.JS`]: https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.JS.html
79
80#![cfg_attr(docsrs, feature(doc_cfg))]
81
82mod bridge;
83#[cfg(target_arch = "wasm32")]
84mod cache;
85mod commands;
86mod error;
87mod exec;
88mod subscribe;
89
90pub use bridge::Bridge;
91pub use commands::dispatch::{dispatch, dispatch_with};
92pub use commands::exec_attr::exec_attr;
93pub use commands::focus::{focus, focus_first, pop_focus, push_focus};
94pub use commands::navigate::{navigate, patch};
95pub use commands::push::{push_event, push_event_to};
96pub use commands::transition::{TransitionClasses, transition};
97pub use error::Error;
98pub use subscribe::{Subscription, subscribe};