diff --git a/Cargo.toml b/Cargo.toml index 30297af3b..2d5d881b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ description = "Core functionality for Dioxus - a concurrent renderer-agnostic Vi [dependencies] dioxus-core = { path="./packages/core", version="0.1.0" } dioxus-core-macro = { path="./packages/core-macro", version="0.1.0" } +dioxus-html-namespace = { path="./packages/html-namespace" } dioxus-web = { path="./packages/web", optional=true } # dioxus-hooks = { path="./packages/hooks", version="0.0.0" } diff --git a/README.md b/README.md index b8ccc43c4..85bb34443 100644 --- a/README.md +++ b/README.md @@ -120,8 +120,8 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an | Fragments | ✅ | ✅ | rsx! can return multiple elements without a root | | Manual Props | ✅ | ✅ | Manually pass in props with spread syntax | | Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs | +| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups[2] | | NodeRef | 🛠 | ✅ | gain direct access to nodes [1] | -| CSS/Inline Styles | 🛠 | ✅ | syntax for inline styles/attribute groups[2] | | 1st class global state | 🛠 | ✅ | redux/recoil/mobx on top of context | | Suspense | 🛠 | ✅ | schedule future render from future/promise | | Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events | diff --git a/examples/readme.rs b/examples/readme.rs index e58cb35b3..d71c3ae93 100644 --- a/examples/readme.rs +++ b/examples/readme.rs @@ -2,7 +2,9 @@ //! //! The example from the README.md -use dioxus::prelude::*; +use dioxus::{events::on::MouseEvent, prelude::*}; +use dioxus_html_namespace::{button, div, h1}; + fn main() { dioxus::web::launch(Example) } @@ -10,9 +12,11 @@ fn main() { fn Example(cx: Context<()>) -> VNode { let name = use_state(&cx, || "..?"); + let handler = move |e: MouseEvent| e.cl; + cx.render(rsx! { h1 { "Hello, {name}" } - button { "?", onclick: move |_| name.set("world!")} + button { "?", onclick: move |event| name.set("world!")} button { "?", onclick: move |_| name.set("Dioxus 🎉")} }) } diff --git a/packages/core-macro/src/rsx/element.rs b/packages/core-macro/src/rsx/element.rs index 74ab04f65..f1ea3b242 100644 --- a/packages/core-macro/src/rsx/element.rs +++ b/packages/core-macro/src/rsx/element.rs @@ -13,15 +13,55 @@ use syn::{ // ======================================= pub struct Element { name: Ident, - attrs: Vec, + key: Option, + attributes: Vec, + listeners: Vec, children: Vec, } +impl ToTokens for Element { + fn to_tokens(&self, tokens: &mut TokenStream2) { + let name = &self.name; + // let name = &self.name.to_string(); + + tokens.append_all(quote! { + __cx.element(#name) + }); + + // Add attributes + // TODO: conver to the "attrs" syntax for compile-time known sizes + if self.attributes.len() > 0 { + let attr = &self.attributes; + tokens.append_all(quote! { + .attributes([ #(#attr),* ]) + }) + } + + if self.children.len() > 0 { + let childs = &self.children; + tokens.append_all(quote! { + .children([ #(#childs),* ]) + }); + } + + if self.listeners.len() > 0 { + let listeners = &self.listeners; + tokens.append_all(quote! { + .listeners([ #(#listeners),* ]) + }); + } + + tokens.append_all(quote! { + .finish() + }); + } +} + impl Parse for Element { fn parse(stream: ParseStream) -> Result { - // let name = Ident::parse(stream)?; + // TODO: remove this in favor of the compile-time validation system if !crate::util::is_valid_tag(&name.to_string()) { return Err(Error::new(name.span(), "Not a valid Html tag")); } @@ -30,20 +70,19 @@ impl Parse for Element { let content: ParseBuffer; syn::braced!(content in stream); - let mut attrs: Vec = vec![]; + let mut attributes: Vec = vec![]; + let mut listeners: Vec = vec![]; let mut children: Vec = vec![]; + let mut key = None; + 'parsing: loop { // [1] Break if empty if content.is_empty() { break 'parsing; } - let forked = content.fork(); - if forked.call(Ident::parse_any).is_ok() - && forked.parse::().is_ok() - && forked.parse::().is_err() - { - attrs.push(content.parse::()?); + if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) { + parse_element_body(&content, &mut attributes, &mut listeners, &mut key)?; } else { children.push(content.parse::()?); } @@ -56,69 +95,22 @@ impl Parse for Element { } Ok(Self { + key, name, - attrs, + attributes, children, + listeners, }) } } -impl ToTokens for Element { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let name = &self.name.to_string(); - - tokens.append_all(quote! { - __cx.element(#name) - }); - // dioxus::builder::ElementBuilder::new(__cx, #name) - // dioxus::builder::ElementBuilder::new(__cx, #name) - - // Add attributes - // TODO: conver to the "attrs" syntax for compile-time known sizes - for attr in self.attrs.iter() { - attr.to_tokens(tokens); - } - - // let mut children = self.children.iter(); - // while let Some(child) = children.next() { - // let inner_toks = child.to_token_stream(); - // tokens.append_all(quote! { - // .iter_child(#inner_toks) - // }) - // } - - let mut childs = quote! {}; - for child in &self.children { - match child { - Node::Text(e) => e.to_tokens(&mut childs), - Node::Element(e) => e.to_tokens(&mut childs), - Node::RawExpr(e) => quote! { - __cx.fragment_from_iter(#e) - } - .to_tokens(&mut childs), - } - childs.append_all(quote! {,}) - } - if self.children.len() > 0 { - tokens.append_all(quote! { - .children([ - #childs - ]) - }); - } - - tokens.append_all(quote! { - .finish() - }); - } -} - /// ======================================= /// Parse a VElement's Attributes /// ======================================= struct ElementAttr { name: Ident, - ty: AttrType, + value: AttrType, + namespace: Option, } enum AttrType { @@ -128,132 +120,142 @@ enum AttrType { Event(ExprClosure), } -impl Parse for ElementAttr { - fn parse(s: ParseStream) -> Result { - let mut name = Ident::parse_any(s)?; - let name_str = name.to_string(); - s.parse::()?; +// We parse attributes and dump them into the attribute vec +// This is because some tags might be namespaced (IE style) +// These dedicated tags produce multiple name-spaced attributes +fn parse_element_body( + stream: ParseStream, + attrs: &mut Vec, + listeners: &mut Vec, + key: &mut Option, +) -> Result<()> { + let mut name = Ident::parse_any(stream)?; + let name_str = name.to_string(); + stream.parse::()?; - // Check if this is an event handler - // If so, parse into literal tokens - let ty = if name_str.starts_with("on") { - // remove the "on" bit - name = Ident::new(&name_str.trim_start_matches("on"), name.span()); + // Return early if the field is a listener + if name_str.starts_with("on") { + // remove the "on" bit + // name = Ident::new(&name_str.trim_start_matches("on"), name.span()); - if s.peek(token::Brace) { - let content; - syn::braced!(content in s); + let ty = if stream.peek(token::Brace) { + let content; + syn::braced!(content in stream); - // Try to parse directly as a closure - let fork = content.fork(); - if let Ok(event) = fork.parse::() { - content.advance_to(&fork); - AttrType::Event(event) - } else { - AttrType::EventTokens(content.parse()?) - } + // Try to parse directly as a closure + let fork = content.fork(); + if let Ok(event) = fork.parse::() { + content.advance_to(&fork); + AttrType::Event(event) } else { - AttrType::Event(s.parse()?) + AttrType::EventTokens(content.parse()?) } } else { - match name_str.as_str() { - "key" => { - // todo: better error here - AttrType::BumpText(s.parse::()?) - } - // "style" => { - // // - // todo!("inline style not yet supported") - // } - "classes" => { - // - todo!("custom class lsit not supported") - } - "namespace" => { - // - todo!("custom namespace not supported") - } - "ref" => { - // - todo!("custom ref not supported") - } - _ => { - if s.peek(LitStr) { - let rawtext = s.parse::().unwrap(); - AttrType::BumpText(rawtext) - } else { - let toks = s.parse::()?; - AttrType::FieldTokens(toks) - } + AttrType::Event(stream.parse()?) + }; + listeners.push(ElementAttr { + name, + value: ty, + namespace: None, + }); + return Ok(()); + } + + let ty: AttrType = match name_str.as_str() { + // short circuit early if style is using the special syntax + "style" if stream.peek(token::Brace) => { + let inner; + syn::braced!(inner in stream); + + while !inner.is_empty() { + let name = Ident::parse_any(&inner)?; + inner.parse::()?; + let ty = if inner.peek(LitStr) { + let rawtext = inner.parse::().unwrap(); + AttrType::BumpText(rawtext) + } else { + let toks = inner.parse::()?; + AttrType::FieldTokens(toks) + }; + if inner.peek(Token![,]) { + let _ = inner.parse::(); } + attrs.push(ElementAttr { + name, + value: ty, + namespace: Some("style".to_string()), + }); } - // let lit_str = if name_str == "style" && s.peek(token::Brace) { - // // special-case to deal with literal styles. - // let outer; - // syn::braced!(outer in s); - // // double brace for inline style. - // // todo!("Style support not ready yet"); - - // // if outer.peek(token::Brace) { - // // let inner; - // // syn::braced!(inner in outer); - // // let styles: Styles = inner.parse()?; - // // MaybeExpr::Literal(LitStr::new(&styles.to_string(), Span::call_site())) - // // } else { - // // just parse as an expression - // outer.parse()? - // // } - // } else { - // s.parse()? - // }; - }; - - // consume comma if it exists - // we don't actually care if there *are* commas between attrs - if s.peek(Token![,]) { - let _ = s.parse::(); + return Ok(()); + } + "key" => { + *key = Some(AttrType::BumpText(stream.parse::()?)); + return Ok(()); + } + "classes" => { + todo!("custom class lsit not supported") + } + "namespace" => { + todo!("custom namespace not supported") + } + "ref" => { + todo!("NodeRefs are currently not supported! This is currently a reserved keyword.") } - Ok(ElementAttr { name, ty }) + // Fall through + _ => { + if stream.peek(LitStr) { + let rawtext = stream.parse::().unwrap(); + AttrType::BumpText(rawtext) + } else { + let toks = stream.parse::()?; + AttrType::FieldTokens(toks) + } + } + }; + + // consume comma if it exists + // we don't actually care if there *are* commas between attrs + if stream.peek(Token![,]) { + let _ = stream.parse::(); } + + attrs.push(ElementAttr { + name, + value: ty, + namespace: None, + }); + Ok(()) } impl ToTokens for ElementAttr { fn to_tokens(&self, tokens: &mut TokenStream2) { let name = self.name.to_string(); let nameident = &self.name; - let _attr_stream = TokenStream2::new(); - match &self.ty { - AttrType::BumpText(value) => match name.as_str() { - "key" => { - tokens.append_all(quote! { - .key2(format_args_f!(#value)) - }); - } - _ => { - tokens.append_all(quote! { - .attr(#name, format_args_f!(#value)) - }); - } - }, - AttrType::FieldTokens(exp) => { - tokens.append_all(quote! { - .attr(#name, #exp) - }); - } - AttrType::Event(event) => { - tokens.append_all(quote! { - .add_listener(dioxus::events::on::#nameident(__cx, #event)) - }); - } - AttrType::EventTokens(event) => { - // - tokens.append_all(quote! { - .add_listener(dioxus::events::on::#nameident(__cx, #event)) - }); - } + let namespace = match &self.namespace { + Some(t) => quote! { Some(#t) }, + None => quote! { None }, + }; + + match &self.value { + AttrType::BumpText(value) => tokens.append_all(quote! { + __cx.attr(#name, format_args_f!(#value), #namespace) + }), + + AttrType::FieldTokens(exp) => tokens.append_all(quote! { + __cx.attr(#name, #exp, #namespace) + }), + + // todo: move event handlers on to the elements or onto the nodefactory + AttrType::Event(event) => tokens.append_all(quote! { + dioxus::events::on::#nameident(__cx, #event) + }), + + AttrType::EventTokens(event) => tokens.append_all(quote! { + dioxus::events::on::#nameident(__cx, #event) + }), } } } diff --git a/packages/core-macro/src/rsx/mod.rs b/packages/core-macro/src/rsx/mod.rs index a10c8d7cc..44fce223b 100644 --- a/packages/core-macro/src/rsx/mod.rs +++ b/packages/core-macro/src/rsx/mod.rs @@ -80,33 +80,19 @@ impl ToTokens for RsxRender { quote! {#inner} } else { let childs = &self.roots; - let children = quote! { - ChildrenList::new(__cx) - #( .add_child(#childs) )* - .finish() - }; - quote! { - // #key_token, - dioxus::builder::vfragment( - __cx, - None, - #children - ) - } + quote! { __cx.fragment_from_iter(&[ #(#childs),* ]) } }; match &self.custom_context { // The `in cx` pattern allows directly rendering Some(ident) => out_tokens.append_all(quote! { - #ident.render(dioxus::prelude::LazyNodes::new(move |__cx|{ - // let bump = &__cx.bump(); + #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory|{ #inner })) }), // Otherwise we just build the LazyNode wrapper None => out_tokens.append_all(quote! { dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory|{ - // let bump = &__cx.bump(); #inner }) }), diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs index dc91ca3a8..e635d525d 100644 --- a/packages/core-macro/src/rsx/node.rs +++ b/packages/core-macro/src/rsx/node.rs @@ -21,7 +21,9 @@ impl ToTokens for Node { match &self { Node::Element(el) => el.to_tokens(tokens), Node::Text(txt) => txt.to_tokens(tokens), - Node::RawExpr(exp) => exp.to_tokens(tokens), + Node::RawExpr(exp) => tokens.append_all(quote! { + __cx.fragment_from_iter(#exp) + }), } } } diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 27524615d..106e0a27b 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -1326,69 +1326,69 @@ mod tests { use crate::util::DebugDom; use dioxus_core_macro::*; - #[test] - fn test_child_iterator() { - static App: FC<()> = |cx| { - cx.render(rsx! { - Fragment { - div {} - h1 {} - h2 {} - h3 {} - Fragment { - "internal node" - div { - "baller text shouldn't show up" - } - p { + // #[test] + // fn test_child_iterator() { + // static App: FC<()> = |cx| { + // cx.render(rsx! { + // Fragment { + // div {} + // h1 {} + // h2 {} + // h3 {} + // Fragment { + // "internal node" + // div { + // "baller text shouldn't show up" + // } + // p { - } - Fragment { - Fragment { - "wow you really like framgents" - Fragment { - "why are you like this" - Fragment { - "just stop now please" - Fragment { - "this hurts" - Fragment { - "who needs this many fragments?????" - Fragment { - "just... fine..." - Fragment { - "no" - } - } - } - } - } - } - } - } - } - "my text node 1" - "my text node 2" - "my text node 3" - "my text node 4" - } - }) - }; - let mut dom = VirtualDom::new(App); - let mut renderer = DebugDom::new(); - dom.rebuild(&mut renderer).unwrap(); - let starter = dom.base_scope().root(); - let ite = RealChildIterator::new(starter, &dom.components); - for child in ite { - match child { - VNode::Element(el) => println!("Found: Element {}", el.tag_name), - VNode::Text(t) => println!("Found: Text {:?}", t.text), + // } + // Fragment { + // Fragment { + // "wow you really like framgents" + // Fragment { + // "why are you like this" + // Fragment { + // "just stop now please" + // Fragment { + // "this hurts" + // Fragment { + // "who needs this many fragments?????" + // Fragment { + // "just... fine..." + // Fragment { + // "no" + // } + // } + // } + // } + // } + // } + // } + // } + // } + // "my text node 1" + // "my text node 2" + // "my text node 3" + // "my text node 4" + // } + // }) + // }; + // let mut dom = VirtualDom::new(App); + // let mut renderer = DebugDom::new(); + // dom.rebuild(&mut renderer).unwrap(); + // let starter = dom.base_scope().root(); + // let ite = RealChildIterator::new(starter, &dom.components); + // for child in ite { + // match child { + // VNode::Element(el) => println!("Found: Element {}", el.tag_name), + // VNode::Text(t) => println!("Found: Text {:?}", t.text), - // These would represent failing cases. - VNode::Fragment(_) => panic!("Found: Fragment"), - VNode::Suspended { real } => panic!("Found: Suspended"), - VNode::Component(_) => panic!("Found: Component"), - } - } - } + // // These would represent failing cases. + // VNode::Fragment(_) => panic!("Found: Fragment"), + // VNode::Suspended { real } => panic!("Found: Suspended"), + // VNode::Component(_) => panic!("Found: Component"), + // } + // } + // } } diff --git a/packages/core/src/events.rs b/packages/core/src/events.rs index b551f2189..b219b822a 100644 --- a/packages/core/src/events.rs +++ b/packages/core/src/events.rs @@ -123,10 +123,25 @@ pub mod on { use super::VirtualEvent; macro_rules! event_directory { - ( $( $eventdata:ident($wrapper:ident): [ $( $name:ident )* ]; )* ) => { + ( $( $( + #[$attr:meta] + )* + $eventdata:ident($wrapper:ident): [ + $( + #[$method_attr:meta] + )* + $( $name:ident )* + ]; + )* ) => { + $( + $(#[$attr])* #[derive(Debug)] pub struct $wrapper(pub Rc); + + // todo: derefing to the event is fine (and easy) but breaks some IDE stuff like (go to source) + // going to source in fact takes you to the source of Rc which is... less than useful + // Either we ask for this to be changed in Rust-analyzer or manually impkement the trait impl Deref for $wrapper { type Target = Rc; fn deref(&self) -> &Self::Target { @@ -134,6 +149,7 @@ pub mod on { } } + $(#[$method_attr])* $( pub fn $name<'a>( c: &'_ NodeFactory<'a>, @@ -155,17 +171,112 @@ pub mod on { }; } + // The Dioxus Synthetic event system + // + // + // + // + // + // + // + // event_directory! { - ClipboardEventInner(ClipboardEvent): [copy cut paste]; - CompositionEventInner(CompositionEvent): [compositionend compositionstart compositionupdate]; - KeyboardEventInner(KeyboardEvent): [keydown keypress keyup]; - FocusEventInner(FocusEvent): [focus blur]; - FormEventInner(FormEvent): [change input invalid reset submit]; - MouseEventInner(MouseEvent): [ - click contextmenu doubleclick drag dragend dragenter dragexit - dragleave dragover dragstart drop mousedown mouseenter mouseleave - mousemove mouseout mouseover mouseup + + + + + ClipboardEventInner(ClipboardEvent): [ + /// Called when "copy" + oncopy + oncut + onpaste ]; + CompositionEventInner(CompositionEvent): [ + oncompositionend + oncompositionstart + oncompositionupdate + ]; + KeyboardEventInner(KeyboardEvent): [ + onkeydown + onkeypress + onkeyup + ]; + FocusEventInner(FocusEvent): [ + onfocus + onblur + ]; + FormEventInner(FormEvent): [ + onchange + oninput + oninvalid + onreset + onsubmit + ]; + + + /// A synthetic event that wraps a web-style [`MouseEvent`](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) + /// + /// + /// The MouseEvent interface represents events that occur due to the user interacting with a pointing device (such as a mouse). + /// + /// ## Trait implementation: + /// ```rust + /// fn alt_key(&self) -> bool; + /// fn button(&self) -> i16; + /// fn buttons(&self) -> u16; + /// fn client_x(&self) -> i32; + /// fn client_y(&self) -> i32; + /// fn ctrl_key(&self) -> bool; + /// fn meta_key(&self) -> bool; + /// fn page_x(&self) -> i32; + /// fn page_y(&self) -> i32; + /// fn screen_x(&self) -> i32; + /// fn screen_y(&self) -> i32; + /// fn shift_key(&self) -> bool; + /// fn get_modifier_state(&self, key_code: &str) -> bool; + /// ``` + /// + /// ## Event Handlers + /// - click + /// - contextmenu + /// - doubleclick + /// - drag + /// - dragend + /// - dragenter + /// - dragexit + /// - dragleave + /// - dragover + /// - dragstart + /// - drop + /// - mousedown + /// - mouseenter + /// - mouseleave + /// - mousemove + /// - mouseout + /// - mouseover + /// - mouseup + MouseEventInner(MouseEvent): [ + /// Onclick! + onclick + oncontextmenu + ondoubleclick + ondrag + ondragend + ondragenter + ondragexit + ondragleave + ondragover + ondragstart + ondrop + onmousedown + onmouseenter + onmouseleave + onmousemove + onmouseout + onmouseover + onmouseup + ]; + PointerEventInner(PointerEvent): [ pointerdown pointermove pointerup pointercancel gotpointercapture lostpointercapture pointerenter pointerleave pointerover pointerout @@ -293,6 +404,8 @@ pub mod on { fn alt_key(&self) -> bool; fn button(&self) -> i16; fn buttons(&self) -> u16; + + /// Get the X coordinate of the mouse relative to the window fn client_x(&self) -> i32; fn client_y(&self) -> i32; fn ctrl_key(&self) -> bool; @@ -597,25 +710,25 @@ pub mod on { } } -mod tests { +// mod tests { - use std::rc::Rc; +// use std::rc::Rc; - use crate as dioxus; - use crate::events::on::MouseEvent; - use crate::prelude::*; +// use crate as dioxus; +// use crate::events::on::MouseEvent; +// use crate::prelude::*; - fn autocomplete() { - // let v = move |evt| { - // let r = evt.alt_key(); - // }; +// fn autocomplete() { +// // let v = move |evt| { +// // let r = evt.alt_key(); +// // }; - let g = rsx! { - button { - onclick: move |evt| { - let r = evt.alt_key(); - } - } - }; - } -} +// let g = rsx! { +// button { +// onclick: move |evt| { +// let r = evt.alt_key(); +// } +// } +// }; +// } +// } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 359d306c4..150ba68e5 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -13,6 +13,7 @@ pub mod serialize; pub mod arena; pub mod component; +pub mod styles; pub mod util; // Logic for extending FC pub mod debug_renderer; @@ -54,6 +55,7 @@ pub(crate) mod innerlude { pub mod prelude { pub use crate::component::{fc_to_builder, Fragment, Properties}; use crate::nodes; + pub use crate::styles::{AsAttr, StyleBuilder}; pub use crate::virtual_dom::Context; pub use crate::virtual_dom::Scoped; pub use nodes::*; @@ -61,7 +63,7 @@ pub mod prelude { pub use crate::nodebuilder::LazyNodes; pub use crate::nodebuilder::ChildrenList; - pub use crate::nodebuilder::NodeFactory; + pub use crate::nodebuilder::{DioxusElement, NodeFactory}; // pub use nodes::iterables::IterableNodes; /// This type alias is an internal way of abstracting over the static functions that represent components. pub use crate::innerlude::FC; diff --git a/packages/core/src/nodebuilder.rs b/packages/core/src/nodebuilder.rs index 095185c54..bc3f8b140 100644 --- a/packages/core/src/nodebuilder.rs +++ b/packages/core/src/nodebuilder.rs @@ -13,7 +13,7 @@ use bumpalo::Bump; use crate::{ events::VirtualEvent, - innerlude::{Properties, VComponent, FC}, + innerlude::{Properties, VComponent, VText, FC}, nodes::{Attribute, Listener, NodeKey, VNode}, prelude::{VElement, VFragment}, virtual_dom::{RealDomNode, Scope}, @@ -34,7 +34,6 @@ where cx: &'b NodeFactory<'a>, key: NodeKey<'a>, tag_name: &'static str, - // tag_name: &'a str, listeners: Listeners, attributes: Attributes, children: Children, @@ -422,7 +421,11 @@ where } }; - self.attributes.push(Attribute { name, value }); + self.attributes.push(Attribute { + name, + value, + namespace: None, + }); self } @@ -455,7 +458,11 @@ where /// ``` pub fn bool_attr(mut self, name: &'static str, should_add: bool) -> Self { if should_add { - self.attributes.push(Attribute { name, value: "" }); + self.attributes.push(Attribute { + name, + value: "", + namespace: None, + }); } self } @@ -659,13 +666,17 @@ pub fn text3<'a>(bump: &'a bumpalo::Bump, args: std::fmt::Arguments) -> VNode<'a // ``` // div {"abc"} // ``` + VNode::text(raw_text(bump, args)) +} + +pub fn raw_text<'a>(bump: &'a bumpalo::Bump, args: std::fmt::Arguments) -> &'a str { match args.as_str() { - Some(static_str) => VNode::text(static_str), + Some(static_str) => 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()) + s.into_bump_str() } } } @@ -683,7 +694,11 @@ pub fn text3<'a>(bump: &'a bumpalo::Bump, args: std::fmt::Arguments) -> VNode<'a /// let my_id_attr = attr("id", "my-id"); /// ``` pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> { - Attribute { name, value } + Attribute { + name, + value, + namespace: None, + } } pub fn virtual_child<'a, T: Properties + 'a>( @@ -762,7 +777,7 @@ impl<'a> NodeFactory<'a> { /// Create an element builder pub fn element<'b>( &'b self, - tag_name: &'static str, + tag: impl DioxusElement, ) -> ElementBuilder< 'a, 'b, @@ -770,7 +785,21 @@ impl<'a> NodeFactory<'a> { bumpalo::collections::Vec<'a, Attribute<'a>>, bumpalo::collections::Vec<'a, VNode<'a>>, > { - ElementBuilder::new(self, tag_name) + ElementBuilder::new(self, tag.tag_name()) + } + + pub fn attr( + &self, + name: &'static str, + val: Arguments<'a>, + namespace: Option<&'static str>, + ) -> Attribute<'a> { + let value = raw_text(self.bump(), val); + Attribute { + name, + value, + namespace, + } } pub fn child_list(&self) -> ChildrenList { @@ -813,3 +842,11 @@ impl Debug for NodeFactory<'_> { Ok(()) } } + +pub trait DioxusElement { + const TAG_NAME: &'static str; + const NAME_SPACE: Option<&'static str>; + fn tag_name(&self) -> &'static str { + Self::TAG_NAME + } +} diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index 3af83c052..5839eabca 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -216,6 +216,11 @@ pub struct VElement<'a> { pub struct Attribute<'a> { pub name: &'static str, pub value: &'a str, + + /// If an attribute is "namespaced", then it belongs to a group + /// The most common namespace is the "style" namespace + // pub is_dynamic: bool, + pub namespace: Option<&'static str>, } impl<'a> Attribute<'a> { diff --git a/packages/core/src/styles.rs b/packages/core/src/styles.rs index 38d76d98d..433ea55f0 100644 --- a/packages/core/src/styles.rs +++ b/packages/core/src/styles.rs @@ -1,6 +1,10 @@ //! Dedicated styling system for Components //! --------------------------------------- //! +//! In the future, we'd like to move this out of Dioxus core or build a better, more general abstraction. For now, dedicated +//! styling is more-or-less hardcoded into Dioxus. +//! +//! //! //! //! @@ -8,76 +12,108 @@ //! //! -enum Styles { - background, - backgroundAttachment, - backgroundColor, - backgroundImage, - backgroundPosition, - backgroundRepeat, - border, - borderBottom, - borderBottomColor, - borderBottomStyle, - borderBottomWidth, - borderColor, - borderLeft, - borderLeftColor, - borderLeftStyle, - borderLeftWidth, - borderRight, - borderRightColor, - borderRightStyle, - borderRightWidth, - borderStyle, - borderTop, - borderTopColor, - borderTopStyle, - borderTopWidth, - borderWidth, - clear, - clip, - color, - cursor, - display, - filter, - cssFloat, - font, - fontFamily, - fontSize, - fontVariant, - fontWeight, - height, - left, - letterSpacing, - lineHeight, - listStyle, - listStyleImage, - listStylePosition, - listStyleType, - margin, - marginBottom, - marginLeft, - marginRight, - marginTop, - overflow, - padding, - paddingBottom, - paddingLeft, - paddingRight, - paddingTop, - pageBreakAfter, - pageBreakBefore, - position, - strokeDasharray, - strokeDashoffset, - textAlign, - textDecoration, - textIndent, - textTransform, - top, - verticalAlign, - visibility, - width, - zIndex, +use crate::{ + innerlude::Attribute, + nodebuilder::{text3, NodeFactory}, +}; + +pub struct StyleBuilder; +pub trait AsAttr<'a> { + fn to_attr(self, field: &'static str, fac: &NodeFactory<'a>) -> Attribute<'a>; +} +impl<'a> AsAttr<'a> for std::fmt::Arguments<'a> { + fn to_attr(self, field: &'static str, fac: &NodeFactory<'a>) -> Attribute<'a> { + fac.attr(field, self, Some("style")) + } +} + +macro_rules! build_styles { + ($ ($name:ident: $lit:literal,)* ) => { + impl StyleBuilder { + $( + pub fn $name<'a>(f: &NodeFactory<'a>, args: impl AsAttr<'a>) -> Attribute<'a> { + args.to_attr($lit, f) + } + )* + } + }; +} + +build_styles! { + background: "background", + background_attachment: "background-attachment", + background_color: "background-color", + background_image: "background-image", + background_position: "background-position", + background_repeat: "background-repeat", + border: "border", + border_bottom: "border-bottom", + border_bottom_color: "border-bottom-color", + border_bottom_style: "border-bottom-style", + border_bottom_width: "border-bottom-width", + border_color: "border-color", + border_left: "border-left", + border_left_color: "border-left-color", + border_left_style: "border-left-style", + border_left_width: "border-left-width", + border_right: "border-right", + border_right_color: "border-right-color", + border_right_style: "border-right-style", + border_right_width: "border-right-width", + border_style: "border-style", + border_top: "border-top", + border_top_color: "border-top-color", + border_top_style: "border-top-style", + border_top_width: "border-top-width", + border_width: "border-width", + clear: "clear", + clip: "clip", + color: "color", + cursor: "cursor", + display: "display", + filter: "filter", + css_float: "css-float", + font: "font", + font_family: "font-family", + font_size: "font-size", + font_variant: "font-variant", + font_weight: "font-weight", + height: "height", + left: "left", + letter_spacing: "letter-spacing", + line_height: "line-height", + list_style: "list-style", + list_style_image: "list-style-image", + list_style_position: "list-style-position", + list_style_type: "list-style-type", + margin: "margin", + margin_bottom: "margin-bottom", + margin_left: "margin-left", + margin_right: "margin-right", + margin_top: "margin-top", + overflow: "overflow", + padding: "padding", + padding_bottom: "padding-bottom", + padding_left: "padding-left", + padding_right: "padding-right", + padding_top: "padding-top", + page_break_after: "page-break-after", + page_break_before: "page-break-before", + position: "position", + stroke_dasharray: "stroke-dasharray", + stroke_dashoffset: "stroke-dashoffset", + text_align: "text-align", + text_decoration: "text-decoration", + text_indent: "text-indent", + text_transform: "text-transform", + top: "top", + vertical_align: "vertical-align", + visibility: "visibility", + width: "width", + z_index: "z-index", +} + +fn example(f: &NodeFactory) { + let style_list = &[("width", "10"), ("text-decoration", "")]; + let styles = &[StyleBuilder::background(f, format_args!("10"))]; } diff --git a/packages/html-namespace/Cargo.toml b/packages/html-namespace/Cargo.toml index f06687251..5d6e8a6f2 100644 --- a/packages/html-namespace/Cargo.toml +++ b/packages/html-namespace/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +dioxus-core = { path="../core" } [dev-dependencies] scraper = "0.12.0" diff --git a/packages/html-namespace/examples/attrlist.html b/packages/html-namespace/examples/attrlist.html deleted file mode 100644 index 6335b84ee..000000000 --- a/packages/html-namespace/examples/attrlist.html +++ /dev/null @@ -1,2598 +0,0 @@ - - - - accept - - - <form>, - <input> - - List of types the server accepts, typically a file type. - - - - accept-charset - - - <form> - - List of supported charsets. - - - - accesskey - - - Global attribute - - Keyboard shortcut to activate or add focus to the element. - - - - action - - - <form> - - - The URI of a program that processes the information submitted via the - form. - - - - - align - - - <applet>, - <caption>, <col>, - <colgroup>, <hr>, - <iframe>, <img>, - <table>, - <tbody>, <td>, - <tfoot> - , <th>, - <thead>, <tr> - - Specifies the horizontal alignment of the element. - - - - allow - - - <iframe> - - Specifies a feature-policy for the iframe. - - - - alt - - - <applet>, - <area>, <img>, - <input> - - Alternative text in case an image can't be displayed. - - - - async - - - <script> - - Executes the script asynchronously. - - - - autocapitalize - - - Global attribute - - - Sets whether input is automatically capitalized when entered by user - - - - - autocomplete - - - <form>, - <input>, - <select>, - <textarea> - - - Indicates whether controls in this form can by default have their values - automatically completed by the browser. - - - - - autofocus - - - <button>, - <input>, - <keygen>, - <select>, - <textarea> - - The element should be automatically focused after the page loaded. - - - - autoplay - - - <audio>, - <video> - - The audio or video should play as soon as possible. - - - background - - <body>, - <table>, <td>, <th> - - - Specifies the URL of an image file. -
- Note: Although browsers and email clients may still - support this attribute, it is obsolete. Use CSS - background-image - instead. -
- - - - bgcolor - - <body>, <col>, - <colgroup>, - <marquee>, - <table>, - <tbody>, - <tfoot>, <td>, <th>, <tr> - - -

