diff --git a/crates/xilem_html/src/element/elements.rs b/crates/xilem_html/src/element/elements.rs index 0c8dad54..b84a2104 100644 --- a/crates/xilem_html/src/element/elements.rs +++ b/crates/xilem_html/src/element/elements.rs @@ -2,94 +2,31 @@ //! macro_rules! elements { () => {}; - (($ty_name:ident, $builder_name:ident, $name:literal, $web_sys_ty:ty), $($rest:tt)*) => { - element!($ty_name, $builder_name, $name, $web_sys_ty); + (($ty_name:ident, $builder_name:ident, $web_sys_ty:ty), $($rest:tt)*) => { + element!($ty_name, $builder_name, $web_sys_ty); elements!($($rest)*); }; } macro_rules! element { - ($ty_name:ident, $builder_name:ident, $name:literal, $web_sys_ty:ty) => { - /// A view representing a - #[doc = concat!("`", $name, "`")] - /// element. - pub struct $ty_name(crate::Element<$web_sys_ty, ViewSeq>); + ($ty_name:ident, $builder_name:ident, $web_sys_ty:ty) => { + /// Tag for a + #[doc = concat!("`", stringify!($builder_name), "`")] + /// view. + pub struct $ty_name; + + impl $crate::element::ElementTag for $ty_name { + type WebSysElement = $web_sys_ty; + fn name() -> &'static str { + stringify!($builder_name) + } + } /// Builder function for a - #[doc = concat!("`", $name, "`")] + #[doc = concat!("`", stringify!($builder_name), "`")] /// view. - pub fn $builder_name(children: ViewSeq) -> $ty_name { - $ty_name(crate::element($name, children)) - } - - impl $ty_name { - /// Set an attribute on this element. - /// - /// # Panics - /// - /// If the name contains characters that are not valid in an attribute name, - /// then the `View::build`/`View::rebuild` functions will panic for this view. - pub fn attr( - mut self, - name: impl Into>, - value: impl Into>, - ) -> Self { - self.0.set_attr(name, value); - self - } - - /// Set an attribute on this element. - /// - /// # Panics - /// - /// If the name contains characters that are not valid in an attribute name, - /// then the `View::build`/`View::rebuild` functions will panic for this view. - pub fn set_attr( - &mut self, - name: impl Into>, - value: impl Into>, - ) -> &mut Self { - self.0.set_attr(name, value); - self - } - } - - impl crate::view::ViewMarker for $ty_name {} - - impl crate::view::View for $ty_name - where - ViewSeq: crate::view::ViewSequence, - { - type State = crate::ElementState; - type Element = $web_sys_ty; - - fn build( - &self, - cx: &mut crate::context::Cx, - ) -> (xilem_core::Id, Self::State, Self::Element) { - self.0.build(cx) - } - - fn rebuild( - &self, - cx: &mut crate::context::Cx, - prev: &Self, - id: &mut xilem_core::Id, - state: &mut Self::State, - element: &mut Self::Element, - ) -> crate::ChangeFlags { - self.0.rebuild(cx, &prev.0, id, state, element) - } - - fn message( - &self, - id_path: &[xilem_core::Id], - state: &mut Self::State, - message: Box, - app_state: &mut T_, - ) -> xilem_core::MessageResult { - self.0.message(id_path, state, message, app_state) - } + pub fn $builder_name(children: ViewSeq) -> $crate::Element<$ty_name, ViewSeq> { + crate::element(stringify!($builder_name), children) } }; } @@ -102,131 +39,121 @@ elements!( // DOM interfaces copied from https://html.spec.whatwg.org/multipage/grouping-content.html and friends // content sectioning - (Address, address, "address", web_sys::HtmlElement), - (Article, article, "article", web_sys::HtmlElement), - (Aside, aside, "aside", web_sys::HtmlElement), - (Footer, footer, "footer", web_sys::HtmlElement), - (Header, header, "header", web_sys::HtmlElement), - (H1, h1, "h1", web_sys::HtmlHeadingElement), - (H2, h2, "h2", web_sys::HtmlHeadingElement), - (H3, h3, "h3", web_sys::HtmlHeadingElement), - (H4, h4, "h4", web_sys::HtmlHeadingElement), - (H5, h5, "h5", web_sys::HtmlHeadingElement), - (H6, h6, "h6", web_sys::HtmlHeadingElement), - (Hgroup, hgroup, "hgroup", web_sys::HtmlElement), - (Main, main, "main", web_sys::HtmlElement), - (Nav, nav, "nav", web_sys::HtmlElement), - (Section, section, "section", web_sys::HtmlElement), + (Address, address, web_sys::HtmlElement), + (Article, article, web_sys::HtmlElement), + (Aside, aside, web_sys::HtmlElement), + (Footer, footer, web_sys::HtmlElement), + (Header, header, web_sys::HtmlElement), + (H1, h1, web_sys::HtmlHeadingElement), + (H2, h2, web_sys::HtmlHeadingElement), + (H3, h3, web_sys::HtmlHeadingElement), + (H4, h4, web_sys::HtmlHeadingElement), + (H5, h5, web_sys::HtmlHeadingElement), + (H6, h6, web_sys::HtmlHeadingElement), + (Hgroup, hgroup, web_sys::HtmlElement), + (Main, main, web_sys::HtmlElement), + (Nav, nav, web_sys::HtmlElement), + (Section, section, web_sys::HtmlElement), // text content - ( - Blockquote, - blockquote, - "blockquote", - web_sys::HtmlQuoteElement - ), - (Dd, dd, "dd", web_sys::HtmlElement), - (Div, div, "div", web_sys::HtmlDivElement), - (Dl, dl, "dl", web_sys::HtmlDListElement), - (Dt, dt, "dt", web_sys::HtmlElement), - (Figcaption, figcaption, "figcaption", web_sys::HtmlElement), - (Figure, figure, "figure", web_sys::HtmlElement), - (Hr, hr, "hr", web_sys::HtmlHrElement), - (Li, li, "li", web_sys::HtmlLiElement), - (Menu, menu, "menu", web_sys::HtmlMenuElement), - (Ol, ol, "ol", web_sys::HtmlOListElement), - (P, p, "p", web_sys::HtmlParagraphElement), - (Pre, pre, "pre", web_sys::HtmlPreElement), - (Ul, ul, "ul", web_sys::HtmlUListElement), + (Blockquote, blockquote, web_sys::HtmlQuoteElement), + (Dd, dd, web_sys::HtmlElement), + (Div, div, web_sys::HtmlDivElement), + (Dl, dl, web_sys::HtmlDListElement), + (Dt, dt, web_sys::HtmlElement), + (Figcaption, figcaption, web_sys::HtmlElement), + (Figure, figure, web_sys::HtmlElement), + (Hr, hr, web_sys::HtmlHrElement), + (Li, li, web_sys::HtmlLiElement), + (Menu, menu, web_sys::HtmlMenuElement), + (Ol, ol, web_sys::HtmlOListElement), + (P, p, web_sys::HtmlParagraphElement), + (Pre, pre, web_sys::HtmlPreElement), + (Ul, ul, web_sys::HtmlUListElement), // inline text - (A, a, "a", web_sys::HtmlAnchorElement), - (Abbr, abbr, "abbr", web_sys::HtmlElement), - (B, b, "b", web_sys::HtmlElement), - (Bdi, bdi, "bdi", web_sys::HtmlElement), - (Bdo, bdo, "bdo", web_sys::HtmlElement), - (Br, br, "br", web_sys::HtmlBrElement), - (Cite, cite, "cite", web_sys::HtmlElement), - (Code, code, "code", web_sys::HtmlElement), - (Data, data, "data", web_sys::HtmlDataElement), - (Dfn, dfn, "dfn", web_sys::HtmlElement), - (Em, em, "em", web_sys::HtmlElement), - (I, i, "i", web_sys::HtmlElement), - (Kbd, kbd, "kbd", web_sys::HtmlElement), - (Mark, mark, "mark", web_sys::HtmlElement), - (Q, q, "q", web_sys::HtmlQuoteElement), - (Rp, rp, "rp", web_sys::HtmlElement), - (Rt, rt, "rt", web_sys::HtmlElement), - (Ruby, ruby, "ruby", web_sys::HtmlElement), - (S, s, "s", web_sys::HtmlElement), - (Samp, samp, "samp", web_sys::HtmlElement), - (Small, small, "small", web_sys::HtmlElement), - (Span, span, "span", web_sys::HtmlSpanElement), - (Strong, strong, "strong", web_sys::HtmlElement), - (Sub, sub, "sub", web_sys::HtmlElement), - (Sup, sup, "sup", web_sys::HtmlElement), - (Time, time, "time", web_sys::HtmlTimeElement), - (U, u, "u", web_sys::HtmlElement), - (Var, var, "var", web_sys::HtmlElement), - (Wbr, wbr, "wbr", web_sys::HtmlElement), + (A, a, web_sys::HtmlAnchorElement), + (Abbr, abbr, web_sys::HtmlElement), + (B, b, web_sys::HtmlElement), + (Bdi, bdi, web_sys::HtmlElement), + (Bdo, bdo, web_sys::HtmlElement), + (Br, br, web_sys::HtmlBrElement), + (Cite, cite, web_sys::HtmlElement), + (Code, code, web_sys::HtmlElement), + (Data, data, web_sys::HtmlDataElement), + (Dfn, dfn, web_sys::HtmlElement), + (Em, em, web_sys::HtmlElement), + (I, i, web_sys::HtmlElement), + (Kbd, kbd, web_sys::HtmlElement), + (Mark, mark, web_sys::HtmlElement), + (Q, q, web_sys::HtmlQuoteElement), + (Rp, rp, web_sys::HtmlElement), + (Rt, rt, web_sys::HtmlElement), + (Ruby, ruby, web_sys::HtmlElement), + (S, s, web_sys::HtmlElement), + (Samp, samp, web_sys::HtmlElement), + (Small, small, web_sys::HtmlElement), + (Span, span, web_sys::HtmlSpanElement), + (Strong, strong, web_sys::HtmlElement), + (Sub, sub, web_sys::HtmlElement), + (Sup, sup, web_sys::HtmlElement), + (Time, time, web_sys::HtmlTimeElement), + (U, u, web_sys::HtmlElement), + (Var, var, web_sys::HtmlElement), + (Wbr, wbr, web_sys::HtmlElement), // image and multimedia - (Area, area, "area", web_sys::HtmlAreaElement), - (Audio, audio, "audio", web_sys::HtmlAudioElement), - (Img, img, "img", web_sys::HtmlImageElement), - (Map, map, "map", web_sys::HtmlMapElement), - (Track, track, "track", web_sys::HtmlTrackElement), - (Video, video, "video", web_sys::HtmlVideoElement), + (Area, area, web_sys::HtmlAreaElement), + (Audio, audio, web_sys::HtmlAudioElement), + (Img, img, web_sys::HtmlImageElement), + (Map, map, web_sys::HtmlMapElement), + (Track, track, web_sys::HtmlTrackElement), + (Video, video, web_sys::HtmlVideoElement), // embedded content - (Embed, embed, "embed", web_sys::HtmlEmbedElement), - (Iframe, iframe, "iframe", web_sys::HtmlIFrameElement), - (Object, object, "object", web_sys::HtmlObjectElement), - (Picture, picture, "picture", web_sys::HtmlPictureElement), - (Portal, portal, "portal", web_sys::HtmlElement), - (Source, source, "source", web_sys::HtmlSourceElement), + (Embed, embed, web_sys::HtmlEmbedElement), + (Iframe, iframe, web_sys::HtmlIFrameElement), + (Object, object, web_sys::HtmlObjectElement), + (Picture, picture, web_sys::HtmlPictureElement), + (Portal, portal, web_sys::HtmlElement), + (Source, source, web_sys::HtmlSourceElement), // SVG and MathML (TODO, svg and mathml elements) - (Svg, svg, "svg", web_sys::HtmlElement), - (Math, math, "math", web_sys::HtmlElement), + (Svg, svg, web_sys::HtmlElement), + (Math, math, web_sys::HtmlElement), // scripting - (Canvas, canvas, "canvas", web_sys::HtmlCanvasElement), - (Noscript, noscript, "noscript", web_sys::HtmlElement), - (Script, script, "script", web_sys::HtmlScriptElement), + (Canvas, canvas, web_sys::HtmlCanvasElement), + (Noscript, noscript, web_sys::HtmlElement), + (Script, script, web_sys::HtmlScriptElement), // demarcating edits - (Del, del, "del", web_sys::HtmlModElement), - (Ins, ins, "ins", web_sys::HtmlModElement), + (Del, del, web_sys::HtmlModElement), + (Ins, ins, web_sys::HtmlModElement), // tables - ( - Caption, - caption, - "caption", - web_sys::HtmlTableCaptionElement - ), - (Col, col, "col", web_sys::HtmlTableColElement), - (Colgroup, colgroup, "colgroup", web_sys::HtmlTableColElement), - (Table, table, "table", web_sys::HtmlTableSectionElement), - (Tbody, tbody, "tbody", web_sys::HtmlTableSectionElement), - (Td, td, "td", web_sys::HtmlTableCellElement), - (Tfoot, tfoot, "tfoot", web_sys::HtmlTableSectionElement), - (Th, th, "th", web_sys::HtmlTableCellElement), - (Thead, thead, "thead", web_sys::HtmlTableSectionElement), - (Tr, tr, "tr", web_sys::HtmlTableRowElement), + (Caption, caption, web_sys::HtmlTableCaptionElement), + (Col, col, web_sys::HtmlTableColElement), + (Colgroup, colgroup, web_sys::HtmlTableColElement), + (Table, table, web_sys::HtmlTableSectionElement), + (Tbody, tbody, web_sys::HtmlTableSectionElement), + (Td, td, web_sys::HtmlTableCellElement), + (Tfoot, tfoot, web_sys::HtmlTableSectionElement), + (Th, th, web_sys::HtmlTableCellElement), + (Thead, thead, web_sys::HtmlTableSectionElement), + (Tr, tr, web_sys::HtmlTableRowElement), // forms - (Button, button, "button", web_sys::HtmlButtonElement), - (Datalist, datalist, "datalist", web_sys::HtmlDataListElement), - (Fieldset, fieldset, "fieldset", web_sys::HtmlFieldSetElement), - (Form, form, "form", web_sys::HtmlFormElement), - (Input, input, "input", web_sys::HtmlInputElement), - (Label, label, "label", web_sys::HtmlLabelElement), - (Legend, legend, "legend", web_sys::HtmlLegendElement), - (Meter, meter, "meter", web_sys::HtmlMeterElement), - (Optgroup, optgroup, "optgroup", web_sys::HtmlOptGroupElement), - (Option, option, "option", web_sys::HtmlOptionElement), - (Output, output, "output", web_sys::HtmlOutputElement), - (Progress, progress, "progress", web_sys::HtmlProgressElement), - (Select, select, "select", web_sys::HtmlSelectElement), - (Textarea, textarea, "textarea", web_sys::HtmlTextAreaElement), + (Button, button, web_sys::HtmlButtonElement), + (Datalist, datalist, web_sys::HtmlDataListElement), + (Fieldset, fieldset, web_sys::HtmlFieldSetElement), + (Form, form, web_sys::HtmlFormElement), + (Input, input, web_sys::HtmlInputElement), + (Label, label, web_sys::HtmlLabelElement), + (Legend, legend, web_sys::HtmlLegendElement), + (Meter, meter, web_sys::HtmlMeterElement), + (Optgroup, optgroup, web_sys::HtmlOptGroupElement), + (Option, option, web_sys::HtmlOptionElement), + (Output, output, web_sys::HtmlOutputElement), + (Progress, progress, web_sys::HtmlProgressElement), + (Select, select, web_sys::HtmlSelectElement), + (Textarea, textarea, web_sys::HtmlTextAreaElement), // interactive elements, - (Details, details, "details", web_sys::HtmlDetailsElement), - (Dialog, dialog, "dialog", web_sys::HtmlDialogElement), - (Summary, summary, "summary", web_sys::HtmlElement), + (Details, details, web_sys::HtmlDetailsElement), + (Dialog, dialog, web_sys::HtmlDialogElement), + (Summary, summary, web_sys::HtmlElement), // web components, - (Slot, slot, "slot", web_sys::HtmlSlotElement), - (Template, template, "template", web_sys::HtmlTemplateElement), + (Slot, slot, web_sys::HtmlSlotElement), + (Template, template, web_sys::HtmlTemplateElement), ); diff --git a/crates/xilem_html/src/element/mod.rs b/crates/xilem_html/src/element/mod.rs index 7b30ccf1..ffdbcbc9 100644 --- a/crates/xilem_html/src/element/mod.rs +++ b/crates/xilem_html/src/element/mod.rs @@ -4,7 +4,7 @@ //! `use xilem_html::elements as el` or similar to the top of your file. use crate::{ context::{ChangeFlags, Cx}, - view::{DomElement, Pod, View, ViewMarker, ViewSequence}, + view::{DomElement, DomNode, Pod, View, ViewMarker, ViewSequence}, }; use std::{borrow::Cow, cmp::Ordering, collections::BTreeMap, fmt, marker::PhantomData}; @@ -24,6 +24,12 @@ pub struct Element { ty: PhantomData, } +pub trait ElementTag { + type WebSysElement: JsCast + DomElement; + + fn name() -> &'static str; +} + impl Element { pub fn debug_as_el(&self) -> impl fmt::Debug + '_ { struct DebugFmt<'a, E, VS>(&'a Element); @@ -100,12 +106,12 @@ impl View for Element where Children: ViewSequence, // In addition, the `E` parameter is expected to be a child of `web_sys::Node` - El: JsCast + DomElement, + El: ElementTag, { type State = ElementState; - type Element = El; + type Element = El::WebSysElement; - fn build(&self, cx: &mut Cx) -> (Id, Self::State, El) { + fn build(&self, cx: &mut Cx) -> (Id, Self::State, Self::Element) { let el = cx.create_html_element(&self.name); for (name, value) in &self.attributes { el.set_attribute(name, value).unwrap(); @@ -128,7 +134,7 @@ where prev: &Self, id: &mut Id, state: &mut Self::State, - element: &mut El, + element: &mut Self::Element, ) -> ChangeFlags { let mut changed = ChangeFlags::empty(); // update tag name diff --git a/crates/xilem_html/web_examples/counter/src/lib.rs b/crates/xilem_html/web_examples/counter/src/lib.rs index 8dcb7f26..be330386 100644 --- a/crates/xilem_html/web_examples/counter/src/lib.rs +++ b/crates/xilem_html/web_examples/counter/src/lib.rs @@ -43,7 +43,7 @@ impl AppState { fn btn( label: &'static str, click_fn: F, -) -> evt::OnClick, F, ()> +) -> evt::OnClick, F, ()> where F: Fn(&mut AppState, &Event), {