@@ -0,0 +1,848 @@
1+//! Helpers for building virtual DOM nodes.
2+
3+use crate::{Attribute, Listener, Node, RootRender, VdomWeak};
4+use bumpalo::Bump;
5+
6+/// A virtual DOM element builder.
7+///
8+/// Typically constructed with element-specific constructors, eg the `div`
9+/// function for building `<div>` elements or the `button` function for building
10+/// `<button>` elements.
11+#[derive(Clone, Debug)]
12+pub struct ElementBuilder<'a, Listeners, Attributes, Children>
13+where
14+ Listeners: 'a + AsRef<[Listener<'a>]>,
15+ Attributes: 'a + AsRef<[Attribute<'a>]>,
16+ Children: 'a + AsRef<[Node<'a>]>,
17+{
18+ bump: &'a Bump,
19+ tag_name: &'a str,
20+ listeners: Listeners,
21+ attributes: Attributes,
22+ children: Children,
23+}
24+
25+impl<'a, Listeners, Attributes, Children> ElementBuilder<'a, Listeners, Attributes, Children>
26+where
27+ Listeners: 'a + AsRef<[Listener<'a>]>,
28+ Attributes: 'a + AsRef<[Attribute<'a>]>,
29+ Children: 'a + AsRef<[Node<'a>]>,
30+{
31+ /// Set the listeners for this element.
32+ ///
33+ /// You can use this method to customize the backing storage for listeners,
34+ /// for example to use a fixed-size array instead of the default
35+ /// dynamically-sized `bumpalo::collections::Vec`.
36+ ///
37+ /// Any listeners already added to the builder will be overridden.
38+ ///
39+ /// # Example
40+ ///
41+ /// ```no_run
42+ /// use dodrio::{builder::*, bumpalo::Bump, on};
43+ ///
44+ /// let b = Bump::new();
45+ ///
46+ /// // Create a `<div>` with a fixed-size array of two listeners.
47+ /// let my_div = div(&b)
48+ /// .listeners([
49+ /// on(&b, "click", |root, vdom, event| {
50+ /// // ...
51+ /// }),
52+ /// on(&b, "dblclick", |root, vdom, event| {
53+ /// // ...
54+ /// }),
55+ /// ])
56+ /// .finish();
57+ /// ```
58+ #[inline]
59+ pub fn listeners<L>(self, listeners: L) -> ElementBuilder<'a, L, Attributes, Children>
60+ where
61+ L: 'a + AsRef<[Listener<'a>]>,
62+ {
63+ ElementBuilder {
64+ bump: self.bump,
65+ tag_name: self.tag_name,
66+ listeners,
67+ attributes: self.attributes,
68+ children: self.children,
69+ }
70+ }
71+
72+ /// Set the attributes for this element.
73+ ///
74+ /// You can use this method to customize the backing storage for attributes,
75+ /// for example to use a fixed-size array instead of the default
76+ /// dynamically-sized `bumpalo::collections::Vec`.
77+ ///
78+ /// Any attributes already added to the builder will be overridden.
79+ ///
80+ /// # Example
81+ ///
82+ /// ```no_run
83+ /// use dodrio::{builder::*, bumpalo::Bump, Attribute};
84+ ///
85+ /// let b = Bump::new();
86+ ///
87+ /// // Create a `<div>` with a fixed-size array of two attributes.
88+ /// let my_div = div(&b)
89+ /// .attributes([
90+ /// Attribute {
91+ /// name: "id",
92+ /// value: "my-div",
93+ /// },
94+ /// Attribute {
95+ /// name: "class",
96+ /// value: "notification",
97+ /// },
98+ /// ])
99+ /// .finish();
100+ /// ```
101+ #[inline]
102+ pub fn attributes<A>(self, attributes: A) -> ElementBuilder<'a, Listeners, A, Children>
103+ where
104+ A: 'a + AsRef<[Attribute<'a>]>,
105+ {
106+ ElementBuilder {
107+ bump: self.bump,
108+ tag_name: self.tag_name,
109+ listeners: self.listeners,
110+ attributes,
111+ children: self.children,
112+ }
113+ }
114+
115+ /// Set the children for this element.
116+ ///
117+ /// You can use this method to customize the backing storage for children,
118+ /// for example to use a fixed-size array instead of the default
119+ /// dynamically-sized `bumpalo::collections::Vec`.
120+ ///
121+ /// Any children already added to the builder will be overridden.
122+ ///
123+ /// # Example
124+ ///
125+ /// ```no_run
126+ /// use dodrio::{builder::*, bumpalo::Bump};
127+ ///
128+ /// let b = Bump::new();
129+ ///
130+ /// // Create a `<div>` with a fixed-size array of two `<span>` children.
131+ /// let my_div = div(&b)
132+ /// .children([
133+ /// span(&b).finish(),
134+ /// span(&b).finish(),
135+ /// ])
136+ /// .finish();
137+ /// ```
138+ #[inline]
139+ pub fn children<C>(self, children: C) -> ElementBuilder<'a, Listeners, Attributes, C>
140+ where
141+ C: 'a + AsRef<[Node<'a>]>,
142+ {
143+ ElementBuilder {
144+ bump: self.bump,
145+ tag_name: self.tag_name,
146+ listeners: self.listeners,
147+ attributes: self.attributes,
148+ children,
149+ }
150+ }
151+
152+ /// Create the virtual DOM node described by this builder.
153+ ///
154+ /// # Example
155+ ///
156+ /// ```no_run
157+ /// use dodrio::{builder::*, bumpalo::Bump, Node};
158+ ///
159+ /// let b = Bump::new();
160+ ///
161+ /// // Start with a builder...
162+ /// let builder: ElementBuilder<_, _, _> = div(&b);
163+ ///
164+ /// // ...and finish it to create a virtual DOM node!
165+ /// let my_div: Node = builder.finish();
166+ /// ```
167+ #[inline]
168+ pub fn finish(self) -> Node<'a> {
169+ Node::element(
170+ self.bump,
171+ self.tag_name,
172+ self.listeners,
173+ self.attributes,
174+ self.children,
175+ )
176+ }
177+}
178+
179+impl<'a, Attributes, Children>
180+ ElementBuilder<'a, bumpalo::collections::Vec<'a, Listener<'a>>, Attributes, Children>
181+where
182+ Attributes: 'a + AsRef<[Attribute<'a>]>,
183+ Children: 'a + AsRef<[Node<'a>]>,
184+{
185+ /// Add a new event listener to this element.
186+ ///
187+ /// The `event` string specifies which event will be listened for. The
188+ /// `callback` function is the function that will be invoked if the
189+ /// specified event occurs.
190+ ///
191+ /// # Example
192+ ///
193+ /// ```no_run
194+ /// use dodrio::{builder::*, bumpalo::Bump};
195+ ///
196+ /// let b = Bump::new();
197+ ///
198+ /// // A button that does something when clicked!
199+ /// let my_button = button(&b)
200+ /// .on("click", |root, vdom, event| {
201+ /// // ...
202+ /// })
203+ /// .finish();
204+ /// ```
205+ #[inline]
206+ pub fn on<F>(mut self, event: &'a str, callback: F) -> Self
207+ where
208+ F: 'static + Fn(&mut dyn RootRender, VdomWeak, web_sys::Event),
209+ {
210+ self.listeners.push(Listener {
211+ event,
212+ callback: self.bump.alloc(callback),
213+ });
214+ self
215+ }
216+}
217+
218+impl<'a, Listeners, Children>
219+ ElementBuilder<'a, Listeners, bumpalo::collections::Vec<'a, Attribute<'a>>, Children>
220+where
221+ Listeners: 'a + AsRef<[Listener<'a>]>,
222+ Children: 'a + AsRef<[Node<'a>]>,
223+{
224+ /// Add a new attribute to this element.
225+ ///
226+ /// # Example
227+ ///
228+ /// ```no_run
229+ /// use dodrio::{builder::*, bumpalo::Bump};
230+ ///
231+ /// let b = Bump::new();
232+ ///
233+ /// // Create the `<div id="my-div"/>` element.
234+ /// let my_div = div(&b).attr("id", "my-div").finish();
235+ /// ```
236+ #[inline]
237+ pub fn attr(mut self, name: &'a str, value: &'a str) -> Self {
238+ self.attributes.push(Attribute { name, value });
239+ self
240+ }
241+
242+ /// Conditionally add a "boolean-style" attribute to this element.
243+ ///
244+ /// If the `should_add` parameter is true, then adds an attribute with the
245+ /// given `name` and an empty string value. If the `should_add` parameter is
246+ /// false, then the attribute is not added.
247+ ///
248+ /// This method is useful for attributes whose semantics are defined by
249+ /// whether or not the attribute is present or not, and whose value is
250+ /// ignored. Example attributes like this include:
251+ ///
252+ /// * `checked`
253+ /// * `hidden`
254+ /// * `selected`
255+ ///
256+ /// # Example
257+ ///
258+ /// ```no_run
259+ /// use dodrio::{builder::*, bumpalo::Bump};
260+ /// use js_sys::Math;
261+ ///
262+ /// let b = Bump::new();
263+ ///
264+ /// // Create the `<div>` that is randomly hidden 50% of the time.
265+ /// let my_div = div(&b)
266+ /// .bool_attr("hidden", Math::random() >= 0.5)
267+ /// .finish();
268+ /// ```
269+ pub fn bool_attr(mut self, name: &'a str, should_add: bool) -> Self {
270+ if should_add {
271+ self.attributes.push(Attribute { name, value: "" });
272+ }
273+ self
274+ }
275+}
276+
277+impl<'a, Listeners, Attributes>
278+ ElementBuilder<'a, Listeners, Attributes, bumpalo::collections::Vec<'a, Node<'a>>>
279+where
280+ Listeners: 'a + AsRef<[Listener<'a>]>,
281+ Attributes: 'a + AsRef<[Attribute<'a>]>,
282+{
283+ /// Add a new child to this element.
284+ ///
285+ /// # Example
286+ ///
287+ /// ```no_run
288+ /// use dodrio::{builder::*, bumpalo::Bump};
289+ /// use js_sys::Math;
290+ ///
291+ /// let b = Bump::new();
292+ ///
293+ /// // Create `<p><span></span></p>`.
294+ /// let my_div = p(&b)
295+ /// .child(span(&b).finish())
296+ /// .finish();
297+ /// ```
298+ #[inline]
299+ pub fn child(mut self, child: Node<'a>) -> Self {
300+ self.children.push(child);
301+ self
302+ }
303+}
304+
305+macro_rules! builder_constructors {
306+ ( $(
307+ $(#[$attr:meta])*
308+ $name:ident;
309+ )* ) => {
310+ $(
311+ $(#[$attr])*
312+ #[inline]
313+ pub fn $name<'a>(
314+ bump: &'a Bump,
315+ ) -> ElementBuilder<
316+ 'a,
317+ bumpalo::collections::Vec<'a, Listener<'a>>,
318+ bumpalo::collections::Vec<'a, Attribute<'a>>,
319+ bumpalo::collections::Vec<'a, Node<'a>>,
320+ > {
321+ ElementBuilder {
322+ bump,
323+ tag_name: stringify!($name),
324+ listeners: bumpalo::collections::Vec::new_in(bump),
325+ attributes: bumpalo::collections::Vec::new_in(bump),
326+ children: bumpalo::collections::Vec::new_in(bump),
327+ }
328+ }
329+ )*
330+ }
331+}
332+
333+// Organized in the same order as
334+// https://developer.mozilla.org/en-US/docs/Web/HTML/Element
335+//
336+// Does not include obsolete elements.
337+builder_constructors! {
338+ // Document metadata
339+
340+ /// Build a
341+ /// [`<base>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base)
342+ /// element.
343+ base;
344+ /// Build a
345+ /// [`<head>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head)
346+ /// element.
347+ head;
348+ /// Build a
349+ /// [`<link>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link)
350+ /// element.
351+ link;
352+ /// Build a
353+ /// [`<meta>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta)
354+ /// element.
355+ meta;
356+ /// Build a
357+ /// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style)
358+ /// element.
359+ style;
360+ /// Build a
361+ /// [`<title>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title)
362+ /// element.
363+ title;
364+
365+ // Sectioning root
366+
367+ /// Build a
368+ /// [`<body>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body)
369+ /// element.
370+ body;
371+
372+ // Content sectioning
373+
374+ /// Build a
375+ /// [`<address>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/address)
376+ /// element.
377+ address;
378+ /// Build a
379+ /// [`<article>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/article)
380+ /// element.
381+ article;
382+ /// Build a
383+ /// [`<aside>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/aside)
384+ /// element.
385+ aside;
386+ /// Build a
387+ /// [`<footer>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/footer)
388+ /// element.
389+ footer;
390+ /// Build a
391+ /// [`<header>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/header)
392+ /// element.
393+ header;
394+ /// Build a
395+ /// [`<h1>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1)
396+ /// element.
397+ h1;
398+ /// Build a
399+ /// [`<h2>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2)
400+ /// element.
401+ h2;
402+ /// Build a
403+ /// [`<h3>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3)
404+ /// element.
405+ h3;
406+ /// Build a
407+ /// [`<h4>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4)
408+ /// element.
409+ h4;
410+ /// Build a
411+ /// [`<h5>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h5)
412+ /// element.
413+ h5;
414+ /// Build a
415+ /// [`<h6>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6)
416+ /// element.
417+ h6;
418+ /// Build a
419+ /// [`<hgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hgroup)
420+ /// element.
421+ hgroup;
422+ /// Build a
423+ /// [`<main>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main)
424+ /// element.
425+ main;
426+ /// Build a
427+ /// [`<nav>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav)
428+ /// element.
429+ nav;
430+ /// Build a
431+ /// [`<section>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section)
432+ /// element.
433+ section;
434+
435+ // Text content
436+
437+ /// Build a
438+ /// [`<blockquote>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote)
439+ /// element.
440+ blockquote;
441+ /// Build a
442+ /// [`<dd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dd)
443+ /// element.
444+ dd;
445+ /// Build a
446+ /// [`<div>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div)
447+ /// element.
448+ div;
449+ /// Build a
450+ /// [`<dl>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl)
451+ /// element.
452+ dl;
453+ /// Build a
454+ /// [`<dt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt)
455+ /// element.
456+ dt;
457+ /// Build a
458+ /// [`<figcaption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figcaption)
459+ /// element.
460+ figcaption;
461+ /// Build a
462+ /// [`<figure>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure)
463+ /// element.
464+ figure;
465+ /// Build a
466+ /// [`<hr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr)
467+ /// element.
468+ hr;
469+ /// Build a
470+ /// [`<li>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/li)
471+ /// element.
472+ li;
473+ /// Build a
474+ /// [`<ol>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol)
475+ /// element.
476+ ol;
477+ /// Build a
478+ /// [`<p>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/p)
479+ /// element.
480+ p;
481+ /// Build a
482+ /// [`<pre>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre)
483+ /// element.
484+ pre;
485+ /// Build a
486+ /// [`<ul>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul)
487+ /// element.
488+ ul;
489+
490+ // Inline text semantics
491+
492+ /// Build a
493+ /// [`<a>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a)
494+ /// element.
495+ a;
496+ /// Build a
497+ /// [`<abbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/abbr)
498+ /// element.
499+ abbr;
500+ /// Build a
501+ /// [`<b>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/b)
502+ /// element.
503+ b;
504+ /// Build a
505+ /// [`<bdi>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi)
506+ /// element.
507+ bdi;
508+ /// Build a
509+ /// [`<bdo>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdo)
510+ /// element.
511+ bdo;
512+ /// Build a
513+ /// [`<br>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br)
514+ /// element.
515+ br;
516+ /// Build a
517+ /// [`<cite>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/cite)
518+ /// element.
519+ cite;
520+ /// Build a
521+ /// [`<code>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/code)
522+ /// element.
523+ code;
524+ /// Build a
525+ /// [`<data>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/data)
526+ /// element.
527+ data;
528+ /// Build a
529+ /// [`<dfn>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dfn)
530+ /// element.
531+ dfn;
532+ /// Build a
533+ /// [`<em>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/em)
534+ /// element.
535+ em;
536+ /// Build a
537+ /// [`<i>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/i)
538+ /// element.
539+ i;
540+ /// Build a
541+ /// [`<kbd>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/kbd)
542+ /// element.
543+ kbd;
544+ /// Build a
545+ /// [`<mark>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/mark)
546+ /// element.
547+ mark;
548+ /// Build a
549+ /// [`<q>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q)
550+ /// element.
551+ q;
552+ /// Build a
553+ /// [`<rb>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rb)
554+ /// element.
555+ rb;
556+ /// Build a
557+ /// [`<rp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp)
558+ /// element.
559+ rp;
560+ /// Build a
561+ /// [`<rt>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt)
562+ /// element.
563+ rt;
564+ /// Build a
565+ /// [`<rtc>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rtc)
566+ /// element.
567+ rtc;
568+ /// Build a
569+ /// [`<ruby>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby)
570+ /// element.
571+ ruby;
572+ /// Build a
573+ /// [`<s>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/s)
574+ /// element.
575+ s;
576+ /// Build a
577+ /// [`<samp>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/samp)
578+ /// element.
579+ samp;
580+ /// Build a
581+ /// [`<small>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/small)
582+ /// element.
583+ small;
584+ /// Build a
585+ /// [`<span>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span)
586+ /// element.
587+ span;
588+ /// Build a
589+ /// [`<strong>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/strong)
590+ /// element.
591+ strong;
592+ /// Build a
593+ /// [`<sub>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sub)
594+ /// element.
595+ sub;
596+ /// Build a
597+ /// [`<sup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/sup)
598+ /// element.
599+ sup;
600+ /// Build a
601+ /// [`<time>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/time)
602+ /// element.
603+ time;
604+ /// Build a
605+ /// [`<u>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/u)
606+ /// element.
607+ u;
608+ /// Build a
609+ /// [`<var>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/var)
610+ /// element.
611+ var;
612+ /// Build a
613+ /// [`<wbr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr)
614+ /// element.
615+ wbr;
616+
617+ // Image and multimedia
618+
619+ /// Build a
620+ /// [`<area>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area)
621+ /// element.
622+ area;
623+ /// Build a
624+ /// [`<audio>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio)
625+ /// element.
626+ audio;
627+ /// Build a
628+ /// [`<img>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img)
629+ /// element.
630+ img;
631+ /// Build a
632+ /// [`<map>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/map)
633+ /// element.
634+ map;
635+ /// Build a
636+ /// [`<track>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track)
637+ /// element.
638+ track;
639+ /// Build a
640+ /// [`<video>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video)
641+ /// element.
642+ video;
643+
644+ // Embedded content
645+
646+ /// Build a
647+ /// [`<embed>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed)
648+ /// element.
649+ embed;
650+ /// Build a
651+ /// [`<iframe>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe)
652+ /// element.
653+ iframe;
654+ /// Build a
655+ /// [`<object>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object)
656+ /// element.
657+ object;
658+ /// Build a
659+ /// [`<param>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param)
660+ /// element.
661+ param;
662+ /// Build a
663+ /// [`<picture>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)
664+ /// element.
665+ picture;
666+ /// Build a
667+ /// [`<source>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source)
668+ /// element.
669+ source;
670+
671+ // Scripting
672+
673+ /// Build a
674+ /// [`<canvas>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas)
675+ /// element.
676+ canvas;
677+ /// Build a
678+ /// [`<noscript>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript)
679+ /// element.
680+ noscript;
681+ /// Build a
682+ /// [`<script>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script)
683+ /// element.
684+ script;
685+
686+ // Demarcating edits
687+
688+ /// Build a
689+ /// [`<del>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/del)
690+ /// element.
691+ del;
692+ /// Build a
693+ /// [`<ins>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins)
694+ /// element.
695+ ins;
696+
697+ // Table content
698+
699+ /// Build a
700+ /// [`<caption>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/caption)
701+ /// element.
702+ caption;
703+ /// Build a
704+ /// [`<col>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col)
705+ /// element.
706+ col;
707+ /// Build a
708+ /// [`<colgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/colgroup)
709+ /// element.
710+ colgroup;
711+ /// Build a
712+ /// [`<table>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table)
713+ /// element.
714+ table;
715+ /// Build a
716+ /// [`<tbody>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tbody)
717+ /// element.
718+ tbody;
719+ /// Build a
720+ /// [`<td>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td)
721+ /// element.
722+ td;
723+ /// Build a
724+ /// [`<tfoot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tfoot)
725+ /// element.
726+ tfoot;
727+ /// Build a
728+ /// [`<th>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/th)
729+ /// element.
730+ th;
731+ /// Build a
732+ /// [`<thead>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/thead)
733+ /// element.
734+ thead;
735+ /// Build a
736+ /// [`<tr>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr)
737+ /// element.
738+ tr;
739+
740+ // Forms
741+
742+ /// Build a
743+ /// [`<button>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button)
744+ /// element.
745+ button;
746+ /// Build a
747+ /// [`<datalist>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist)
748+ /// element.
749+ datalist;
750+ /// Build a
751+ /// [`<fieldset>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset)
752+ /// element.
753+ fieldset;
754+ /// Build a
755+ /// [`<form>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)
756+ /// element.
757+ form;
758+ /// Build a
759+ /// [`<input>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)
760+ /// element.
761+ input;
762+ /// Build a
763+ /// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
764+ /// element.
765+ label;
766+ /// Build a
767+ /// [`<legend>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/legend)
768+ /// element.
769+ legend;
770+ /// Build a
771+ /// [`<meter>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meter)
772+ /// element.
773+ meter;
774+ /// Build a
775+ /// [`<optgroup>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup)
776+ /// element.
777+ optgroup;
778+ /// Build a
779+ /// [`<option>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option)
780+ /// element.
781+ option;
782+ /// Build a
783+ /// [`<output>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/output)
784+ /// element.
785+ output;
786+ /// Build a
787+ /// [`<progress>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress)
788+ /// element.
789+ progress;
790+ /// Build a
791+ /// [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)
792+ /// element.
793+ select;
794+ /// Build a
795+ /// [`<textarea>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea)
796+ /// element.
797+ textarea;
798+
799+ // Interactive elements
800+
801+ /// Build a
802+ /// [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
803+ /// element.
804+ details;
805+ /// Build a
806+ /// [`<dialog>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
807+ /// element.
808+ dialog;
809+ /// Build a
810+ /// [`<menu>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu)
811+ /// element.
812+ menu;
813+ /// Build a
814+ /// [`<menuitem>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem)
815+ /// element.
816+ menuitem;
817+ /// Build a
818+ /// [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
819+ /// element.
820+ summary;
821+
822+ // Web components
823+
824+ /// Build a
825+ /// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot)
826+ /// element.
827+ slot;
828+ /// Build a
829+ /// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
830+ /// element.
831+ template;
832+}
833+
834+/// Construct a text node.
835+///
836+/// This is `dodrio`'s virtual DOM equivalent of `document.createTextNode`.
837+///
838+/// # Example
839+///
840+/// ```no_run
841+/// use dodrio::builder::*;
842+///
843+/// let my_text = text("hello, dodrio!");
844+/// ```
845+#[inline]
846+pub fn text<'a>(contents: &'a str) -> Node<'a> {
847+ Node::text(contents)
848+}