Background color of the element.

- -
-

- Note: This is a legacy attribute. Please use the CSS - background-color - property instead. -

-
- - - - border - - <img>, - <object>, - <table> - - -

The border width.

- -
-

- Note: This is a legacy attribute. Please use the CSS - border property - instead. -

-
- - - - - buffered - - - <audio>, - <video> - - Contains the time range of already buffered media. - - - - capture - - - <input> - - - From the - HTML Media Capture
The definition of 'media capture' in that specification.
spec, specifies a new file can be captured. - - - - - challenge - - - <keygen> - - A challenge string that is submitted along with the public key. - - - - charset - - - <meta>, - <script> - - Declares the character encoding of the page or script. - - - - checked - - - <command>, - <input> - - Indicates whether the element should be checked on page load. - - - - cite - - - <blockquote>, <del>, <ins>, <q> - - Contains a URI which points to the source of the quote or change. - - - - class - - - Global attribute - - Often used with CSS to style elements with common properties. - - - - code - - - <applet> - - - Specifies the URL of the applet's class file to be loaded and executed. - - - - - codebase - - - <applet> - - - This attribute gives the absolute or relative URL of the directory where - applets' .class files referenced by the code attribute are stored. - - - - color - - <basefont>, - <font>, <hr> - - -

- This attribute sets the text color using either a named color or a color - specified in the hexadecimal #RRGGBB format. -

