123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797 |
- //! Helpers for building virtual DOM VNodes.
- use std::{
- any::Any,
- borrow::BorrowMut,
- cell::{Cell, RefCell},
- fmt::Arguments,
- intrinsics::transmute,
- u128,
- };
- use crate::{
- events::VirtualEvent,
- innerlude::{Properties, VComponent, FC},
- nodes::{Attribute, Listener, NodeKey, VNode},
- prelude::{VElement, VFragment},
- virtual_dom::{RealDomNode, Scope},
- };
- /// A virtual DOM element builder.
- ///
- /// Typically constructed with element-specific constructors, eg the `div`
- /// function for building `<div>` elements or the `button` function for building
- /// `<button>` elements.
- #[derive(Debug)]
- pub struct ElementBuilder<'a, 'b, Listeners, Attributes, Children>
- where
- Listeners: 'a + AsRef<[Listener<'a>]>,
- Attributes: 'a + AsRef<[Attribute<'a>]>,
- Children: 'a + AsRef<[VNode<'a>]>,
- {
- cx: &'b NodeFactory<'a>,
- key: NodeKey<'a>,
- tag_name: &'static str,
- // tag_name: &'a str,
- listeners: Listeners,
- attributes: Attributes,
- children: Children,
- namespace: Option<&'static str>,
- }
- impl<'a, 'b>
- ElementBuilder<
- 'a,
- 'b,
- bumpalo::collections::Vec<'a, Listener<'a>>,
- bumpalo::collections::Vec<'a, Attribute<'a>>,
- bumpalo::collections::Vec<'a, VNode<'a>>,
- >
- {
- /// Create a new `ElementBuilder` for an element with the given tag name.
- ///
- /// In general, only use this constructor if the tag is dynamic (i.e. you
- /// might build a `<div>` or you might build a `<span>` and you don't know
- /// until runtime). Prefer using the tag-specific constructors instead:
- /// `div(bump)` or `span(bump)`, etc.
- ///
- /// # Example
- ///
- /// ```
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// let tag_name = if flip_coin() {
- /// "div"
- /// } else {
- /// "span"
- /// };
- ///
- /// let my_element_builder = ElementBuilder::new(&b, tag_name);
- /// # fn flip_coin() -> bool { true }
- /// ```
- pub fn new(cx: &'b NodeFactory<'a>, tag_name: &'static str) -> Self {
- let bump = cx.bump();
- ElementBuilder {
- cx,
- key: NodeKey::NONE,
- tag_name,
- listeners: bumpalo::collections::Vec::new_in(bump),
- attributes: bumpalo::collections::Vec::new_in(bump),
- children: bumpalo::collections::Vec::new_in(bump),
- namespace: None,
- }
- }
- }
- impl<'a, 'b, Listeners, Attributes, Children>
- ElementBuilder<'a, 'b, Listeners, Attributes, Children>
- where
- Listeners: 'a + AsRef<[Listener<'a>]>,
- Attributes: 'a + AsRef<[Attribute<'a>]>,
- Children: 'a + AsRef<[VNode<'a>]>,
- {
- /// Set the listeners for this element.
- ///
- /// You can use this method to customize the backing storage for listeners,
- /// for example to use a fixed-size array instead of the default
- /// dynamically-sized `bumpalo::collections::Vec`.
- ///
- /// Any listeners already added to the builder will be overridden.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// // Create a `<div>` with a fixed-size array of two listeners.
- /// let my_div = div(&b)
- /// .listeners([
- /// on(&b, "click", |root, vdom, event| {
- /// // ...
- /// }),
- /// on(&b, "dblclick", |root, vdom, event| {
- /// // ...
- /// }),
- /// ])
- /// .finish();
- /// ```
- #[inline]
- pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, 'b, L, Attributes, Children>
- where
- L: 'a + AsRef<[Listener<'a>]>,
- {
- ElementBuilder {
- cx: self.cx,
- key: self.key,
- tag_name: self.tag_name,
- listeners,
- attributes: self.attributes,
- children: self.children,
- namespace: self.namespace,
- }
- }
- /// Set the attributes for this element.
- ///
- /// You can use this method to customize the backing storage for attributes,
- /// for example to use a fixed-size array instead of the default
- /// dynamically-sized `bumpalo::collections::Vec`.
- ///
- /// Any attributes already added to the builder will be overridden.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump, Attribute};
- ///
- /// let b = Bump::new();
- ///
- /// // Create a `<div>` with a fixed-size array of two attributes.
- /// let my_div = div(&b)
- /// .attributes([
- /// attr("id", "my-div"),
- /// attr("class", "notification"),
- /// ])
- /// .finish();
- /// ```
- #[inline]
- pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, 'b, Listeners, A, Children>
- where
- A: 'a + AsRef<[Attribute<'a>]>,
- {
- ElementBuilder {
- cx: self.cx,
- key: self.key,
- tag_name: self.tag_name,
- listeners: self.listeners,
- attributes,
- children: self.children,
- namespace: self.namespace,
- }
- }
- /// Set the children for this element.
- ///
- /// You can use this method to customize the backing storage for children,
- /// for example to use a fixed-size array instead of the default
- /// dynamically-sized `bumpalo::collections::Vec`.
- ///
- /// Any children already added to the builder will be overridden.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// // Create a `<div>` with a fixed-size array of two `<span>` children.
- /// let my_div = div(&b)
- /// .children([
- /// span(&b).finish(),
- /// span(&b).finish(),
- /// ])
- /// .finish();
- /// ```
- #[inline]
- pub fn children<C>(self, children: C) -> ElementBuilder<'a, 'b, Listeners, Attributes, C>
- where
- C: 'a + AsRef<[VNode<'a>]>,
- {
- ElementBuilder {
- cx: self.cx,
- key: self.key,
- tag_name: self.tag_name,
- listeners: self.listeners,
- attributes: self.attributes,
- children,
- namespace: self.namespace,
- }
- }
- /// Set the namespace for this element.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// // Create a `<td>` tag with an xhtml namespace
- /// let my_td = td(&b)
- /// .namespace(Some("http://www.w3.org/1999/xhtml"))
- /// .finish();
- /// ```
- #[inline]
- pub fn namespace(self, namespace: Option<&'static str>) -> Self {
- ElementBuilder {
- cx: self.cx,
- key: self.key,
- tag_name: self.tag_name,
- listeners: self.listeners,
- attributes: self.attributes,
- children: self.children,
- namespace,
- }
- }
- /// Set this element's key.
- ///
- /// When diffing sets of siblings, if an old sibling and new sibling share a
- /// key, then they will always reuse the same physical DOM VNode. This is
- /// important when using CSS animations, web components, third party JS, or
- /// anything else that makes the diffing implementation observable.
- ///
- /// Do not use keys if such a scenario does not apply. Keyed diffing is
- /// generally more expensive than not, since it is putting greater
- /// constraints on the diffing algorithm.
- ///
- /// # Invariants You Must Uphold
- ///
- /// The key may not be `u32::MAX`, which is a reserved key value.
- ///
- /// Keys must be unique among siblings.
- ///
- /// All sibling VNodes must be keyed, or they must all not be keyed. You may
- /// not mix keyed and unkeyed siblings.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// let my_li = li(&b)
- /// .key(1337)
- /// .finish();
- /// ```
- #[inline]
- pub fn key(mut self, key: &'a str) -> Self {
- self.key = NodeKey(Some(key));
- self
- }
- pub fn key2(mut self, args: Arguments) -> Self {
- let key = match args.as_str() {
- Some(static_str) => static_str,
- None => {
- use bumpalo::core_alloc::fmt::Write;
- let mut s = bumpalo::collections::String::new_in(self.cx.bump());
- s.write_fmt(args).unwrap();
- s.into_bump_str()
- }
- };
- self.key = NodeKey(Some(key));
- self
- }
- /// Create the virtual DOM VNode described by this builder.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump, VNode};
- ///
- /// let b = Bump::new();
- ///
- /// // Start with a builder...
- /// let builder: ElementBuilder<_, _, _> = div(&b);
- ///
- /// // ...and finish it to create a virtual DOM VNode!
- /// let my_div: VNode = builder.finish();
- /// ```
- #[inline]
- pub fn finish(self) -> VNode<'a> {
- let bump = self.cx.bump();
- let children: &'a Children = bump.alloc(self.children);
- let children: &'a [VNode<'a>] = children.as_ref();
- let listeners: &'a Listeners = bump.alloc(self.listeners);
- let listeners: &'a [Listener<'a>] = listeners.as_ref();
- let attributes: &'a Attributes = bump.alloc(self.attributes);
- let attributes: &'a [Attribute<'a>] = attributes.as_ref();
- VNode::element(
- bump,
- self.key,
- self.tag_name,
- listeners,
- attributes,
- children,
- self.namespace,
- )
- }
- }
- impl<'a, 'b, Attributes, Children>
- ElementBuilder<'a, 'b, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
- where
- Attributes: 'a + AsRef<[Attribute<'a>]>,
- Children: 'a + AsRef<[VNode<'a>]>,
- {
- /// Add a new event listener to this element.
- ///
- /// The `event` string specifies which event will be listened for. The
- /// `callback` function is the function that will be invoked if the
- /// specified event occurs.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// // A button that does something when clicked!
- /// let my_button = button(&b)
- /// .on("click", |event| {
- /// // ...
- /// })
- /// .finish();
- /// ```
- pub fn on(self, event: &'static str, callback: impl Fn(VirtualEvent) + 'a) -> Self {
- let bump = &self.cx.bump();
- let listener = Listener {
- event,
- callback: bump.alloc(callback),
- scope: self.cx.scope_ref.arena_idx,
- mounted_node: bump.alloc(Cell::new(RealDomNode::empty())),
- };
- self.add_listener(listener)
- }
- pub fn add_listener(mut self, listener: Listener<'a>) -> Self {
- self.listeners.push(listener);
- // bump the context id forward
- let id = self.cx.listener_id.get();
- self.cx.listener_id.set(id + 1);
- // Add this listener to the context list
- // This casts the listener to a self-referential pointer
- // This is okay because the bump arena is stable
- self.listeners.last().map(|g| {
- let r = unsafe { std::mem::transmute::<&Listener<'a>, &Listener<'static>>(g) };
- self.cx
- .scope_ref
- .listeners
- .borrow_mut()
- .push((r.mounted_node as *const _, r.callback as *const _));
- });
- self
- }
- }
- impl<'a, 'b, Listeners, Children>
- ElementBuilder<'a, 'b, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
- where
- Listeners: 'a + AsRef<[Listener<'a>]>,
- Children: 'a + AsRef<[VNode<'a>]>,
- {
- /// Add a new attribute to this element.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// // Create the `<div id="my-div"/>` element.
- /// let my_div = div(&b).attr("id", "my-div").finish();
- /// ```
- pub fn attr(mut self, name: &'static str, args: std::fmt::Arguments) -> Self {
- let value = match args.as_str() {
- Some(static_str) => static_str,
- None => {
- use bumpalo::core_alloc::fmt::Write;
- let mut s = bumpalo::collections::String::new_in(self.cx.bump());
- s.write_fmt(args).unwrap();
- s.into_bump_str()
- }
- };
- self.attributes.push(Attribute { name, value });
- self
- }
- /// Conditionally add a "boolean-style" attribute to this element.
- ///
- /// If the `should_add` parameter is true, then adds an attribute with the
- /// given `name` and an empty string value. If the `should_add` parameter is
- /// false, then the attribute is not added.
- ///
- /// This method is useful for attributes whose semantics are defined by
- /// whether or not the attribute is present or not, and whose value is
- /// ignored. Example attributes like this include:
- ///
- /// * `checked`
- /// * `hidden`
- /// * `selected`
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- /// use js_sys::Math;
- ///
- /// let b = Bump::new();
- ///
- /// // Create the `<div>` that is randomly hidden 50% of the time.
- /// let my_div = div(&b)
- /// .bool_attr("hidden", Math::random() >= 0.5)
- /// .finish();
- /// ```
- pub fn bool_attr(mut self, name: &'static str, should_add: bool) -> Self {
- if should_add {
- self.attributes.push(Attribute { name, value: "" });
- }
- self
- }
- }
- impl<'a, 'b, Listeners, Attributes>
- ElementBuilder<'a, 'b, Listeners, Attributes, bumpalo::collections::Vec<'a, VNode<'a>>>
- where
- Listeners: 'a + AsRef<[Listener<'a>]>,
- Attributes: 'a + AsRef<[Attribute<'a>]>,
- {
- /// Add a new child to this element.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- /// use js_sys::Math;
- ///
- /// let b = Bump::new();
- ///
- /// // Create `<p><span></span></p>`.
- /// let my_div = p(&b)
- /// .child(span(&b).finish())
- /// .finish();
- /// ```
- #[inline]
- pub fn child(mut self, child: VNode<'a>) -> Self {
- self.children.push(child);
- self
- }
- /// Add multiple children to this element from an iterator.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::{builder::*, bumpalo::Bump};
- ///
- /// let b = Bump::new();
- ///
- /// let my_div = p(&b)
- /// .iter_child((0..10).map(|f| span(&b).finish())
- /// .finish();
- /// ```
- pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
- let len_before = self.children.len();
- for item in nodes {
- let child = item.into_vnode(&self.cx);
- self.children.push(child);
- }
- if cfg!(debug_assertions) {
- if self.children.len() > len_before + 1 {
- if self.children.last().unwrap().key().is_none() {
- log::error!(
- r#"
- Warning: Each child in an array or iterator should have a unique "key" prop.
- Not providing a key will lead to poor performance with lists.
- See docs.rs/dioxus for more information.
- ---
- To help you identify where this error is coming from, we've generated a backtrace.
- "#,
- );
- }
- }
- }
- self
- }
- }
- impl<'a> IntoIterator for VNode<'a> {
- type Item = VNode<'a>;
- type IntoIter = std::iter::Once<Self::Item>;
- fn into_iter(self) -> Self::IntoIter {
- std::iter::once(self)
- }
- }
- impl<'a> IntoVNode<'a> for VNode<'a> {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
- self
- }
- }
- impl<'a> IntoVNode<'a> for &VNode<'a> {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
- // cloning is cheap since vnodes are just references into bump arenas
- self.clone()
- }
- }
- pub trait IntoVNode<'a> {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a>;
- }
- pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
- where
- G: IntoVNode<'a>,
- {
- }
- impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where
- F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a
- {
- }
- // Wrap the the node-builder closure in a concrete type.
- // ---
- // This is a bit of a hack to implement the IntoVNode trait for closure types.
- pub struct LazyNodes<'a, G>
- where
- G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
- {
- inner: G,
- _p: std::marker::PhantomData<&'a ()>,
- }
- impl<'a, G> LazyNodes<'a, G>
- where
- G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
- {
- pub fn new(f: G) -> Self {
- Self {
- inner: f,
- _p: std::default::Default::default(),
- }
- }
- }
- // Cover the cases where nodes are used by macro.
- // Likely used directly.
- // ---
- // let nodes = rsx!{ ... };
- // rsx! { {nodes } }
- impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
- where
- G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
- {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
- (self.inner)(cx)
- }
- }
- // Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator
- impl<'a, G> IntoIterator for LazyNodes<'a, G>
- where
- G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
- {
- type Item = Self;
- type IntoIter = std::iter::Once<Self::Item>;
- fn into_iter(self) -> Self::IntoIter {
- std::iter::once(self)
- }
- }
- impl<'a> IntoVNode<'a> for () {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
- todo!();
- VNode::Suspended {
- real: Cell::new(RealDomNode::empty()),
- }
- }
- }
- impl<'a> IntoVNode<'a> for Option<()> {
- fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
- todo!();
- VNode::Suspended {
- real: Cell::new(RealDomNode::empty()),
- }
- }
- }
- /// Construct a text VNode.
- ///
- /// This is `dioxus`'s virtual DOM equivalent of `document.createTextVNode`.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use dioxus::builder::*;
- ///
- /// let my_text = text("hello, dioxus!");
- /// ```
- #[inline]
- pub fn text<'a>(contents: &'a str) -> VNode<'a> {
- VNode::text(contents)
- }
- pub fn text2<'a>(contents: bumpalo::collections::String<'a>) -> VNode<'a> {
- let f: &'a str = contents.into_bump_str();
- VNode::text(f)
- }
- pub fn text3<'a>(bump: &'a bumpalo::Bump, args: std::fmt::Arguments) -> VNode<'a> {
- // This is a cute little optimization
- //
- // We use format_args! on everything. However, not all textnodes have dynamic content, and thus are completely static.
- // we can just short-circuit to the &'static str version instead of having to allocate in the bump arena.
- //
- // In the most general case, this prevents the need for any string allocations for simple code IE:
- // div {"abc"}
- //
- match args.as_str() {
- Some(static_str) => VNode::text(static_str),
- None => {
- use bumpalo::core_alloc::fmt::Write;
- let mut s = bumpalo::collections::String::new_in(bump);
- s.write_fmt(args).unwrap();
- VNode::text(s.into_bump_str())
- }
- }
- }
- /// Construct an attribute for an element.
- ///
- /// # Example
- ///
- /// This example creates the `id="my-id"` for some element like `<div
- /// id="my-id"/>`.
- ///
- /// ```no_run
- /// use dioxus::builder::*;
- ///
- /// let my_id_attr = attr("id", "my-id");
- /// ```
- pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
- Attribute { name, value }
- }
- pub fn virtual_child<'a, T: Properties + 'a>(
- cx: &NodeFactory<'a>,
- f: FC<T>,
- props: T,
- key: Option<&'a str>, // key: NodeKey<'a>,
- children: &'a [VNode<'a>],
- ) -> VNode<'a> {
- // currently concerned about if props have a custom drop implementation
- // might override it with the props macro
- // todo!()
- VNode::Component(
- cx.bump()
- .alloc(crate::nodes::VComponent::new(cx, f, props, key, children)),
- // cx.bump()
- // .alloc(crate::nodes::VComponent::new(f, props, key)),
- )
- }
- pub fn vfragment<'a>(
- cx: &NodeFactory<'a>,
- key: Option<&'a str>, // key: NodeKey<'a>,
- children: &'a [VNode<'a>],
- ) -> VNode<'a> {
- VNode::Fragment(cx.bump().alloc(VFragment::new(key, children)))
- }
- pub struct ChildrenList<'a, 'b> {
- cx: &'b NodeFactory<'a>,
- children: bumpalo::collections::Vec<'a, VNode<'a>>,
- }
- impl<'a, 'b> ChildrenList<'a, 'b> {
- pub fn new(cx: &'b NodeFactory<'a>) -> Self {
- Self {
- cx,
- children: bumpalo::collections::Vec::new_in(cx.bump()),
- }
- }
- pub fn add_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
- for item in nodes {
- let child = item.into_vnode(&self.cx);
- self.children.push(child);
- }
- self
- }
- pub fn finish(self) -> &'a [VNode<'a>] {
- self.children.into_bump_slice()
- }
- }
- // NodeFactory is used to build VNodes in the component's memory space.
- // This struct adds metadata to the final VNode about listeners, attributes, and children
- #[derive(Clone)]
- pub struct NodeFactory<'a> {
- pub scope_ref: &'a Scope,
- pub listener_id: Cell<usize>,
- // pub listener_id: RefCell<usize>,
- }
- impl<'a> NodeFactory<'a> {
- #[inline]
- pub fn bump(&self) -> &'a bumpalo::Bump {
- &self.scope_ref.cur_frame().bump
- }
- /// Create some text that's allocated along with the other vnodes
- pub fn text(&self, args: Arguments) -> VNode<'a> {
- text3(self.bump(), args)
- }
- /// Create an element builder
- pub fn element<'b, Listeners, Attributes, Children>(
- &'b self,
- tag_name: &'static str,
- ) -> ElementBuilder<
- 'a,
- 'b,
- bumpalo::collections::Vec<'a, Listener<'a>>,
- bumpalo::collections::Vec<'a, Attribute<'a>>,
- bumpalo::collections::Vec<'a, VNode<'a>>,
- > {
- ElementBuilder::new(self, tag_name)
- }
- pub fn child_list(&self) -> ChildrenList {
- ChildrenList::new(&self)
- }
- pub fn fragment_builder<'b>(
- &'b self,
- key: Option<&'a str>,
- builder: impl FnOnce(ChildrenList<'a, 'b>) -> &'a [VNode<'a>],
- ) -> VNode<'a> {
- self.fragment(builder(ChildrenList::new(&self)), key)
- }
- pub fn fragment(&self, children: &'a [VNode<'a>], key: Option<&'a str>) -> VNode<'a> {
- VNode::Fragment(self.bump().alloc(VFragment {
- children,
- key: NodeKey::new_opt(key),
- }))
- }
- }
- use std::fmt::Debug;
- impl Debug for NodeFactory<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- Ok(())
- }
- }
|