stellation_frontend/
lib.rs

1//! Stellation Frontend.
2//!
3//! This crate contains the frontend renderer and useful utilities for stellation applications.
4
5#![deny(clippy::all)]
6#![deny(missing_debug_implementations)]
7#![deny(unsafe_code)]
8#![deny(non_snake_case)]
9#![deny(clippy::cognitive_complexity)]
10#![deny(missing_docs)]
11#![cfg_attr(documenting, feature(doc_cfg))]
12#![cfg_attr(documenting, feature(doc_auto_cfg))]
13#![cfg_attr(any(releasing, not(debug_assertions)), deny(dead_code, unused_imports))]
14
15use std::marker::PhantomData;
16
17use bounce::Selector;
18use stellation_bridge::links::{Link, PhantomLink};
19use stellation_bridge::state::BridgeState;
20use stellation_bridge::Bridge;
21use yew::prelude::*;
22
23use crate::root::{StellationRoot, StellationRootProps};
24pub mod components;
25mod root;
26pub mod trace;
27
28/// The Stellation Frontend Renderer.
29///
30/// This type wraps the [Yew Renderer](yew::Renderer) and provides additional features.
31///
32/// # Note
33///
34/// Stellation provides [`BrowserRouter`](yew_router::BrowserRouter) and
35/// [`BounceRoot`](bounce::BounceRoot) to all applications.
36///
37/// Bounce Helmet is also bridged automatically.
38///
39/// You do not need to add them manually.
40#[derive(Debug)]
41pub struct Renderer<COMP, L = PhantomLink>
42where
43    COMP: BaseComponent,
44    L: Link,
45{
46    props: COMP::Properties,
47    bridge_state: Option<BridgeState<L>>,
48    _marker: PhantomData<COMP>,
49}
50
51impl<COMP> Default for Renderer<COMP>
52where
53    COMP: BaseComponent,
54    COMP::Properties: Default,
55{
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl<COMP> Renderer<COMP>
62where
63    COMP: BaseComponent,
64{
65    /// Creates a Renderer with default props.
66    pub fn new() -> Renderer<COMP>
67    where
68        COMP::Properties: Default,
69    {
70        Self::with_props(Default::default())
71    }
72}
73
74impl<COMP, L> Renderer<COMP, L>
75where
76    COMP: BaseComponent,
77    L: 'static + Link,
78{
79    /// Creates a Renderer with specified props.
80    pub fn with_props(props: COMP::Properties) -> Renderer<COMP, L> {
81        Renderer {
82            props,
83            bridge_state: None,
84            _marker: PhantomData,
85        }
86    }
87
88    /// Connects a bridge to the application.
89    pub fn bridge_selector<S, LINK>(self) -> Renderer<COMP, LINK>
90    where
91        S: 'static + Selector + AsRef<Bridge<LINK>>,
92        LINK: 'static + Link,
93    {
94        Renderer {
95            props: self.props,
96            bridge_state: Some(BridgeState::from_bridge_selector::<S>()),
97            _marker: PhantomData,
98        }
99    }
100
101    fn into_yew_renderer(self) -> yew::Renderer<StellationRoot<L>> {
102        let Self {
103            props,
104            bridge_state,
105            ..
106        } = self;
107
108        let children = html! {
109            <COMP ..props />
110        };
111
112        let props = StellationRootProps {
113            bridge_state,
114            children,
115        };
116
117        yew::Renderer::with_props(props)
118    }
119
120    /// Renders the application.
121    ///
122    /// Whether the application is rendered or hydrated is determined automatically based on whether
123    /// SSR is used on the server side for this page.
124    pub fn render(self) {
125        let renderer = self.into_yew_renderer();
126
127        if web_sys::window()
128            .and_then(|m| m.document())
129            .and_then(|m| {
130                m.query_selector(r#"meta[name="stellation-mode"][content="hydrate"]"#)
131                    .ok()
132                    .flatten()
133            })
134            .is_some()
135        {
136            renderer.hydrate();
137        } else {
138            renderer.render();
139        }
140    }
141}