- -
-

- Note: This is a legacy attribute. Please use the CSS - color property - instead. -

-
- - - - - cols - - - <textarea> - - Defines the number of columns in a textarea. - - - - colspan - - - <td>, <th> - - - The colspan attribute defines the number of columns a cell should span. - - - - - content - - - <meta> - - - A value associated with http-equiv or - name depending on the context. - - - - - contenteditable - - - Global attribute - - Indicates whether the element's content is editable. - - - - contextmenu - - - Global attribute - - - Defines the ID of a - <menu> - element which will serve as the element's context menu. - - - - - controls - - - <audio>, - <video> - - - Indicates whether the browser should show playback controls to the user. - - - - - coords - - - <area> - - A set of values specifying the coordinates of the hot-spot region. - - - - crossorigin - - - <audio>, <img>, - <link>, - <script>, - <video> - - How the element handles cross-origin requests - - - - csp - - - - - - <iframe> - - - Specifies the Content Security Policy that an embedded document must agree - to enforce upon itself. - - - - - data - - - <object> - - Specifies the URL of the resource. - - - - data-* - - - Global attribute - - Lets you attach custom attributes to an HTML element. - - - - datetime - - - <del>, <ins>, - <time> - - Indicates the date and time associated with the element. - - - - decoding - - - <img> - - Indicates the preferred method to decode the image. - - - - default - - - <track> - - - Indicates that the track should be enabled unless the user's preferences - indicate something different. - - - - - defer - - - <script> - - - Indicates that the script should be executed after the page has been - parsed. - - - - - dir - - - Global attribute - - - Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl - (Right-To-Left) - - - - - dirname - - - <input>, - <textarea> - - - - - - disabled - - - <button>, - <command>, - <fieldset>, - <input>, - <keygen>, - <optgroup>, - <option>, - <select>, - <textarea> - - Indicates whether the user can interact with the element. - - - - download - - - <a>, - <area> - - - Indicates that the hyperlink is to be used for downloading a resource. - - - - - draggable - - - Global attribute - - Defines whether the element can be dragged. - - - - enctype - - - <form> - - - Defines the content type of the form data when the method is - POST. - - - - - enterkeyhint - - - - - - <textarea>, - contenteditable - - - The - enterkeyhint - specifies what action label (or icon) to present for the enter key on - virtual keyboards. The attribute can be used with form controls (such as - the value of textarea elements), or in elements in an editing - host (e.g., using contenteditable attribute). - - - - - for - - - <label>, - <output> - - Describes elements which belongs to this one. - - - - form - - - <button>, - <fieldset>, - <input>, - <keygen>, - <label>, - <meter>, - <object>, - <output>, - <progress>, - <select>, - <textarea> - - Indicates the form that is the owner of the element. - - - - formaction - - - <input>, - <button> - - - Indicates the action of the element, overriding the action defined in the - <form>. - - - - - formenctype - - - <button>, - <input> - - - If the button/input is a submit button (type="submit"), this - attribute sets the encoding type to use during form submission. If this - attribute is specified, it overrides the enctype attribute of - the button's form owner. - - - - - formmethod - - - <button>, - <input> - - - If the button/input is a submit button (type="submit"), this - attribute sets the submission method to use during form submission - (GET, POST, etc.). If this attribute is - specified, it overrides the method attribute of the button's - form owner. - - - - - formnovalidate - - - <button>, - <input> - - - If the button/input is a submit button (type="submit"), this - boolean attribute specifies that the form is not to be validated when it - is submitted. If this attribute is specified, it overrides the - novalidate attribute of the button's - form owner. - - - - - formtarget - - - <button>, - <input> - - - If the button/input is a submit button (type="submit"), this - attribute specifies the browsing context (for example, tab, window, or - inline frame) in which to display the response that is received after - submitting the form. If this attribute is specified, it overrides the - target attribute of the button's - form owner. - - - - - headers - - - <td>, <th> - - - IDs of the <th> elements which applies to this element. - - - - height - - <canvas>, - <embed>, - <iframe>, <img>, - <input>, - <object>, - <video> - - -

