silkenweb/node/
element.rs

1//! Traits and types for building elements.
2#[cfg(debug_assertions)]
3use std::collections::HashSet;
4use std::{
5    self, fmt,
6    future::Future,
7    marker::PhantomData,
8    pin::{pin, Pin},
9};
10
11use discard::DiscardOnDrop;
12use futures::StreamExt;
13use futures_signals::{
14    cancelable_future,
15    signal::{Signal, SignalExt},
16    signal_vec::{always, SignalVec, SignalVecExt},
17    CancelableFutureHandle,
18};
19use include_doc::function_body;
20use silkenweb_base::document;
21use silkenweb_signals_ext::value::{Executor, RefSignalOrValue, SignalOrValue, Value};
22use wasm_bindgen::{JsCast, JsValue};
23
24use self::child_vec::{ChildVec, ParentUnique};
25use super::{ChildNode, Node, Resource};
26use crate::{
27    attribute::Attribute,
28    clone,
29    dom::{
30        private::{DomElement, DomText, EventStore, InstantiableDomElement},
31        DefaultDom, Dom, Hydro, InDom, InstantiableDom, Template, Wet,
32    },
33    empty_str,
34    hydration::HydrationStats,
35    intern_str,
36    node::text,
37    task,
38};
39
40pub(crate) mod child_vec;
41
42/// A generic HTML element.
43///
44/// Where available, specific DOM elements from [`crate::elements::html`] should
45/// be used in preference to this.
46///
47/// `Mutability` should be one of [`Mut`] or [`Const`].
48pub struct GenericElement<D: Dom = DefaultDom, Mutability = Mut> {
49    static_child_count: usize,
50    child_vec: Option<Pin<Box<dyn SignalVec<Item = Node<D>>>>>,
51    resources: Vec<Resource>,
52    events: EventStore,
53    element: D::Element,
54    #[cfg(debug_assertions)]
55    attributes: HashSet<String>,
56    phantom: PhantomData<Mutability>,
57}
58
59impl<D: Dom> GenericElement<D> {
60    /// Construct an element with type `tag` in `namespace`.
61    pub fn new(namespace: &Namespace, tag: &str) -> Self {
62        Self::from_dom(D::Element::new(namespace, tag), 0)
63    }
64
65    /// Make this element immutable.
66    pub fn freeze(mut self) -> GenericElement<D, Const> {
67        self.build();
68        GenericElement {
69            static_child_count: self.static_child_count,
70            child_vec: self.child_vec,
71            resources: self.resources,
72            events: self.events,
73            element: self.element,
74            #[cfg(debug_assertions)]
75            attributes: self.attributes,
76            phantom: PhantomData,
77        }
78    }
79
80    /// Observe mutations to attributes.
81    pub fn observe_mutations<F>(mut self, f: F) -> Self
82    where
83        F: for<'a> FnOnce(GenericElementObserver<'a, D>) -> GenericElementObserver<'a, D>,
84    {
85        f(GenericElementObserver(&mut self));
86        self
87    }
88
89    pub(crate) fn from_dom(element: D::Element, static_child_count: usize) -> Self {
90        Self {
91            static_child_count,
92            child_vec: None,
93            resources: Vec::new(),
94            events: EventStore::default(),
95            element,
96            #[cfg(debug_assertions)]
97            attributes: HashSet::new(),
98            phantom: PhantomData,
99        }
100    }
101
102    pub(crate) fn store_child(&mut self, mut child: Self) {
103        child.build();
104        self.resources.append(&mut child.resources);
105        self.events.combine(child.events);
106    }
107
108    fn check_attribute_unique(&mut self, name: &str) {
109        #[cfg(debug_assertions)]
110        debug_assert!(self.attributes.insert(name.into()));
111        let _ = name;
112    }
113
114    async fn class_signal<T>(mut element: D::Element, class: impl Signal<Item = T>)
115    where
116        T: AsRef<str>,
117    {
118        let mut class = pin!(class.to_stream());
119
120        if let Some(new_value) = class.next().await {
121            Self::check_class(&new_value);
122            element.add_class(intern_str(new_value.as_ref()));
123            let mut previous_value = new_value;
124
125            while let Some(new_value) = class.next().await {
126                Self::check_class(&new_value);
127                element.remove_class(previous_value.as_ref());
128                element.add_class(intern_str(new_value.as_ref()));
129                previous_value = new_value;
130            }
131        }
132    }
133
134    async fn classes_signal<T>(
135        mut element: D::Element,
136        classes: impl Signal<Item = impl IntoIterator<Item = T>>,
137    ) where
138        T: AsRef<str>,
139    {
140        let mut classes = pin!(classes.to_stream());
141        let mut previous_classes: Vec<T> = Vec::new();
142
143        while let Some(new_classes) = classes.next().await {
144            for to_remove in previous_classes.drain(..) {
145                element.remove_class(to_remove.as_ref());
146            }
147
148            for to_add in new_classes {
149                Self::check_class(&to_add);
150                element.add_class(intern_str(to_add.as_ref()));
151                previous_classes.push(to_add);
152            }
153        }
154    }
155
156    fn check_class(name: &impl AsRef<str>) {
157        assert!(
158            !name.as_ref().is_empty(),
159            "Class names must not be empty. Use `.classes` with `Option::None` to unset an optional class."
160        );
161        debug_assert!(
162            !name.as_ref().contains(char::is_whitespace),
163            "Class names must not contain whitespace."
164        )
165    }
166}
167
168pub struct GenericElementObserver<'a, D: Dom>(&'a mut GenericElement<D>);
169
170impl<D: Dom> GenericElementObserver<'_, D> {
171    pub fn attribute(
172        self,
173        name: String,
174        mut f: impl FnMut(&web_sys::Element, Option<String>) + 'static,
175    ) -> Self {
176        let name = name.to_string();
177
178        self.0.element.observe_attributes(
179            move |changes, _observer| {
180                for change in changes
181                    .to_vec()
182                    .into_iter()
183                    .map(|change| change.unchecked_into::<web_sys::MutationRecord>())
184                {
185                    if change.type_() == "attributes"
186                        && change.attribute_name().as_ref() == Some(&name)
187                    {
188                        if let Some(elem) =
189                            change.target().and_then(|target| target.dyn_into().ok())
190                        {
191                            f(&elem, change.old_value())
192                        }
193                    }
194                }
195            },
196            &mut self.0.events,
197        );
198        self
199    }
200}
201
202impl<D: Dom, Mutability> GenericElement<D, Mutability> {
203    fn build(&mut self) {
204        if let Some(children) = self.child_vec.take() {
205            let child_vec =
206                ChildVec::<D, ParentUnique>::new(self.element.clone(), self.static_child_count);
207
208            let handle = child_vec.run(children);
209            self.resources.push(Resource::Any(Box::new(handle)));
210        }
211    }
212}
213
214impl<Param, D> GenericElement<Template<Param, D>>
215where
216    Param: 'static,
217    D: InstantiableDom,
218{
219    pub fn on_instantiate(
220        mut self,
221        f: impl 'static + Fn(GenericElement<D>, &Param) -> GenericElement<D>,
222    ) -> Self {
223        self.element.on_instantiate(f);
224        self
225    }
226}
227
228impl<D: Dom> TextParentElement<D> for GenericElement<D> {
229    fn text<'a, T>(mut self, child: impl RefSignalOrValue<'a, Item = T>) -> Self
230    where
231        T: 'a + AsRef<str> + Into<String>,
232    {
233        if self.child_vec.is_some() {
234            return self.child(child.map(|child| text(child.as_ref())));
235        }
236
237        self.static_child_count += 1;
238
239        child.select_spawn(
240            |parent, child| {
241                parent
242                    .element
243                    .append_child(&D::Text::new(child.as_ref()).into());
244            },
245            |parent, child_signal| {
246                let mut text_node = D::Text::new(empty_str());
247                parent.element.append_child(&text_node.clone().into());
248
249                child_signal.for_each(move |new_value| {
250                    text_node.set_text(new_value.as_ref());
251                    async {}
252                })
253            },
254            &mut self,
255        );
256
257        self
258    }
259}
260
261impl<D: Dom> ParentElement<D> for GenericElement<D> {
262    fn optional_child(self, child: impl SignalOrValue<Item = Option<impl ChildNode<D>>>) -> Self {
263        child.select(
264            |mut parent, child| {
265                if let Some(child) = child {
266                    if parent.child_vec.is_some() {
267                        return parent.children_signal(always(vec![child]));
268                    }
269
270                    parent.static_child_count += 1;
271                    let child = child.into();
272
273                    parent.element.append_child(&child.node);
274                    parent.resources.append(&mut child.resources.into_vec());
275                    parent.events.combine(child.events);
276                }
277
278                parent
279            },
280            |parent, child| {
281                let child_vec = child
282                    .map(|child| child.into_iter().collect::<Vec<_>>())
283                    .to_signal_vec();
284                parent.children_signal(child_vec)
285            },
286            self,
287        )
288    }
289
290    fn children<N>(mut self, children: impl IntoIterator<Item = N>) -> Self
291    where
292        N: Into<Node<D>>,
293    {
294        if self.child_vec.is_some() {
295            let children = children
296                .into_iter()
297                .map(|node| node.into())
298                .collect::<Vec<_>>();
299            return self.children_signal(always(children));
300        }
301
302        for child in children {
303            self = self.child(child.into());
304        }
305
306        self
307    }
308
309    fn children_signal<N>(mut self, children: impl SignalVec<Item = N> + 'static) -> Self
310    where
311        N: Into<Node<D>>,
312    {
313        let new_children = children.map(|child| child.into());
314
315        let boxed_children = if let Some(child_vec) = self.child_vec.take() {
316            child_vec.chain(new_children).boxed_local()
317        } else {
318            new_children.boxed_local()
319        };
320
321        self.child_vec = Some(boxed_children);
322
323        self
324    }
325}
326
327impl<Mutability> GenericElement<Wet, Mutability> {
328    pub(crate) fn dom_element(&self) -> web_sys::Element {
329        self.element.dom_element()
330    }
331}
332
333impl<Mutability> GenericElement<Hydro, Mutability> {
334    pub(crate) fn hydrate(
335        mut self,
336        element: &web_sys::Element,
337        tracker: &mut HydrationStats,
338    ) -> GenericElement<Wet, Const> {
339        self.build();
340
341        GenericElement {
342            static_child_count: self.static_child_count,
343            child_vec: None,
344            resources: self.resources,
345            events: self.events,
346            element: self.element.hydrate(element, tracker),
347            #[cfg(debug_assertions)]
348            attributes: self.attributes,
349            phantom: PhantomData,
350        }
351    }
352}
353
354impl<D: InstantiableDom> ShadowRootParent<D> for GenericElement<D> {
355    fn attach_shadow_children<N>(mut self, children: impl IntoIterator<Item = N> + 'static) -> Self
356    where
357        N: Into<Node<D>>,
358    {
359        let children: Vec<_> = children
360            .into_iter()
361            .map(|child| {
362                let child = child.into();
363                let child_node = child.node;
364                self.resources.append(&mut child.resources.into_vec());
365                self.events.combine(child.events);
366                child_node
367            })
368            .collect();
369
370        self.element.attach_shadow_children(children);
371        self
372    }
373}
374
375impl<D: Dom> Element for GenericElement<D> {
376    type Dom = D;
377    type DomElement = web_sys::Element;
378
379    fn class<'a, T>(mut self, class: impl RefSignalOrValue<'a, Item = T>) -> Self
380    where
381        T: 'a + AsRef<str>,
382    {
383        class.select_spawn(
384            |elem, class| {
385                Self::check_class(&class);
386                elem.element.add_class(intern_str(class.as_ref()))
387            },
388            |elem, class| Self::class_signal(elem.element.clone(), class),
389            &mut self,
390        );
391
392        self
393    }
394
395    fn classes<'a, T, Iter>(mut self, classes: impl RefSignalOrValue<'a, Item = Iter>) -> Self
396    where
397        T: 'a + AsRef<str>,
398        Iter: 'a + IntoIterator<Item = T>,
399    {
400        classes.select_spawn(
401            |elem, classes| {
402                for class in classes {
403                    Self::check_class(&class);
404                    elem.element.add_class(intern_str(class.as_ref()));
405                }
406            },
407            |elem, classes| Self::classes_signal(elem.element.clone(), classes),
408            &mut self,
409        );
410
411        self
412    }
413
414    fn attribute<'a>(
415        mut self,
416        name: &str,
417        value: impl RefSignalOrValue<'a, Item = impl Attribute>,
418    ) -> Self {
419        self.check_attribute_unique(name);
420
421        value.select_spawn(
422            |elem, value| elem.element.attribute(name, value),
423            |elem, value| {
424                let name = name.to_owned();
425                clone!(mut elem.element);
426
427                value.for_each(move |new_value| {
428                    element.attribute(&name, new_value);
429
430                    async {}
431                })
432            },
433            &mut self,
434        );
435
436        self
437    }
438
439    fn style_property<'a>(
440        mut self,
441        name: impl Into<String>,
442        value: impl RefSignalOrValue<'a, Item = impl AsRef<str> + 'a>,
443    ) -> Self {
444        #[cfg(debug_assertions)]
445        debug_assert!(!self.attributes.contains("style"));
446
447        let name = name.into();
448
449        value.select_spawn(
450            |elem, value| elem.element.style_property(&name, value.as_ref()),
451            |elem, value| {
452                clone!(name, mut elem.element);
453
454                value.for_each(move |new_value| {
455                    element.style_property(&name, new_value.as_ref());
456
457                    async {}
458                })
459            },
460            &mut self,
461        );
462
463        self
464    }
465
466    fn effect(mut self, f: impl FnOnce(&Self::DomElement) + 'static) -> Self {
467        self.element.effect(f);
468        self
469    }
470
471    fn effect_signal<T>(
472        self,
473        sig: impl Signal<Item = T> + 'static,
474        f: impl Clone + Fn(&Self::DomElement, T) + 'static,
475    ) -> Self
476    where
477        T: 'static,
478    {
479        clone!(mut self.element);
480
481        let future = sig.for_each(move |x| {
482            clone!(f);
483            element.effect(move |elem| f(elem, x));
484            async {}
485        });
486
487        self.spawn_future(future)
488    }
489
490    fn map_element(self, f: impl FnOnce(&Self::DomElement) + 'static) -> Self {
491        if let Some(element) = self.element.try_dom_element() {
492            f(&element);
493        }
494
495        self
496    }
497
498    fn map_element_signal<T>(
499        self,
500        sig: impl Signal<Item = T> + 'static,
501        f: impl Clone + Fn(&Self::DomElement, T) + 'static,
502    ) -> Self
503    where
504        T: 'static,
505    {
506        clone!(mut self.element);
507
508        let future = sig.for_each(move |x| {
509            if let Some(element) = element.try_dom_element() {
510                f(&element, x);
511            }
512
513            async {}
514        });
515
516        self.spawn_future(future)
517    }
518
519    fn handle(&self) -> ElementHandle<Self::Dom, Self::DomElement> {
520        ElementHandle(self.element.clone(), PhantomData)
521    }
522
523    fn spawn_future(mut self, future: impl Future<Output = ()> + 'static) -> Self {
524        self.spawn(future);
525        self
526    }
527
528    fn on(mut self, name: &'static str, f: impl FnMut(JsValue) + 'static) -> Self {
529        self.element.on(name, f, &mut self.events);
530        self
531    }
532}
533
534impl<D: Dom> Executor for GenericElement<D> {
535    fn spawn(&mut self, future: impl Future<Output = ()> + 'static) {
536        self.resources
537            .push(Resource::FutureHandle(spawn_cancelable_future(future)));
538    }
539}
540
541impl<D: Dom, Mutability> Value for GenericElement<D, Mutability> {}
542
543impl<D: Dom, Mutability> InDom for GenericElement<D, Mutability> {
544    type Dom = D;
545}
546
547impl<D: Dom, Mutability> From<GenericElement<D, Mutability>> for Node<D> {
548    fn from(mut elem: GenericElement<D, Mutability>) -> Self {
549        elem.build();
550
551        Self {
552            node: elem.element.into(),
553            resources: elem.resources.into_boxed_slice(),
554            events: elem.events,
555        }
556    }
557}
558
559/// Trait alias for elements that can be used as a child
560pub trait ChildElement<D: Dom = DefaultDom>:
561    Into<GenericElement<D, Const>> + Into<Node<D>> + Value + 'static
562{
563}
564
565impl<D, T> ChildElement<D> for T
566where
567    D: Dom,
568    T: Into<GenericElement<D, Const>> + Into<Node<D>> + Value + 'static,
569{
570}
571
572/// An HTML element.
573pub trait Element: Sized {
574    type Dom: Dom;
575    type DomElement: JsCast + 'static;
576
577    /// Add a class to the element.
578    ///
579    /// This method can be called multiple
580    /// times to add multiple classes.
581    ///
582    /// `class` must not be the empty string, or contain whitespace. Use
583    /// [`Self::classes`] with an `Option` for optional classes.
584    ///
585    /// Classes must be unique across all
586    /// invocations of this method and [`Self::classes`], otherwise the results
587    /// are undefined. Any class signal values, past or present, must be unique
588    /// w.r.t. other invocations.
589    ///
590    /// # Panics
591    ///
592    /// This panics if `class` is the empty string, or contains whitespace.
593    ///
594    /// # Examples
595    ///
596    /// Add static class names:
597    ///
598    /// ```
599    #[doc = function_body!("tests/doc/node/element.rs", static_single_class_name, [])]
600    /// ```
601    /// 
602    /// Add dynamic class names:
603    /// ```
604    #[doc = function_body!("tests/doc/node/element.rs", dynamic_single_class_name, [])]
605    /// ```
606    fn class<'a, T>(self, class: impl RefSignalOrValue<'a, Item = T>) -> Self
607    where
608        T: 'a + AsRef<str>;
609
610    /// Set the classes on an element
611    ///
612    /// All `classes` must not contain spaces, or be the empty string. This
613    /// method can be called multiple times and will add to existing
614    /// classes.
615    ///
616    /// Classes must be unique across all invocations of this method and
617    /// [`Self::class`], otherwise the results are undefined. Any class signal
618    /// values, past or present, must be unique w.r.t. other invocations.
619    ///
620    /// # Panics
621    ///
622    /// Panics if any of the items in `classes` contain whitespace, or are empty
623    /// strings.
624    ///
625    /// # Examples
626    ///
627    /// Add static class names:
628    ///
629    /// ```
630    #[doc = function_body!("tests/doc/node/element.rs", static_class_names, [])]
631    /// ```
632    /// 
633    /// Add dynamic class names:
634    /// ```
635    #[doc = function_body!("tests/doc/node/element.rs", dynamic_class_names, [])]
636    /// ```
637    fn classes<'a, T, Iter>(self, classes: impl RefSignalOrValue<'a, Item = Iter>) -> Self
638    where
639        T: 'a + AsRef<str>,
640        Iter: 'a + IntoIterator<Item = T>;
641
642    /// Set an attribute
643    ///
644    /// The attribute can either be a value or a signal. Signals should be
645    /// wrapped in the [`Sig`] newtype.`Option<impl Attribute>` can be used to
646    /// add/remove an attribute based on a signal.
647    ///
648    /// [`Sig`]: crate::value::Sig
649    fn attribute<'a>(
650        self,
651        name: &str,
652        value: impl RefSignalOrValue<'a, Item = impl Attribute>,
653    ) -> Self;
654
655    /// Set an inline style property
656    ///
657    /// The property can be a value or a signal. Signals should be wrapped in
658    /// the [`Sig`] newtype.
659    ///
660    /// [`Sig`]: crate::value::Sig
661    fn style_property<'a>(
662        self,
663        name: impl Into<String>,
664        value: impl RefSignalOrValue<'a, Item = impl AsRef<str> + 'a>,
665    ) -> Self;
666
667    /// Apply an effect after the next render.
668    ///
669    /// Effects give you access to the underlying DOM element.
670    ///
671    /// # Example
672    ///
673    /// Set the focus to an `HTMLInputElement`.
674    ///
675    /// ```no_run
676    #[doc = function_body!("tests/doc/node/element.rs", effect, [])]
677    /// ```
678    fn effect(self, f: impl FnOnce(&Self::DomElement) + 'static) -> Self;
679
680    /// Apply an effect after the next render each time a signal yields a new
681    /// value.
682    fn effect_signal<T: 'static>(
683        self,
684        sig: impl Signal<Item = T> + 'static,
685        f: impl Fn(&Self::DomElement, T) + Clone + 'static,
686    ) -> Self;
687
688    /// Map a function over the element.
689    fn map_element(self, f: impl FnOnce(&Self::DomElement) + 'static) -> Self;
690
691    /// Map a function over the element each time a signal changes.
692    fn map_element_signal<T: 'static>(
693        self,
694        sig: impl Signal<Item = T> + 'static,
695        f: impl Fn(&Self::DomElement, T) + Clone + 'static,
696    ) -> Self;
697
698    /// Get a handle to the element.
699    ///
700    /// Handles can be cloned and used within click handlers, for example.
701    ///
702    /// # Example
703    ///
704    /// ```no_run
705    #[doc = function_body!("tests/doc/node/element.rs", handle, [])]
706    /// ```
707    fn handle(&self) -> ElementHandle<Self::Dom, Self::DomElement>;
708
709    /// Spawn a future on the element.
710    ///
711    /// The future will be dropped when this element is dropped.
712    fn spawn_future(self, future: impl Future<Output = ()> + 'static) -> Self;
713
714    /// Register an event handler.
715    ///
716    /// `name` is the name of the event. See the [MDN Events] page for a list.
717    ///
718    /// `f` is the callback when the event fires and will be passed the
719    /// javascript `Event` object.
720    ///
721    /// [MDN Events]: https://developer.mozilla.org/en-US/docs/Web/Events
722    fn on(self, name: &'static str, f: impl FnMut(JsValue) + 'static) -> Self;
723}
724
725/// An element that can have text children.
726pub trait TextParentElement<D: Dom = DefaultDom>: Element {
727    /// Add a text child to this element
728    ///
729    /// # Example
730    ///
731    /// Static text:
732    ///
733    /// ```no_run
734    #[doc = function_body!("tests/doc/node/element.rs", static_text, [])]
735    /// ```
736    /// 
737    /// Dynamic text:
738    /// ```no_run
739    #[doc = function_body!("tests/doc/node/element.rs", dynamic_text, [])]
740    /// ```
741    fn text<'a, T>(self, child: impl RefSignalOrValue<'a, Item = T>) -> Self
742    where
743        T: 'a + AsRef<str> + Into<String>;
744}
745
746/// An element that can have children.
747pub trait ParentElement<D: Dom = DefaultDom>: TextParentElement<D> {
748    /// Add a child to the element.
749    ///
750    /// # Example
751    ///
752    /// Add static children:
753    ///
754    /// ```no_run
755    #[doc = function_body!("tests/doc/node/element.rs", static_child, [])]
756    /// ```
757    /// 
758    /// Add a dynamic child:
759    /// ```no_run
760    #[doc = function_body!("tests/doc/node/element.rs", dynamic_child, [])]
761    /// ```
762    fn child(self, child: impl SignalOrValue<Item = impl ChildNode<D>>) -> Self {
763        self.optional_child(child.map(Some))
764    }
765
766    /// Add an optional child to the element.
767    ///
768    /// The child will update when the signal changes to `Some(..)`, and will be
769    /// removed when the signal changes to `None`.
770    ///
771    /// # Example
772    ///
773    /// Add a static optional child:
774    ///
775    /// ```no_run
776    #[doc = function_body!("tests/doc/node/element.rs", static_optional_child, [])]
777    /// ```
778    /// 
779    /// Add a dynamic optional child:
780    /// ```no_run
781    #[doc = function_body!("tests/doc/node/element.rs", dynamic_optional_child, [])]
782    /// ```
783    fn optional_child(self, child: impl SignalOrValue<Item = Option<impl ChildNode<D>>>) -> Self;
784
785    /// Add children to the element.
786    ///
787    /// # Example
788    ///
789    /// ```no_run
790    #[doc = function_body!("tests/doc/node/element.rs", children, [])]
791    /// ```
792    fn children<N>(self, children: impl IntoIterator<Item = N>) -> Self
793    where
794        N: Into<Node<D>>;
795
796    /// Add children from a [`SignalVec`] to the element.
797    ///
798    /// See [counter_list](https://github.com/silkenweb/silkenweb/tree/main/examples/counter-list/src/main.rs)
799    /// for an example
800    fn children_signal<N>(self, children: impl SignalVec<Item = N> + 'static) -> Self
801    where
802        N: Into<Node<D>>;
803}
804
805/// An element that can be a shadow host.
806pub trait ShadowRootParent<D: InstantiableDom = DefaultDom>: Element {
807    /// Attach an open shadow root to `self` and add `children` to it.
808    ///
809    /// If there's already a shadow root, the `children` are appended to it.
810    ///
811    /// See [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow)
812    fn attach_shadow_children<N>(self, children: impl IntoIterator<Item = N> + 'static) -> Self
813    where
814        N: Into<Node<D>>;
815}
816
817impl<D> fmt::Display for GenericElement<D, Const>
818where
819    D: Dom,
820{
821    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
822        self.element.fmt(f)
823    }
824}
825
826impl<Param, D> GenericElement<Template<Param, D>, Const>
827where
828    D: InstantiableDom,
829    Param: 'static,
830{
831    /// Instantiate a template with `param`.
832    ///
833    /// See [`Template`] for an example.
834    pub fn instantiate(&self, param: &Param) -> GenericElement<D> {
835        self.element.instantiate(param)
836    }
837}
838
839fn spawn_cancelable_future(
840    future: impl Future<Output = ()> + 'static,
841) -> DiscardOnDrop<CancelableFutureHandle> {
842    let (handle, cancelable_future) = cancelable_future(future, || ());
843
844    task::spawn_local(cancelable_future);
845
846    handle
847}
848
849/// A handle to an element in the DOM.
850///
851/// The handle will only be valid for [`Wet`]  DOM elements, so the methods
852/// should only be used inside event handlers and effects.
853///
854/// See [`Element::handle`] for an example.
855pub struct ElementHandle<D: Dom, DomElement>(D::Element, PhantomData<DomElement>);
856
857impl<D: Dom, DomElement> Clone for ElementHandle<D, DomElement> {
858    fn clone(&self) -> Self {
859        Self(self.0.clone(), PhantomData)
860    }
861}
862
863impl<D: Dom, DomElement: JsCast + Clone> ElementHandle<D, DomElement> {
864    /// Get the associated DOM element, if it is a [`Wet`] element.
865    ///
866    /// If the referenced element is not [`Wet`] or a hydrated [`Hydro`]
867    /// element, this will return [`None`].
868    pub fn try_dom_element(&self) -> Option<DomElement> {
869        self.0
870            .try_dom_element()
871            .map(|elem| elem.dyn_into().unwrap())
872    }
873
874    /// Get the associated DOM element, or panic.
875    ///
876    /// # Panics
877    ///
878    /// This will panic if [`Self::try_dom_element`] would return [`None`], or
879    /// `self` was created from an invalid [`ElementHandle::cast`].
880    pub fn dom_element(&self) -> DomElement {
881        self.0.dom_element().dyn_into().unwrap()
882    }
883}
884
885impl<D: Dom> ElementHandle<D, web_sys::Element> {
886    /// Cast the dom type of an [`ElementHandle`].
887    ///
888    /// It is the clients responsibility to ensure the new type is correct.
889    pub fn cast<T: JsCast>(self) -> ElementHandle<D, T> {
890        ElementHandle(self.0, PhantomData)
891    }
892}
893
894/// The namespace of a DOM element.
895#[derive(Clone, Eq, PartialEq)]
896pub enum Namespace {
897    /// New elements in the `Html` namespace are created with `create_element`,
898    /// thus avoiding converting the namespace to a javascript string.
899    Html,
900    Svg,
901    MathML,
902    Other(String),
903}
904
905impl Namespace {
906    pub(crate) fn create_element(&self, tag: &str) -> web_sys::Element {
907        match self {
908            Namespace::Html => document::create_element(tag),
909            _ => document::create_element_ns(intern_str(self.as_str()), tag),
910        }
911    }
912
913    pub(crate) fn as_str(&self) -> &str {
914        match self {
915            Namespace::Html => "http://www.w3.org/1999/xhtml",
916            Namespace::Svg => "http://www.w3.org/2000/svg",
917            Namespace::MathML => "http://www.w3.org/1998/Math/MathML",
918            Namespace::Other(ns) => ns,
919        }
920    }
921}
922
923/// Marker type for mutable elements.
924pub struct Mut;
925
926/// Marker type for immutable elements.
927pub struct Const;