maple_core/
lib.rs

1//! # Maple API Documentation
2//!
3//! Maple is a VDOM-less web library with fine-grained reactivity.
4//!
5//! This is the API docs for maple. If you are looking for the usage docs, checkout the [README](https://github.com/lukechu10/maple).
6//!
7//! ## Supported Targets
8//! - `wasm32-unknown-unknown`
9//!
10//! ## Features
11//! - `serde` - Enables serializing and deserializing `Signal`s and other wrapper types using `serde`.
12
13#![allow(non_snake_case)]
14#![warn(clippy::clone_on_ref_ptr)]
15#![warn(clippy::rc_buffer)]
16#![deny(clippy::trait_duplication_in_bounds)]
17#![deny(clippy::type_repetition_in_bounds)]
18
19pub mod flow;
20#[doc(hidden)]
21pub mod internal;
22#[doc(hidden)]
23pub mod macros;
24pub mod noderef;
25pub mod reactive;
26pub mod render;
27
28use prelude::SignalVec;
29use web_sys::Node;
30
31use std::cell::RefCell;
32
33pub use maple_core_macro::template;
34
35/// The result of the [`template!`](template) macro. Should not be used directly.
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct TemplateResult {
38    node: Node,
39}
40
41impl TemplateResult {
42    /// Create a new [`TemplateResult`] from a [`Node`].
43    pub fn new(node: Node) -> Self {
44        Self { node }
45    }
46
47    /// Create a new [`TemplateResult`] with a blank comment node
48    pub fn empty() -> Self {
49        Self::new(
50            web_sys::window()
51                .unwrap()
52                .document()
53                .unwrap()
54                .create_comment("")
55                .into(),
56        )
57    }
58
59    pub fn inner_element(&self) -> Node {
60        self.node.clone()
61    }
62}
63
64/// A [`SignalVec`](reactive::SignalVec) of [`TemplateResult`]s.
65#[derive(Clone)]
66pub struct TemplateList {
67    templates: reactive::SignalVec<TemplateResult>,
68}
69
70impl From<SignalVec<TemplateResult>> for TemplateList {
71    fn from(templates: SignalVec<TemplateResult>) -> Self {
72        Self { templates }
73    }
74}
75
76/// Render a [`TemplateResult`] into the DOM.
77///
78/// Alias for [`render_to`] with `parent` being the `<body>` tag.
79pub fn render(template_result: impl FnOnce() -> TemplateResult + 'static) {
80    let window = web_sys::window().unwrap();
81    let document = window.document().unwrap();
82
83    render_to(template_result, &document.body().unwrap());
84}
85
86/// Render a [`TemplateResult`] under a `parent` node. For rendering under the `<body>` tag, use [`render()`] instead.
87pub fn render_to(template_result: impl FnOnce() -> TemplateResult + 'static, parent: &Node) {
88    let owner = reactive::create_root(move || {
89        parent.append_child(&template_result().node).unwrap();
90    });
91
92    thread_local! {
93        static GLOBAL_OWNERS: RefCell<Vec<reactive::Owner>> = RefCell::new(Vec::new());
94    }
95
96    GLOBAL_OWNERS.with(|global_owners| global_owners.borrow_mut().push(owner));
97}
98
99/// The maple prelude.
100pub mod prelude {
101    pub use crate::cloned;
102    pub use crate::flow::{Indexed, IndexedProps, Keyed, KeyedProps};
103    pub use crate::noderef::NodeRef;
104    pub use crate::reactive::{
105        create_effect, create_effect_initial, create_memo, create_root, create_selector,
106        create_selector_with, on_cleanup, untrack, Signal, SignalVec, StateHandle,
107    };
108    pub use crate::render::Render;
109    pub use crate::{render, render_to, TemplateList, TemplateResult};
110
111    pub use maple_core_macro::template;
112}