- Specifies the height of elements listed here. For all other elements, - use the CSS - height property. -

- -
-

- Note: In some instances, such as - <div>, this is a legacy attribute, in which case the CSS - height property - should be used instead. -

-
- - - - - hidden - - - Global attribute - - - Prevents rendering of given element, while keeping child elements, e.g. - script elements, active. - - - - - high - - - <meter> - - Indicates the lower bound of the upper range. - - - - href - - - <a>, - <area>, - <base>, - <link> - - The URL of a linked resource. - - - - hreflang - - - <a>, - <area>, - <link> - - Specifies the language of the linked resource. - - - - http-equiv - - - <meta> - - Defines a pragma directive. - - - - icon - - - <command> - - Specifies a picture which represents the command. - - - - id - - - Global attribute - - - Often used with CSS to style a specific element. The value of this - attribute must be unique. - - - - - importance - - - - - - <iframe>, <img>, - <link>, - <script> - - Indicates the relative fetch priority for the resource. - - - - integrity - - - <link>, - <script> - - -

- Specifies a - Subresource Integrity - value that allows browsers to verify what they fetch. -

- - - - - intrinsicsize - - - - - - <img> - - - This attribute tells the browser to ignore the actual intrinsic size of - the image and pretend it’s the size specified in the attribute. - - - - - inputmode - - - <textarea>, - contenteditable - - - Provides a hint as to the type of data that might be entered by the user - while editing the element or its contents. The attribute can be used with - form controls (such as the value of textarea elements), or in - elements in an editing host (e.g., using - contenteditable attribute). - - - - - ismap - - - <img> - - Indicates that the image is part of a server-side image map. - - - - itemprop - - - Global attribute - - - - - - keytype - - - <keygen> - - Specifies the type of key generated. - - - - kind - - - <track> - - Specifies the kind of text track. - - - - label - - - <optgroup>, - <option>, - <track> - - Specifies a user-readable title of the element. - - - - lang - - - Global attribute - - Defines the language used in the element. - - - - language - - - - - - <script> - - Defines the script language used in the element. - - - - loading - - - - - - <img>, - <iframe> - - - Indicates if the element should be loaded lazily - (loading="lazy") or loaded immediately - (loading="eager"). -
- WIP: - WHATWG PR #3752 -
- - - - - list - - - <input> - - Identifies a list of pre-defined options to suggest to the user. - - - - loop - - - <audio>, - <bgsound>, - <marquee>, - <video> - - - Indicates whether the media should start playing from the start when it's - finished. - - - - - low - - - <meter> - - Indicates the upper bound of the lower range. - - - - manifest - - - - - - <html> - - - Specifies the URL of the document's cache manifest. -
- Note: This attribute is obsolete, use - <link rel="manifest"> - instead. -
- - - - - max - - - <input>, - <meter>, - <progress> - - Indicates the maximum value allowed. - - - - maxlength - - - <input>, - <textarea> - - Defines the maximum number of characters allowed in the element. - - - - minlength - - - <input>, - <textarea> - - Defines the minimum number of characters allowed in the element. - - - - media - - - <a>, - <area>, - <link>, - <source>, - <style> - - - Specifies a hint of the media for which the linked resource was designed. - - - - method - - <form> - - - Defines which HTTP method to use when - submitting the form. Can be GET (default) or - POST. - - - - - min - - - <input>, - <meter> - - Indicates the minimum value allowed. - - - - multiple - - - <input>, - <select> - - - Indicates whether multiple values can be entered in an input of the type - email or file. - - - - - muted - - - <audio>, - <video> - - - Indicates whether the audio will be initially silenced on page load. - - - - - name - - - <button>, - <form>, - <fieldset>, - <iframe>, - <input>, - <keygen>, - <object>, - <output>, - <select>, - <textarea>, <map>, - <meta>, - <param> - - - Name of the element. For example used by the server to identify the fields - in form submits. - - - - - novalidate - - - <form> - - - This attribute indicates that the form shouldn't be validated when - submitted. - - - - - open - - - <details> - - Indicates whether the details will be shown on page load. - - - - optimum - - - <meter> - - Indicates the optimal numeric value. - - - - pattern - - - <input> - - - Defines a regular expression which the element's value will be validated - against. - - - - - ping - - - <a>, - <area> - - - The ping attribute specifies a space-separated list of URLs - to be notified if a user follows the hyperlink. - - - - - placeholder - - - <input>, - <textarea> - - Provides a hint to the user of what can be entered in the field. - - - - poster - - - <video> - - - A URL indicating a poster frame to show until the user plays or seeks. - - - - - preload - - - <audio>, - <video> - - - Indicates whether the whole resource, parts of it or nothing should be - preloaded. - - - - - radiogroup - - - <command> - - - - - - readonly - - - <input>, - <textarea> - - Indicates whether the element can be edited. - - - - referrerpolicy - - - <a>, - <area>, - <iframe>, <img>, - <link>, - <script> - - Specifies which referrer is sent when fetching the resource. - - - - rel - - - <a>, - <area>, - <link> - - Specifies the relationship of the target object to the link object. - - - - required - - - <input>, - <select>, - <textarea> - - Indicates whether this element is required to fill out or not. - - - - reversed - - - <ol> - - - Indicates whether the list should be displayed in a descending order - instead of a ascending. - - - - - rows - - - <textarea> - - Defines the number of rows in a text area. - - - - rowspan - - - <td>, <th> - - Defines the number of rows a table cell should span over. - - - - sandbox - - - <iframe> - - - Stops a document loaded in an iframe from using certain features (such as - submitting forms or opening new windows). - - - - - scope - - - <th> - - - Defines the cells that the header test (defined in the - th element) relates to. - - - - - scoped - - - - - - - - - <style> - - - - - - selected - - - <option> - - Defines a value which will be selected on page load. - - - - shape - - - <a>, - <area> - - - - - - size - - - <input>, - <select> - - - Defines the width of the element (in pixels). If the element's - type attribute is text or - password then it's the number of characters. - - - - - sizes - - - <link>, <img>, - <source> - - - - - - slot - - - Global attribute - - Assigns a slot in a shadow DOM shadow tree to an element. - - - - span - - - <col>, - <colgroup> - - - - - - spellcheck - - - Global attribute - - Indicates whether spell checking is allowed for the element. - - - - src - - - <audio>, - <embed>, - <iframe>, <img>, - <input>, - <script>, - <source>, - <track>, - <video> - - The URL of the embeddable content. - - - - srcdoc - - - <iframe> - - - - - - srclang - - - <track> - - - - - - srcset - - - <img>, - <source> - - One or more responsive image candidates. - - - - start - - - <ol> - - Defines the first number if other than 1. - - - - step - - - <input> - - - - - - style - - - Global attribute - - Defines CSS styles which will override styles previously set. - - - - summary - - - - - - <table> - - - - - - tabindex - - - Global attribute - - - Overrides the browser's default tab order and follows the one specified - instead. - - - - - target - - - <a>, - <area>, - <base>, - <form> - - - Specifies where to open the linked document (in the case of an - <a> element) or where to display the response received - (in the case of a <form> element) - - - - - title - - - Global attribute - - Text to be displayed in a tooltip when hovering over the element. - - - - translate - - - Global attribute - - - Specify whether an element’s attribute values and the values of its - Text - node children are to be translated when the page is localized, or whether - to leave them unchanged. - - - - - type - - - <button>, - <input>, - <command>, - <embed>, - <object>, - <script>, - <source>, - <style>, - <menu> - - Defines the type of the element. - - - - usemap - - - <img>, - <input>, - <object> - - - - - - value - - - <button>, - <data>, - <input>, <li>, - <meter>, - <option>, - <progress>, - <param> - - - Defines a default value which will be displayed in the element on page - load. - - - - - width - - - <canvas>, - <embed>, - <iframe>, <img>, - <input>, - <object>, - <video> - - -

