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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#![deny(missing_docs)]
#![cfg_attr(not(feature = "stable"), feature(fn_traits))]
#![cfg_attr(not(feature = "stable"), feature(unboxed_closures))]

//! DOM operations and rendering for Leptos.
//!
//! This crate mostly includes utilities and types used by the templating system, and utility
//! functions to make it easier for you to interact with the DOM, including with events.
//!
//! It also includes functions to support rendering HTML to strings, which is the server-side
//! equivalent of DOM operations.
//!
//! Note that the types [Element] and [Node] are type aliases, handled differently depending on the
//! target:
//! - Browser (features `csr` and `hydrate`): they alias [web_sys::Element] and [web_sys::Node],
//!   since the renderer works directly with actual DOM nodes.
//! - Server: they both alias [String], since the templating system directly generates HTML strings.

use cfg_if::cfg_if;

mod attribute;
mod child;
mod class;
mod event_delegation;
mod logging;
mod mount;
mod node_ref;
mod operations;
mod property;

cfg_if! {
    // can only include this if we're *only* enabling SSR, as it's the lowest-priority feature
    // if either `csr` or `hydrate` is enabled, `Element` is a `web_sys::Element` and can't be rendered
    if #[cfg(doc)] {
        /// The type of an HTML or DOM element. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Element`.
        pub type Element = web_sys::Element;

        /// The type of an HTML or DOM node. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Node`.
        pub type Node = web_sys::Node;

        mod render_to_string;
        pub use render_to_string::*;
        mod reconcile;
        mod render;

        pub use reconcile::*;
        pub use render::*;
    } else if #[cfg(not(any(feature = "hydrate", feature = "csr")))] {
        /// The type of an HTML or DOM element. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Element`.
        pub type Element = String;

        /// The type of an HTML or DOM node. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Node`.
        pub type Node = String;

        mod render_to_string;
        pub use render_to_string::*;

        #[doc(hidden)]
        pub struct Marker { }
    } else {
        /// The type of an HTML or DOM element. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Element`.
        pub type Element = web_sys::Element;

        /// The type of an HTML or DOM node. When server rendering, this is a `String`. When rendering in a browser,
        /// this is a DOM `Node`.
        pub type Node = web_sys::Node;

        mod reconcile;
        mod render;

        pub use reconcile::*;
        pub use render::*;
    }
}

pub use attribute::*;
pub use child::*;
pub use class::*;
pub use logging::*;
pub use mount::*;
pub use node_ref::*;
pub use operations::*;
pub use property::*;

pub use js_sys;
pub use wasm_bindgen;
pub use web_sys;

use leptos_reactive::Scope;
pub use wasm_bindgen::UnwrapThrowExt;

// Hidden because this is primarily used by the `view` macro, not by library users.
#[doc(hidden)]
pub fn create_component<F, T>(cx: Scope, f: F) -> T
where
    F: FnOnce() -> T,
{
    cfg_if! {
        if #[cfg(feature = "csr")] {
            cx.untrack(f)
        } else {
            cx.with_next_context(f)
        }
    }
}

/// Shorthand to test for whether an `ssr` feature is enabled.
///
/// In the past, this was implemented by checking whether `not(target_arch = "wasm32")`.
/// Now that some cloud platforms are moving to run Wasm on the edge, we really can't
/// guarantee that compiling to Wasm means browser APIs are available, or that not compiling
/// to Wasm means we're running on the server.
///
/// ```
/// # use leptos_dom::is_server;
/// let todos = if is_server!() {
///   // if on the server, load from DB
/// } else {
///   // if on the browser, do something else
/// };
/// ```
#[macro_export]
macro_rules! is_server {
    () => {
        cfg!(feature = "ssr")
    };
}

/// A shorthand macro to test whether this is a debug build.
/// ```
/// # use leptos_dom::is_dev;
/// if is_dev!() {
///   // log something or whatever
/// }
/// ```
#[macro_export]
macro_rules! is_dev {
    () => {
        cfg!(debug_assertions)
    };
}

#[doc(hidden)]
pub fn __leptos_renderer_error(expected: &'static str, location: &'static str) -> web_sys::Node {
    cfg_if! {
        if #[cfg(debug_assertions)] {
            panic!("Yikes! Something went wrong while Leptos was trying to traverse the DOM to set up the reactive system.\n\nThe renderer expected {expected:?} as {location} and couldn't get it.\n\nThis is almost certainly a bug in the framework, not your application. Please open an issue on GitHub and provide example code if possible.\n\nIn the meantime, these bugs are often related to <Component/>s or {{block}}s when they are siblings of each other. Try wrapping those in a <span> or <div> for now. Sorry for the pain!")
        } else {
            _ = expected;
            panic!("Renderer error. You can find a more detailed error message if you compile in debug mode.")
        }
    }
}