renamed IntoNode to IntoView and Node to View, and fixed broken doc links

This commit is contained in:
Jose Quesada 2022-12-05 12:39:24 -06:00
parent 1fbe8bd790
commit b3d813d0c1
9 changed files with 221 additions and 216 deletions

View file

@ -5,7 +5,7 @@ mod unit;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind, Mountable};
use crate::{Comment, IntoNode, Node};
use crate::{Comment, IntoView, View};
pub use dyn_child::*;
pub use each::*;
pub use fragment::*;
@ -23,7 +23,7 @@ pub enum CoreComponent {
Unit(UnitRepr),
/// The [`DynChild`] component.
DynChild(DynChildRepr),
/// The [`Each`] component.
/// The [`EachKey`] component.
Each(EachRepr),
}
@ -37,14 +37,14 @@ pub struct ComponentRepr {
#[cfg(debug_assertions)]
_opening: Comment,
/// The children of the component.
pub children: Vec<Node>,
pub children: Vec<View>,
closing: Comment,
disposer: Option<ScopeDisposer>,
}
impl Drop for ComponentRepr {
fn drop(&mut self) {
// TODO: all ComponentReprs are immediately dropped,
// TODO: all ComponentReprs are immediately dropped,
// which means their scopes are immediately disposed,
// which means components have no reactivity
if let Some(disposer) = self.disposer.take() {
@ -71,15 +71,15 @@ impl Mountable for ComponentRepr {
}
}
impl IntoNode for ComponentRepr {
impl IntoView for ComponentRepr {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<Component />", skip_all, fields(name = %self.name)))]
fn into_node(self, _: Scope) -> Node {
fn into_view(self, _: Scope) -> View {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
for child in &self.children {
mount_child(MountKind::Before(&self.closing.node), child);
}
Node::Component(self)
View::Component(self)
}
}
@ -133,7 +133,7 @@ impl ComponentRepr {
/// A user-defined `leptos` component.
pub struct Component<F>
where
F: FnOnce(Scope) -> Node,
F: FnOnce(Scope) -> View,
{
name: Cow<'static, str>,
children_fn: F,
@ -141,7 +141,7 @@ where
impl<F> Component<F>
where
F: FnOnce(Scope) -> Node,
F: FnOnce(Scope) -> View,
{
/// Creates a new component.
pub fn new(name: impl Into<Cow<'static, str>>, f: F) -> Self {
@ -152,16 +152,17 @@ where
}
}
impl<F> IntoNode for Component<F>
impl<F> IntoView for Component<F>
where
F: FnOnce(Scope) -> Node,
F: FnOnce(Scope) -> View,
{
fn into_node(self, cx: Scope) -> Node {
fn into_view(self, cx: Scope) -> View {
let Self { name, children_fn } = self;
let mut children = None;
let disposer = cx.child_scope(|cx| children = Some(cx.untrack(move || children_fn(cx))));
let disposer =
cx.child_scope(|cx| children = Some(cx.untrack(move || children_fn(cx))));
let children = children.unwrap();
@ -170,6 +171,6 @@ where
repr.disposer = Some(disposer);
repr.children = vec![children];
repr.into_node(cx)
repr.into_view(cx)
}
}

View file

@ -1,6 +1,6 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind, Mountable};
use crate::{Comment, IntoNode, Node};
use crate::{Comment, IntoView, View};
use leptos_reactive::{create_effect, Scope};
use std::{borrow::Cow, cell::RefCell, rc::Rc};
use wasm_bindgen::JsCast;
@ -12,7 +12,7 @@ pub struct DynChildRepr {
document_fragment: web_sys::DocumentFragment,
#[cfg(debug_assertions)]
opening: Comment,
child: Rc<RefCell<Box<Option<Node>>>>,
child: Rc<RefCell<Box<Option<View>>>>,
closing: Comment,
}
@ -69,11 +69,11 @@ impl DynChildRepr {
}
}
/// Represents any [`Node`] that can change over time.
/// Represents any [`View`] that can change over time.
pub struct DynChild<CF, N>
where
CF: Fn() -> N + 'static,
N: IntoNode,
N: IntoView,
{
child_fn: CF,
}
@ -81,7 +81,7 @@ where
impl<CF, N> DynChild<CF, N>
where
CF: Fn() -> N + 'static,
N: IntoNode,
N: IntoView,
{
/// Creates a new dynamic child which will re-render whenever it's
/// signal dependencies change.
@ -90,16 +90,16 @@ where
}
}
impl<CF, N> IntoNode for DynChild<CF, N>
impl<CF, N> IntoView for DynChild<CF, N>
where
CF: Fn() -> N + 'static,
N: IntoNode,
N: IntoView,
{
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "<DynChild />", skip_all)
)]
fn into_node(self, cx: Scope) -> crate::Node {
fn into_view(self, cx: Scope) -> crate::View {
let Self { child_fn } = self;
let component = DynChildRepr::new();
@ -123,7 +123,7 @@ where
create_effect(cx, move |prev_run| {
let _guard = span.enter();
let _guard = trace_span!("DynChild reactive").entered();
let new_child = child_fn().into_node(cx);
let new_child = child_fn().into_view(cx);
if let Some(t) = new_child.get_text() {
let mut prev_text_node_borrow = prev_text_node.borrow_mut();
@ -155,11 +155,11 @@ where
#[cfg(all(target_arch = "wasm32", feature = "web"))]
mount_child(MountKind::Before(&closing), &new_child);
**child.borrow_mut() = Some(new_child);
}
});
Node::CoreComponent(crate::CoreComponent::DynChild(component))
View::CoreComponent(crate::CoreComponent::DynChild(component))
}
}

View file

@ -1,6 +1,6 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind, Mountable, RANGE};
use crate::{Comment, CoreComponent, IntoNode, Node};
use crate::{Comment, CoreComponent, IntoView, View};
use itertools::{EitherOrBoth, Itertools};
use leptos_reactive::{create_effect, Scope};
use rustc_hash::FxHasher;
@ -39,7 +39,7 @@ impl VecExt for Vec<Option<EachItem>> {
}
}
/// The internal representation of the [`Each`] core-component.
/// The internal representation of the [`EachKey`] core-component.
#[derive(Debug)]
pub struct EachRepr {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
@ -110,19 +110,19 @@ impl Mountable for EachRepr {
}
}
/// The internal representation of an [`Each`] item.
/// The internal representation of an [`EachKey`] item.
#[derive(Debug)]
struct EachItem {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
document_fragment: web_sys::DocumentFragment,
#[cfg(debug_assertions)]
opening: Comment,
child: Node,
child: View,
closing: Comment,
}
impl EachItem {
fn new(child: Node) -> Self {
fn new(child: View) -> Self {
let markers = (
Comment::new(Cow::Borrowed("</EachItem>")),
#[cfg(debug_assertions)]
@ -201,7 +201,7 @@ where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K + 'static,
K: Eq + Hash + 'static,
T: 'static,
@ -216,12 +216,12 @@ where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K,
K: Eq + Hash + 'static,
T: 'static,
{
/// Creates a new [`Each`] component.
/// Creates a new [`EachKey`] component.
pub fn new(items_fn: IF, key_fn: KF, each_fn: EF) -> Self {
Self {
items_fn,
@ -231,12 +231,12 @@ where
}
}
impl<IF, I, T, EF, N, KF, K> IntoNode for EachKey<IF, I, T, EF, N, KF, K>
impl<IF, I, T, EF, N, KF, K> IntoView for EachKey<IF, I, T, EF, N, KF, K>
where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K + 'static,
K: Eq + Hash + 'static,
T: 'static,
@ -245,7 +245,7 @@ where
debug_assertions,
instrument(level = "trace", name = "<Each />", skip_all)
)]
fn into_node(self, cx: leptos_reactive::Scope) -> crate::Node {
fn into_view(self, cx: leptos_reactive::Scope) -> crate::View {
let Self {
items_fn,
each_fn,
@ -294,7 +294,7 @@ where
*children_borrow = Vec::with_capacity(items.len());
for item in items {
let child = each_fn(item).into_node(cx);
let child = each_fn(item).into_view(cx);
let each_item = EachItem::new(child);
@ -308,7 +308,7 @@ where
HashRun(hashed_items)
});
Node::CoreComponent(CoreComponent::Each(component))
View::CoreComponent(CoreComponent::Each(component))
}
}
@ -483,7 +483,7 @@ fn apply_cmds<T, EF, N>(
each_fn: &EF,
) where
EF: Fn(T) -> N,
N: IntoNode,
N: IntoView,
{
#[cfg(all(target_arch = "wasm32", feature = "web"))]
let range = &RANGE;
@ -558,7 +558,7 @@ fn apply_cmds<T, EF, N>(
for DiffOpAdd { at, mode } in cmds.added {
let item = std::mem::replace(&mut items[at], None).unwrap();
let child = each_fn(item).into_node(cx);
let child = each_fn(item).into_view(cx);
let each_item = EachItem::new(child);
@ -605,7 +605,7 @@ where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K + 'static,
K: Eq + Hash + 'static,
T: 'static,
@ -661,16 +661,16 @@ where
pub fn For<IF, I, T, EF, N, KF, K>(
cx: Scope,
props: ForProps<IF, I, T, EF, N, KF, K>,
) -> Node
) -> View
where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K + 'static,
K: Eq + Hash + 'static,
T: 'static,
{
let each_fn = (props.children)().swap_remove(0);
EachKey::new(props.each, props.key, each_fn).into_node(cx)
EachKey::new(props.each, props.key, each_fn).into_view(cx)
}

View file

@ -1,21 +1,21 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind};
use crate::{ComponentRepr, IntoNode, Node};
use crate::{ComponentRepr, IntoView, View};
/// Represents a group of [`Nodes`](Node).
/// Represents a group of [`views`](View).
#[derive(Debug)]
pub struct Fragment(Vec<Node>);
pub struct Fragment(Vec<View>);
impl Fragment {
/// Creates a new [`Fragment`] from a [`Vec<Node>`].
pub fn new(nodes: Vec<Node>) -> Self {
pub fn new(nodes: Vec<View>) -> Self {
Self(nodes)
}
}
impl IntoNode for Fragment {
impl IntoView for Fragment {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "</>", skip_all, fields(children = self.0.len())))]
fn into_node(self, _cx: leptos_reactive::Scope) -> Node {
fn into_view(self, _cx: leptos_reactive::Scope) -> View {
let mut frag = ComponentRepr::new("");
#[cfg(all(target_arch = "wasm32", feature = "web"))]
@ -28,6 +28,6 @@ impl IntoNode for Fragment {
frag.children = self.0;
Node::Component(frag)
View::Component(frag)
}
}

View file

@ -1,6 +1,6 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::Mountable;
use crate::{Comment, CoreComponent, IntoNode, Node};
use crate::{Comment, CoreComponent, IntoView, View};
use wasm_bindgen::JsCast;
/// The internal representation of the [`Unit`] core-component.
@ -32,14 +32,14 @@ impl Mountable for UnitRepr {
#[derive(Clone, Copy, Debug)]
pub struct Unit;
impl IntoNode for Unit {
impl IntoView for Unit {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "<() />", skip_all)
)]
fn into_node(self, _: leptos_reactive::Scope) -> crate::Node {
fn into_view(self, _: leptos_reactive::Scope) -> crate::View {
let component = UnitRepr::default();
Node::CoreComponent(CoreComponent::Unit(component))
View::CoreComponent(CoreComponent::Unit(component))
}
}

View file

@ -1,8 +1,8 @@
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::events::*;
use crate::{
components::DynChild, ev::EventDescriptor, Element, Fragment, IntoNode, Node,
Text,
components::DynChild, ev::EventDescriptor, Element, Fragment, IntoView, Text,
View,
};
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use crate::{mount_child, MountKind};
@ -52,8 +52,7 @@ pub trait IntoElement: IntoElementBounds {
}
}
/// Represents potentially any element, which you can change
/// at any time before calling [`HtmlElement::into_node`].
/// Represents potentially any element.
#[derive(Clone, Debug)]
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), derive(educe::Educe))]
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), educe(Deref))]
@ -124,7 +123,7 @@ cfg_if! {
pub(crate) attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
#[educe(Debug(ignore))]
#[allow(clippy::type_complexity)]
pub(crate) children: SmallVec<[Box<dyn FnOnce(Scope) -> Node>; 4]>,
pub(crate) children: SmallVec<[Box<dyn FnOnce(Scope) -> View>; 4]>,
}
}
}
@ -418,11 +417,11 @@ impl<El: IntoElement> HtmlElement<El> {
}
/// Inserts a child into this element.
pub fn child<C: IntoNode + 'static>(mut self, child: C) -> Self {
pub fn child<C: IntoView + 'static>(mut self, child: C) -> Self {
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
{
let child = child.into_node(self.cx);
let child = child.into_view(self.cx);
mount_child(MountKind::Append(self.element.get_element()), &child)
}
@ -440,11 +439,11 @@ impl<El: IntoElement> HtmlElement<El> {
pub fn dyn_child<CF, N>(mut self, child_fn: CF) -> Self
where
CF: Fn() -> N + 'static,
N: IntoNode,
N: IntoView,
{
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
mount_child(MountKind::Append(self.element.get_element()), &DynChild::new(child_fn).into_node(self.cx))
mount_child(MountKind::Append(self.element.get_element()), &DynChild::new(child_fn).into_view(self.cx))
} else {
self
.children
@ -456,12 +455,12 @@ impl<El: IntoElement> HtmlElement<El> {
}
}
impl<El: IntoElement> IntoNode for HtmlElement<El> {
impl<El: IntoElement> IntoView for HtmlElement<El> {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<HtmlElement />", skip_all, fields(tag = %self.element.name())))]
fn into_node(self, cx: Scope) -> Node {
fn into_view(self, cx: Scope) -> View {
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
Node::Element(Element::new(self.element))
View::Element(Element::new(self.element))
} else {
let Self { element, attrs, children, .. } = self;
let mut element = Element::new(element);
@ -473,31 +472,31 @@ impl<El: IntoElement> IntoNode for HtmlElement<El> {
element.attrs = attrs;
element.children.extend(children);
Node::Element(element)
View::Element(element)
}
}
}
}
impl<El: IntoElement> IntoNode for Vec<HtmlElement<El>> {
impl<El: IntoElement> IntoView for Vec<HtmlElement<El>> {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "Vec<HtmlElement>", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
Fragment::new(self.into_iter().map(|el| el.into_node(cx)).collect())
.into_node(cx)
fn into_view(self, cx: Scope) -> View {
Fragment::new(self.into_iter().map(|el| el.into_view(cx)).collect())
.into_view(cx)
}
}
impl<El: IntoElement, const N: usize> IntoNode for [HtmlElement<El>; N] {
impl<El: IntoElement, const N: usize> IntoView for [HtmlElement<El>; N] {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "[HtmlElement; N]", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
Fragment::new(self.into_iter().map(|el| el.into_node(cx)).collect())
.into_node(cx)
fn into_view(self, cx: Scope) -> View {
Fragment::new(self.into_iter().map(|el| el.into_view(cx)).collect())
.into_view(cx)
}
}
@ -514,9 +513,9 @@ pub fn custom<El: IntoElement>(cx: Scope, el: El) -> HtmlElement<Custom> {
}
/// Creates a text node.
pub fn text(text: impl Into<Cow<'static, str>>) -> Node {
pub fn text(text: impl Into<Cow<'static, str>>) -> View {
let text = Text::new(text.into());
Node::Text(text)
View::Text(text)
}
macro_rules! generate_html_tags {
@ -722,7 +721,7 @@ impl<El: IntoElement> HtmlElement<El> {
let child = child.into_child(cx);
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
mount_child(MountKind::Append(self.element.get_element()), &child.into_node(cx))
mount_child(MountKind::Append(self.element.get_element()), &child.into_view(cx))
}
else {
self.children.push(Box::new(move |cx| child.into_node(cx)));

View file

@ -42,10 +42,10 @@ static COMMENT: LazyCell<web_sys::Node> =
static RANGE: LazyCell<web_sys::Range> =
LazyCell::new(|| web_sys::Range::new().unwrap());
/// Converts the value into a [`Node`].
pub trait IntoNode {
/// Converts the value into [`Node`].
fn into_node(self, cx: Scope) -> Node;
/// Converts the value into a [`View`].
pub trait IntoView {
/// Converts the value into [`View`].
fn into_view(self, cx: Scope) -> View;
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
@ -63,44 +63,44 @@ trait Mountable {
fn get_opening_node(&self) -> web_sys::Node;
}
impl IntoNode for () {
impl IntoView for () {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "<() />", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
Unit.into_node(cx)
fn into_view(self, cx: Scope) -> View {
Unit.into_view(cx)
}
}
impl<T> IntoNode for Option<T>
impl<T> IntoView for Option<T>
where
T: IntoNode,
T: IntoView,
{
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "Option<T>", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
fn into_view(self, cx: Scope) -> View {
if let Some(t) = self {
t.into_node(cx)
t.into_view(cx)
} else {
Unit.into_node(cx)
Unit.into_view(cx)
}
}
}
impl<F, N> IntoNode for F
impl<F, N> IntoView for F
where
F: Fn() -> N + 'static,
N: IntoNode,
N: IntoView,
{
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "Fn() -> N", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
DynChild::new(self).into_node(cx)
fn into_view(self, cx: Scope) -> View {
DynChild::new(self).into_view(cx)
}
}
@ -120,15 +120,15 @@ cfg_if! {
name: Cow<'static, str>,
is_void: bool,
attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
children: Vec<Node>,
children: Vec<View>,
}
}
}
impl IntoNode for Element {
impl IntoView for Element {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<Element />", skip_all, fields(tag = %self.name)))]
fn into_node(self, _: Scope) -> Node {
Node::Element(self)
fn into_view(self, _: Scope) -> View {
View::Element(self)
}
}
@ -191,10 +191,10 @@ pub struct Text {
content: Cow<'static, str>,
}
impl IntoNode for Text {
impl IntoView for Text {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "#text", skip_all, fields(content = %self.content)))]
fn into_node(self, _: Scope) -> Node {
Node::Text(self)
fn into_view(self, _: Scope) -> View {
View::Text(self)
}
}
@ -213,9 +213,9 @@ impl Text {
}
}
/// A leptos Node.
/// A leptos view which can be mounted to the DOM.
#[derive(Debug)]
pub enum Node {
pub enum View {
/// HTML element node.
Element(Element),
/// HTML text node.
@ -226,42 +226,42 @@ pub enum Node {
CoreComponent(CoreComponent),
}
/// The default [`Node`] is the [`Unit`] core-component.
impl Default for Node {
/// The default [`View`] is the [`Unit`] core-component.
impl Default for View {
fn default() -> Self {
Self::CoreComponent(Default::default())
}
}
impl IntoNode for Node {
impl IntoView for View {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "Node", skip_all, fields(kind = self.kind_name())))]
fn into_node(self, _: Scope) -> Node {
fn into_view(self, _: Scope) -> View {
self
}
}
impl IntoNode for Vec<Node> {
impl IntoView for Vec<View> {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "Vec<Node>", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
Fragment::new(self).into_node(cx)
fn into_view(self, cx: Scope) -> View {
Fragment::new(self).into_view(cx)
}
}
impl<const N: usize> IntoNode for [Node; N] {
impl<const N: usize> IntoView for [View; N] {
#[cfg_attr(
debug_assertions,
instrument(level = "trace", name = "[Node; N]", skip_all)
)]
fn into_node(self, cx: Scope) -> Node {
Fragment::new(self.into_iter().collect()).into_node(cx)
fn into_view(self, cx: Scope) -> View {
Fragment::new(self.into_iter().collect()).into_view(cx)
}
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
impl Mountable for Node {
impl Mountable for View {
fn get_mountable_node(&self) -> web_sys::Node {
match self {
Self::Element(element) => {
@ -291,7 +291,7 @@ impl Mountable for Node {
}
}
impl Node {
impl View {
fn kind_name(&self) -> &'static str {
match self {
Self::Component(..) => "Component",
@ -359,7 +359,7 @@ enum MountKind<'a> {
pub fn mount_to_body<F, N>(f: F)
where
F: FnOnce(Scope) -> N + 'static,
N: IntoNode,
N: IntoView,
{
mount_to(crate::document().body().expect("body element to exist"), f)
}
@ -369,12 +369,12 @@ where
pub fn mount_to<F, N>(parent: web_sys::HtmlElement, f: F)
where
F: FnOnce(Scope) -> N + 'static,
N: IntoNode,
N: IntoView,
{
let disposer = leptos_reactive::create_scope(
leptos_reactive::create_runtime(),
move |cx| {
let node = f(cx).into_node(cx);
let node = f(cx).into_view(cx);
parent.append_child(&node.get_mountable_node()).unwrap();

View file

@ -1,62 +1,70 @@
use std::{cell::{OnceCell, RefCell}, hash::Hash, rc::Rc};
use crate::{
text, Component, ComponentRepr, DynChild, EachKey, Element, Fragment,
HtmlElement, IntoElement, IntoView, Text, Unit, View,
};
use cfg_if::cfg_if;
use leptos_reactive::{Scope, create_effect};
use crate::{IntoNode, ComponentRepr, EachKey, Node, HtmlElement, Text, Element, Fragment, Unit, text, DynChild, IntoElement, Component};
use leptos_reactive::{create_effect, Scope};
use std::{
cell::{OnceCell, RefCell},
hash::Hash,
rc::Rc,
};
pub enum Child {
/// A (presumably reactive) function, which will be run inside an effect to do targeted updates to the node.
Fn(Box<RefCell<dyn FnMut() -> Child>>),
/// Content for a text node.
Text(String),
/// A generic node (a text node, comment, or element.)
Node(Node),
/// Nothing
Unit
/// A (presumably reactive) function, which will be run inside an effect to do targeted updates to the node.
Fn(Box<RefCell<dyn FnMut() -> Child>>),
/// Content for a text node.
Text(String),
/// A generic node (a text node, comment, or element.)
Node(View),
/// Nothing
Unit,
}
impl IntoNode for Child {
fn into_node(self, cx: Scope) -> Node {
match self {
Child::Node(node) => node,
Child::Unit => Unit.into_node(cx),
Child::Text(data) => text(data),
Child::Fn(f) => DynChild::new(move || {
let mut value = (f.borrow_mut())();
while let Child::Fn(f) = value {
value = (f.borrow_mut())();
}
value.into_node(cx)
}).into_node(cx)
}
impl IntoView for Child {
fn into_view(self, cx: Scope) -> View {
match self {
Child::Node(node) => node,
Child::Unit => Unit.into_view(cx),
Child::Text(data) => text(data),
Child::Fn(f) => DynChild::new(move || {
let mut value = (f.borrow_mut())();
while let Child::Fn(f) = value {
value = (f.borrow_mut())();
}
value.into_view(cx)
})
.into_view(cx),
}
}
}
pub trait IntoChild {
fn into_child(self, cx: Scope) -> Child;
fn into_child(self, cx: Scope) -> Child;
}
impl IntoChild for Node {
fn into_child(self, _cx: Scope) -> Child {
Child::Node(self)
}
impl IntoChild for View {
fn into_child(self, _cx: Scope) -> Child {
Child::Node(self)
}
}
impl IntoChild for String {
fn into_child(self, _cx: Scope) -> Child {
Child::Text(self)
}
fn into_child(self, _cx: Scope) -> Child {
Child::Text(self)
}
}
impl<T> IntoChild for Option<T>
where
T: IntoChild,
T: IntoChild,
{
fn into_child(self, cx: Scope) -> Child {
match self {
Some(val) => val.into_child(cx),
None => Child::Unit,
}
fn into_child(self, cx: Scope) -> Child {
match self {
Some(val) => val.into_child(cx),
None => Child::Unit,
}
}
}
impl<IF, I, T, EF, N, KF, K> IntoChild for EachKey<IF, I, T, EF, N, KF, K>
@ -64,68 +72,67 @@ where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + 'static,
N: IntoNode,
N: IntoView,
KF: Fn(&T) -> K + 'static,
K: Eq + Hash + 'static,
T: 'static,
{
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_node(cx))
}
{
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_view(cx))
}
}
impl<T, U> IntoChild for T
where
T: FnMut() -> U + 'static,
U: IntoChild,
T: FnMut() -> U + 'static,
U: IntoChild,
{
fn into_child(mut self, cx: Scope) -> Child {
let modified_fn = Box::new(RefCell::new(move || (self)().into_child(cx)));
Child::Fn(modified_fn)
}
fn into_child(mut self, cx: Scope) -> Child {
let modified_fn = Box::new(RefCell::new(move || (self)().into_child(cx)));
Child::Fn(modified_fn)
}
}
macro_rules! node_type {
($child_type:ty) => {
impl IntoChild for $child_type {
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_node(cx))
}
}
};
($child_type:ty) => {
impl IntoChild for $child_type {
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_view(cx))
}
}
};
}
node_type!(());
node_type!(Element);
node_type!(Text);
node_type!(Vec<Node>);
node_type!(Vec<View>);
node_type!(Fragment);
node_type!(ComponentRepr);
impl<El: IntoElement> IntoChild for HtmlElement<El> {
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_node(cx))
}
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_view(cx))
}
}
impl<F> IntoChild for Component<F>
where
F: FnOnce(Scope) -> Node,
F: FnOnce(Scope) -> View,
{
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_node(cx))
}
fn into_child(self, cx: Scope) -> Child {
Child::Node(self.into_view(cx))
}
}
macro_rules! text_type {
($child_type:ty) => {
impl IntoChild for $child_type {
fn into_child(self, cx: Scope) -> Child {
Child::Text(self.to_string().into())
}
}
};
($child_type:ty) => {
impl IntoChild for $child_type {
fn into_child(self, cx: Scope) -> Child {
Child::Text(self.to_string().into())
}
}
};
}
text_type!(&String);
@ -145,4 +152,4 @@ text_type!(i128);
text_type!(f32);
text_type!(f64);
text_type!(char);
text_type!(bool);
text_type!(bool);

View file

@ -1,8 +1,6 @@
use leptos_reactive::{
create_rw_signal, RwSignal, Scope
};
use leptos_reactive::{create_rw_signal, RwSignal, Scope};
/// Contains a shared reference to a DOM node creating while using the [view](leptos::view)
/// Contains a shared reference to a DOM node creating while using the `view`
/// macro to create your UI.
///
/// ```
@ -34,27 +32,27 @@ use leptos_reactive::{
pub struct NodeRef(RwSignal<Option<web_sys::Element>>);
impl NodeRef {
/// Creates an empty reference.
pub fn new(cx: Scope) -> Self {
Self(create_rw_signal(cx, None))
}
/// Creates an empty reference.
pub fn new(cx: Scope) -> Self {
Self(create_rw_signal(cx, None))
}
/// Gets the element that is currently stored in the reference.
///
/// This tracks reactively, so that node references can be used in effects.
/// Initially, the value will be `None`, but once it is loaded the effect
/// will rerun and its value will be `Some(Element)`.
pub fn get(&self) -> Option<web_sys::Element> {
self.0.get()
}
/// Gets the element that is currently stored in the reference.
///
/// This tracks reactively, so that node references can be used in effects.
/// Initially, the value will be `None`, but once it is loaded the effect
/// will rerun and its value will be `Some(Element)`.
pub fn get(&self) -> Option<web_sys::Element> {
self.0.get()
}
#[doc(hidden)]
/// Loads an element into the reference. This tracks reactively,
/// so that effects that use the node reference will rerun once it is loaded,
/// i.e., effects can be forward-declared.
pub fn load(&self, node: &web_sys::Element) {
self.0.set(Some(node.clone()))
}
#[doc(hidden)]
/// Loads an element into the reference. This tracks reactively,
/// so that effects that use the node reference will rerun once it is loaded,
/// i.e., effects can be forward-declared.
pub fn load(&self, node: &web_sys::Element) {
self.0.set(Some(node.clone()))
}
}
cfg_if::cfg_if! {