For the elements listed here, this establishes the element's width.

- -
-

- Note: For all other instances, such as - <div>, this is a legacy attribute, in which case the CSS - width property - should be used instead. -

-
- - - - - wrap - - - <textarea> - - Indicates whether the text should be wrapped. - - diff --git a/packages/html-namespace/examples/namespace.rs b/packages/html-namespace/examples/namespace.rs deleted file mode 100644 index 5c9cfe87b..000000000 --- a/packages/html-namespace/examples/namespace.rs +++ /dev/null @@ -1,42 +0,0 @@ -use scraper::{Html, Selector}; - -struct AttrClass { - attr_name: String, - attr_doc_link: String, - target_elements: Vec, - docs: String, -} - -const contents: &str = ""; -// let contents = include_str!("./attrlist.html"); -fn main() { - let mut items: Vec = Vec::new(); - - let fragment = Html::parse_fragment(contents); - - let ul_selector = Selector::parse("tbody").unwrap(); - let li_selector = Selector::parse("tr").unwrap(); - - let ul = fragment.select(&ul_selector).next().unwrap(); - for element in ul.select(&li_selector) { - let mut childs = element.children().into_iter(); - - let attr_field_node = childs.next().unwrap(); - let elements_node = childs.next().unwrap(); - let description_node = childs.next().unwrap(); - - // let attr_name = { todo!() }; - // let attr_doc_link = { todo!() }; - // let target_elements = { todo!() }; - - // let docs = description_node.text(); - - // todo!() - // items.push(AttrClass { - // attr_name, - // attr_doc_link, - // target_elements, - // docs, - // }) - } -} diff --git a/packages/html-namespace/examples/poc.rs b/packages/html-namespace/examples/poc.rs deleted file mode 100644 index 501fe3181..000000000 --- a/packages/html-namespace/examples/poc.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! POC: Planning the layout of a single element type -//! -//! -//! The ultimate goal with a dedicated namespace is three-fold: -//! - compile-time correct templates preventing misuse of elemnents -//! - deep integration of DSL with IDE -//! -//! -//! - -struct NodeFactory {} - -struct div<'a>(&NodeFactory); -impl<'a> div<'a> { - fn new(cx: &NodeFactory) -> Self { - div(cx) - } -} - -fn main() {} - -fn factory( - // this is your mom - cx: &NodeFactory, -) { - div::new(cx); - rsx! { - div {} - } -} diff --git a/packages/html-namespace/src/lib.rs b/packages/html-namespace/src/lib.rs index 02e1a635a..beeb4c8b6 100644 --- a/packages/html-namespace/src/lib.rs +++ b/packages/html-namespace/src/lib.rs @@ -1,37 +1,22 @@ -trait DioxusElement { - const TAG_NAME: &'static str; - const NAME_SPACE: Option<&'static str>; -} +//! # Dioxus Namespace for HTML +//! +//! This crate provides a set of compile-time correct HTML elements that can be used with the Rsx and Html macros. +//! This system allows users to easily build new tags, new types, and customize the output of the Rsx and Html macros. +//! +//! An added benefit of this approach is the ability to lend comprehensive documentation on how to use these elements inside +//! of the Rsx and Html macros. Each element comes with a substantial amount of documentation on how to best use it, hopefully +//! making the development cycle quick. -struct myinput {} - -struct NodeBuilder {} -impl NodeBuilder { - // fn add_attr() -} +use dioxus_core::prelude::{DioxusElement, NodeFactory}; macro_rules! builder_constructors { - ( $( - $(#[$attr:meta])* - $name:ident; - // { - // attrs: [ - // $( - // $(#[$attr2:meta])* - // $attr3:ident - // , - // )* - // ]; - // } - )* ) => { + ( $( $(#[$attr:meta])* $name:ident; )* ) => { $( #[allow(non_camel_case_types)] $(#[$attr])* - pub struct $name<'a> { - // the we wrap the builder, shielding what can be added - builder: &'a NodeBuilder - } - impl<'a> DioxusElement for $name<'a> { + pub struct $name; + + impl DioxusElement for $name { const TAG_NAME: &'static str = stringify!($name); const NAME_SPACE: Option<&'static str> = None; } @@ -48,6 +33,10 @@ macro_rules! builder_constructors { // https://developer.mozilla.org/en-US/docs/Web/HTML/Element // // Does not include obsolete elements. + +// This namespace represents a collection of modern HTML-5 compatiable elements. +// +// This list does not include obsolete, deprecated, experimental, or poorly supported elements. builder_constructors! { // Document metadata @@ -109,18 +98,57 @@ builder_constructors! { /// element. header; + /// Build a /// [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h1) /// element. + /// + /// # About + /// - The HTML `

