ravel_web/
lib.rs

1//! A web/DOM/HTML backend for [`ravel`].
2
3use std::sync::Arc;
4
5use atomic_waker::AtomicWaker;
6use dom::Position;
7use ravel::{AdaptState, Builder, Cx, CxRep, WithLocalState};
8
9mod any;
10pub mod attr;
11pub mod collections;
12mod dom;
13pub mod el;
14pub mod event;
15mod option;
16pub mod run;
17pub mod text;
18
19pub use any::*;
20pub use option::*;
21
22/// A dummy type representing the web backend.
23pub struct Web;
24
25impl CxRep for Web {
26    type BuildCx<'a> = BuildCx<'a>;
27    type RebuildCx<'a> = RebuildCx<'a>;
28}
29
30/// The necessary context for building [`Web`] components.
31#[derive(Copy, Clone)]
32pub struct BuildCx<'cx> {
33    position: Position<'cx>,
34}
35
36/// The necessary context for rebuilding [`Web`] components.
37#[derive(Copy, Clone)]
38pub struct RebuildCx<'cx> {
39    parent: &'cx web_sys::Element,
40    // TODO: Remove double pointer.
41    waker: &'cx Arc<AtomicWaker>,
42}
43
44/// A marker trait for the [`ravel::State`] types of a [`trait@View`].
45pub trait ViewMarker {}
46
47impl<T: 'static, S: ViewMarker> ViewMarker for WithLocalState<T, S> {}
48impl<S: ViewMarker, F> ViewMarker for AdaptState<S, F> {}
49
50macro_rules! tuple_state {
51    ($($a:ident),*) => {
52        #[allow(non_camel_case_types)]
53        impl<$($a),*> ViewMarker for ($($a,)*)
54        where
55            $($a: ViewMarker,)*
56        {
57        }
58    };
59}
60
61tuple_state!();
62tuple_state!(a);
63tuple_state!(a, b);
64tuple_state!(a, b, c);
65tuple_state!(a, b, c, d);
66tuple_state!(a, b, c, d, e);
67tuple_state!(a, b, c, d, e, f);
68tuple_state!(a, b, c, d, e, f, g);
69tuple_state!(a, b, c, d, e, f, g, h);
70
71/// Trait for DOM fragments.
72///
73/// These types can be used in contexts where the component may be removed
74/// according to its position in the DOM, for example when used inside an
75/// [`Option`].
76///
77/// This is implemented for [`el`] and [`text`] types and composites thereof,
78/// but not for [`attr`] or [`event`] types, which must always be permanently
79/// attached to an element.
80pub trait View: Builder<Web, State = Self::ViewState> {
81    type ViewState: ViewMarker;
82}
83
84impl<T, S: ViewMarker> View for T
85where
86    T: Builder<Web, State = S>,
87{
88    type ViewState = S;
89}
90
91#[doc(hidden)]
92pub trait Captures<'a> {}
93impl<'a, T: ?Sized> Captures<'a> for T {}
94
95#[doc(hidden)]
96pub use ravel::State as ViewState;
97
98/// A convenience macro for declaring a [`trait@View`] type.
99///
100/// The first parameter is the `Output` type of the [`trait@View`]'s
101/// [`Builder::State`]. Any additional parameters are captured lifetimes.
102#[macro_export]
103macro_rules! View {
104    ($output:ty $(, $a:lifetime)*) => {
105        impl $crate::View<
106            ViewState = impl $crate::ViewMarker + $crate::ViewState<$output>
107        > $(+ $crate::Captures<$a>)*
108    };
109}