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
//! Dynamic, declarative views.
use std::{cell::RefCell, rc::Rc};
pub use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
pub use web_sys::{Element, Event, EventTarget};

use crate::prelude::Receiver;

pub mod builder;
pub mod dom;
pub mod interface;

/// `Effect`s describe a value right now or at many points in the future - or both.
///
/// `Effect`s are used to change attributes, styles and inner text.
///
/// An `Effect` can be created from either a single value, a [`Receiver`] or a tuple of the
/// two.
pub enum Effect<T> {
    /// A value now.
    OnceNow {
        /// The extant value.
        now: T
    },
    /// Forthcoming values, to be delivered as messages from a [`Receiver`].
    ManyLater {
        /// The receiver that will deliver new values.
        later: Receiver<T>
    },
    /// Both a value now and forthcoming values to be delivered as messages from a [`Receiver`].
    OnceNowAndManyLater {
        /// The extant value.
        now: T,
        /// The receiver that will deliver new values.
        later: Receiver<T>
    },
}

impl<T: Clone> Clone for Effect<T> {
    fn clone(&self) -> Self {
        match self {
            Effect::OnceNow { now } => Effect::OnceNow { now: now.clone() },
            Effect::ManyLater { later } => Effect::ManyLater {
                later: later.branch(),
            },
            Effect::OnceNowAndManyLater { now, later } => Effect::OnceNowAndManyLater {
                now: now.clone(),
                later: later.branch(),
            },
        }
    }
}

impl<T> From<Effect<T>> for (Option<T>, Option<Receiver<T>>) {
    fn from(eff: Effect<T>) -> Self {
        match eff {
            Effect::OnceNow { now } => (Some(now), None),
            Effect::ManyLater { later } => (None, Some(later)),
            Effect::OnceNowAndManyLater { now, later } => (Some(now), Some(later)),
        }
    }
}

impl<T> From<T> for Effect<T> {
    fn from(now: T) -> Effect<T> {
        Effect::OnceNow { now }
    }
}

impl From<&str> for Effect<String> {
    fn from(s: &str) -> Effect<String> {
        Effect::OnceNow { now: s.into() }
    }
}

impl From<&String> for Effect<String> {
    fn from(s: &String) -> Effect<String> {
        Effect::OnceNow { now: s.clone() }
    }
}

impl<T> From<Receiver<T>> for Effect<T> {
    fn from(later: Receiver<T>) -> Effect<T> {
        Effect::ManyLater { later }
    }
}

impl<T> From<(T, Receiver<T>)> for Effect<T> {
    fn from((now, later): (T, Receiver<T>)) -> Effect<T> {
        Effect::OnceNowAndManyLater { now, later }
    }
}

impl<T> From<(Option<T>, Receiver<Rc<RefCell<Option<T>>>>)> for Effect<Rc<RefCell<Option<T>>>> {
    fn from((now, later): (Option<T>, Receiver<Rc<RefCell<Option<T>>>>)) -> Self {
        let now = Rc::new(RefCell::new(now));
        Effect::OnceNowAndManyLater { now, later }
    }
}

impl From<(&str, Receiver<String>)> for Effect<String> {
    fn from((now, later): (&str, Receiver<String>)) -> Effect<String> {
        Effect::OnceNowAndManyLater {
            now: now.into(),
            later,
        }
    }
}

/// Marker trait that means JsCast + Clone + + 'static.
pub trait IsDomNode: JsCast + Clone + 'static {}

impl<T> IsDomNode for T where T: JsCast + Clone + 'static {}