` element is found within the `` tag. + /// - Headings can range from `

` to `

`. + /// - The most important heading is `

` and the least important heading is `

`. + /// - The `

` heading is the first heading in the document. + /// - The `

` heading is usually a large bolded font. + /// + /// # Usage + /// ``` + /// html!(

A header element

) + /// rsx!(h1 { "A header element" }) + /// LazyNodes::new(|f| f.el(h1).children([f.text("A header element")]).finish()) + /// ``` h1; + /// Build a /// [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h2) /// element. + /// + /// # About + /// - The HTML `

` element is found within the `` tag. + /// - Headings can range from `

` to `

`. + /// - The most important heading is `

` and the least important heading is `

`. + /// - The `

` heading is the second heading in the document. + /// - The `

` heading is usually a large bolded font. + /// + /// # Usage + /// ``` + /// html!(

A header element

) + /// rsx!(h2 { "A header element" }) + /// LazyNodes::new(|f| f.el(h2).children([f.text("A header element")]).finish()) + /// ``` h2; + + /// Build a /// [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h3) /// element. + /// + /// # About + /// - The HTML

element is found within the tag. + /// - Headings can range from

to

. + /// - The most important heading is

and the least important heading is

. + /// - The

heading is the first heading in the document. + /// - The

heading is usually a large bolded font. h3; /// Build a /// [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h4) @@ -134,10 +162,7 @@ builder_constructors! { /// [`

