1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
use crate::{document, Element};
use cfg_if::cfg_if;
use leptos_reactive::Scope;
use wasm_bindgen::UnwrapThrowExt;
/// Describes a type that can be mounted to a parent element in the DOM.
pub trait Mountable {
/// Injects the element into the parent as its next child.
fn mount(&self, parent: &web_sys::Element);
}
impl Mountable for Element {
fn mount(&self, parent: &web_sys::Element) {
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
parent.append_child(self).unwrap_throw();
} else {
let _ = parent;
}
}
}
}
impl Mountable for Vec<Element> {
fn mount(&self, parent: &web_sys::Element) {
cfg_if! {
if #[cfg(any(feature = "csr", feature = "hydrate"))] {
for element in self {
parent.append_child(element).unwrap_throw();
}
} else {
_ = parent; // to clear warning
}
}
}
}
/// Runs the given function to mount something to the `<body>` element in the DOM.
///
/// ```
/// // the simplest Leptos application
/// # use leptos_dom::*; use leptos_dom::wasm_bindgen::JsCast;
/// # use leptos_macro::view;
/// # if false { // can't actually run as a doctest on any feature
/// mount_to_body(|cx| view! { cx, <p>"Hello, world!"</p> });
/// # }
/// ```
pub fn mount_to_body<T, F>(f: F)
where
F: Fn(Scope) -> T + 'static,
T: Mountable,
{
mount(document().body().unwrap_throw(), f)
}
/// Runs the given function to mount something to the given element in the DOM.
///
/// ```
/// // a very simple Leptos application
/// # use leptos_dom::*; use leptos_dom::wasm_bindgen::JsCast;
/// # use leptos_macro::view;
/// # if false { // can't actually run as a doctest on any feature
/// mount(
/// document().get_element_by_id("root").unwrap().unchecked_into(),
/// |cx| view! { cx, <p>"Hello, world!"</p> }
/// );
/// # }
/// ```
pub fn mount<T, F>(parent: web_sys::HtmlElement, f: F)
where
F: Fn(Scope) -> T + 'static,
T: Mountable,
{
use leptos_reactive::{create_runtime, create_scope};
// this is not a leak
// CSR and hydrate mode define a single, thread-local Runtime
let _ = create_scope(create_runtime(), move |cx| {
(f(cx)).mount(&parent);
});
}
/// “Hydrates” server-rendered HTML, attaching event listeners and setting up reactivity
/// while reusing the existing DOM nodes, by running the given function beginning with
/// the parent node.
///
/// ```
/// // rehydrate a very simple Leptos application
/// # use leptos_dom::*; use leptos_dom::wasm_bindgen::JsCast;
/// # use leptos_macro::view;
/// # if false { // can't actually run as a doctest on any feature
/// if let Some(body) = body() {
/// hydrate(body, |cx| view! { cx, <p>"Hello, world!"</p> });
/// }
/// # }
/// ```
#[cfg(feature = "hydrate")]
pub fn hydrate<T, F>(parent: web_sys::HtmlElement, f: F)
where
F: Fn(Scope) -> T + 'static,
T: Mountable,
{
use leptos_reactive::create_runtime;
// this is not a leak
// CSR and hydrate mode define a single, thread-local Runtime
let _ = leptos_reactive::create_scope(create_runtime(), move |cx| {
cx.start_hydration(&parent);
(f(cx));
cx.end_hydration();
});
}