`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/h6) /// element. h6; - /// Build a - /// [`
`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hgroup) - /// element. - hgroup; + /// Build a /// [`
`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/main) /// element. @@ -268,22 +293,17 @@ builder_constructors! { /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q) /// element. q; - /// Build a - /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rb) - /// element. - rb; + /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rp) /// element. rp; + /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rt) /// element. rt; - /// Build a - /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/rtc) - /// element. - rtc; + /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ruby) /// element. @@ -521,18 +541,8 @@ builder_constructors! { /// [`
`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) /// element. details; - /// Build a - /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) - /// element. - dialog; - /// Build a - /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu) - /// element. - menu; - /// Build a - /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menuitem) - /// element. - menuitem; + + /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary) /// element. @@ -552,7 +562,6 @@ builder_constructors! { builder_constructors! { // SVG components - /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg) /// element. @@ -590,38 +599,3 @@ builder_constructors! { /// element. image <> "http://www.w3.org/2000/svg"; } - -macro_rules! impl_attrs { - ( $( - $(#[$attr:meta])* - $name:ident: [$($f:ident)*]; - )* ) => {}; -} - -impl_attrs! { - /// Indicates whether the user can interact with the element - disabled: [button command fieldset input keygen optgroup option select textarea]; - -} - -mod tests { - use super::*; - fn r#type() {} - - struct MyThing {} - impl MyThing { - /// eat my socks - fn r#type(&self) -> &Self { - self - } - fn nothing(&self) -> &Self { - self - } - } - fn test() { - let t = MyThing {}; - t.r#type().r#nothing(); - - // let g = div::TAG_NAME; - } -} diff --git a/packages/webview/src/dom.rs b/packages/webview/src/dom.rs index b6d792972..a11ee1ff3 100644 --- a/packages/webview/src/dom.rs +++ b/packages/webview/src/dom.rs @@ -11,16 +11,6 @@ use dioxus_core::{ use serde::{Deserialize, Serialize}; use DomEdits::*; -fn test() { - const App: FC<()> = |cx| cx.render(rsx! { div {}}); - let mut vi = VirtualDom::new(App); - let mut real = WebviewDom { - edits: Vec::new(), - node_counter: 0, - }; - vi.rebuild(&mut real); -} - pub struct WebviewDom<'bump> { pub edits: Vec>, pub node_counter: u64,