Merge pull request #895 from Demonthos/inline-custom-elements
Allow raw elements if they include a dash
This commit is contained in:
commit
7e96475951
|
@ -0,0 +1,13 @@
|
||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dioxus_desktop::launch(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app(cx: Scope) -> Element {
|
||||||
|
cx.render(rsx! {
|
||||||
|
web-component {
|
||||||
|
"my-prop": "5%",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use dioxus_rsx::{
|
use dioxus_rsx::{
|
||||||
BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, IfmtInput,
|
BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput,
|
||||||
};
|
};
|
||||||
pub use html_parser::{Dom, Node};
|
pub use html_parser::{Dom, Node};
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
|
@ -21,7 +21,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
||||||
Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))),
|
Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))),
|
||||||
Node::Element(el) => {
|
Node::Element(el) => {
|
||||||
let el_name = el.name.to_case(Case::Snake);
|
let el_name = el.name.to_case(Case::Snake);
|
||||||
let el_name = Ident::new(el_name.as_str(), Span::call_site());
|
let el_name = ElementName::Ident(Ident::new(el_name.as_str(), Span::call_site()));
|
||||||
|
|
||||||
let mut attributes: Vec<_> = el
|
let mut attributes: Vec<_> = el
|
||||||
.attributes
|
.attributes
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseBuffer, ParseStream},
|
parse::{Parse, ParseBuffer, ParseStream},
|
||||||
|
punctuated::Punctuated,
|
||||||
|
spanned::Spanned,
|
||||||
Error, Expr, Ident, LitStr, Result, Token,
|
Error, Expr, Ident, LitStr, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +16,7 @@ use syn::{
|
||||||
// =======================================
|
// =======================================
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub struct Element {
|
pub struct Element {
|
||||||
pub name: Ident,
|
pub name: ElementName,
|
||||||
pub key: Option<IfmtInput>,
|
pub key: Option<IfmtInput>,
|
||||||
pub attributes: Vec<ElementAttrNamed>,
|
pub attributes: Vec<ElementAttrNamed>,
|
||||||
pub children: Vec<BodyNode>,
|
pub children: Vec<BodyNode>,
|
||||||
|
@ -22,7 +26,7 @@ pub struct Element {
|
||||||
|
|
||||||
impl Parse for Element {
|
impl Parse for Element {
|
||||||
fn parse(stream: ParseStream) -> Result<Self> {
|
fn parse(stream: ParseStream) -> Result<Self> {
|
||||||
let el_name = Ident::parse(stream)?;
|
let el_name = ElementName::parse(stream)?;
|
||||||
|
|
||||||
// parse the guts
|
// parse the guts
|
||||||
let content: ParseBuffer;
|
let content: ParseBuffer;
|
||||||
|
@ -181,7 +185,7 @@ impl ToTokens for Element {
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
__cx.element(
|
__cx.element(
|
||||||
dioxus_elements::#name,
|
#name,
|
||||||
__cx.bump().alloc([ #(#listeners),* ]),
|
__cx.bump().alloc([ #(#listeners),* ]),
|
||||||
__cx.bump().alloc([ #(#attr),* ]),
|
__cx.bump().alloc([ #(#attr),* ]),
|
||||||
__cx.bump().alloc([ #(#children),* ]),
|
__cx.bump().alloc([ #(#children),* ]),
|
||||||
|
@ -191,6 +195,75 @@ impl ToTokens for Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
|
pub enum ElementName {
|
||||||
|
Ident(Ident),
|
||||||
|
Custom(LitStr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementName {
|
||||||
|
pub(crate) fn tag_name(&self) -> TokenStream2 {
|
||||||
|
match self {
|
||||||
|
ElementName::Ident(i) => quote! { dioxus_elements::#i::TAG_NAME },
|
||||||
|
ElementName::Custom(s) => quote! { #s },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ElementName {
|
||||||
|
pub fn span(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
ElementName::Ident(i) => i.span(),
|
||||||
|
ElementName::Custom(s) => s.span(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<&str> for ElementName {
|
||||||
|
fn eq(&self, other: &&str) -> bool {
|
||||||
|
match self {
|
||||||
|
ElementName::Ident(i) => i == *other,
|
||||||
|
ElementName::Custom(s) => s.value() == *other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ElementName {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ElementName::Ident(i) => write!(f, "{}", i),
|
||||||
|
ElementName::Custom(s) => write!(f, "{}", s.value()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ElementName {
|
||||||
|
fn parse(stream: ParseStream) -> Result<Self> {
|
||||||
|
let raw = Punctuated::<Ident, Token![-]>::parse_separated_nonempty(stream)?;
|
||||||
|
if raw.len() == 1 {
|
||||||
|
Ok(ElementName::Ident(raw.into_iter().next().unwrap()))
|
||||||
|
} else {
|
||||||
|
let span = raw.span();
|
||||||
|
let tag = raw
|
||||||
|
.into_iter()
|
||||||
|
.map(|ident| ident.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("-");
|
||||||
|
let tag = LitStr::new(&tag, span);
|
||||||
|
Ok(ElementName::Custom(tag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for ElementName {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
match self {
|
||||||
|
ElementName::Ident(i) => tokens.append_all(quote! { dioxus_elements::#i }),
|
||||||
|
ElementName::Custom(s) => tokens.append_all(quote! { #s }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub enum ElementAttr {
|
pub enum ElementAttr {
|
||||||
/// `attribute: "value"`
|
/// `attribute: "value"`
|
||||||
|
@ -234,7 +307,7 @@ impl ElementAttr {
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub struct ElementAttrNamed {
|
pub struct ElementAttrNamed {
|
||||||
pub el_name: Ident,
|
pub el_name: ElementName,
|
||||||
pub attr: ElementAttr,
|
pub attr: ElementAttr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,24 +315,46 @@ impl ToTokens for ElementAttrNamed {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
let ElementAttrNamed { el_name, attr } = self;
|
let ElementAttrNamed { el_name, attr } = self;
|
||||||
|
|
||||||
tokens.append_all(match attr {
|
let ns = |name| match el_name {
|
||||||
|
ElementName::Ident(i) => quote! { dioxus_elements::#i::#name.1 },
|
||||||
|
ElementName::Custom(_) => quote! { None },
|
||||||
|
};
|
||||||
|
let volitile = |name| match el_name {
|
||||||
|
ElementName::Ident(_) => quote! { #el_name::#name.2 },
|
||||||
|
ElementName::Custom(_) => quote! { false },
|
||||||
|
};
|
||||||
|
let attribute = |name: &Ident| match el_name {
|
||||||
|
ElementName::Ident(_) => quote! { #el_name::#name.0 },
|
||||||
|
ElementName::Custom(_) => {
|
||||||
|
let as_string = name.to_string();
|
||||||
|
quote!(#as_string)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let attribute = match attr {
|
||||||
ElementAttr::AttrText { name, value } => {
|
ElementAttr::AttrText { name, value } => {
|
||||||
|
let ns = ns(name);
|
||||||
|
let volitile = volitile(name);
|
||||||
|
let attribute = attribute(name);
|
||||||
quote! {
|
quote! {
|
||||||
__cx.attr(
|
__cx.attr(
|
||||||
dioxus_elements::#el_name::#name.0,
|
#attribute,
|
||||||
#value,
|
#value,
|
||||||
dioxus_elements::#el_name::#name.1,
|
#ns,
|
||||||
dioxus_elements::#el_name::#name.2
|
#volitile
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ElementAttr::AttrExpression { name, value } => {
|
ElementAttr::AttrExpression { name, value } => {
|
||||||
|
let ns = ns(name);
|
||||||
|
let volitile = volitile(name);
|
||||||
|
let attribute = attribute(name);
|
||||||
quote! {
|
quote! {
|
||||||
__cx.attr(
|
__cx.attr(
|
||||||
dioxus_elements::#el_name::#name.0,
|
#attribute,
|
||||||
#value,
|
#value,
|
||||||
dioxus_elements::#el_name::#name.1,
|
#ns,
|
||||||
dioxus_elements::#el_name::#name.2
|
#volitile
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,7 +383,9 @@ impl ToTokens for ElementAttrNamed {
|
||||||
dioxus_elements::events::#name(__cx, #tokens)
|
dioxus_elements::events::#name(__cx, #tokens)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
tokens.append_all(attribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -426,13 +426,25 @@ impl<'a> DynamicContext<'a> {
|
||||||
match root {
|
match root {
|
||||||
BodyNode::Element(el) => {
|
BodyNode::Element(el) => {
|
||||||
let el_name = &el.name;
|
let el_name = &el.name;
|
||||||
|
let ns = |name| match el_name {
|
||||||
|
ElementName::Ident(i) => quote! { dioxus_elements::#i::#name },
|
||||||
|
ElementName::Custom(_) => quote! { None },
|
||||||
|
};
|
||||||
let static_attrs = el.attributes.iter().map(|attr| match &attr.attr {
|
let static_attrs = el.attributes.iter().map(|attr| match &attr.attr {
|
||||||
ElementAttr::AttrText { name, value } if value.is_static() => {
|
ElementAttr::AttrText { name, value } if value.is_static() => {
|
||||||
let value = value.to_static().unwrap();
|
let value = value.to_static().unwrap();
|
||||||
|
let ns = ns(quote!(#name.1));
|
||||||
|
let name = match el_name {
|
||||||
|
ElementName::Ident(_) => quote! { #el_name::#name.0 },
|
||||||
|
ElementName::Custom(_) => {
|
||||||
|
let as_string = name.to_string();
|
||||||
|
quote! { #as_string }
|
||||||
|
}
|
||||||
|
};
|
||||||
quote! {
|
quote! {
|
||||||
::dioxus::core::TemplateAttribute::Static {
|
::dioxus::core::TemplateAttribute::Static {
|
||||||
name: dioxus_elements::#el_name::#name.0,
|
name: #name,
|
||||||
namespace: dioxus_elements::#el_name::#name.1,
|
namespace: #ns,
|
||||||
value: #value,
|
value: #value,
|
||||||
|
|
||||||
// todo: we don't diff these so we never apply the volatile flag
|
// todo: we don't diff these so we never apply the volatile flag
|
||||||
|
@ -479,10 +491,13 @@ impl<'a> DynamicContext<'a> {
|
||||||
let _opt = el.children.len() == 1;
|
let _opt = el.children.len() == 1;
|
||||||
let children = quote! { #(#children),* };
|
let children = quote! { #(#children),* };
|
||||||
|
|
||||||
|
let ns = ns(quote!(NAME_SPACE));
|
||||||
|
let el_name = el_name.tag_name();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
::dioxus::core::TemplateNode::Element {
|
::dioxus::core::TemplateNode::Element {
|
||||||
tag: dioxus_elements::#el_name::TAG_NAME,
|
tag: #el_name,
|
||||||
namespace: dioxus_elements::#el_name::NAME_SPACE,
|
namespace: #ns,
|
||||||
attrs: &[ #attrs ],
|
attrs: &[ #attrs ],
|
||||||
children: &[ #children ],
|
children: &[ #children ],
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,16 @@ impl Parse for BodyNode {
|
||||||
return Ok(BodyNode::Text(stream.parse()?));
|
return Ok(BodyNode::Text(stream.parse()?));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if this is a dash-separated path, it's a web component (custom element)
|
||||||
let body_stream = stream.fork();
|
let body_stream = stream.fork();
|
||||||
|
if let Ok(ElementName::Custom(name)) = body_stream.parse::<ElementName>() {
|
||||||
|
if name.value().contains('-') && body_stream.peek(token::Brace) {
|
||||||
|
return Ok(BodyNode::Element(stream.parse::<Element>()?));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let body_stream = stream.fork();
|
||||||
|
|
||||||
if let Ok(path) = body_stream.parse::<syn::Path>() {
|
if let Ok(path) = body_stream.parse::<syn::Path>() {
|
||||||
// this is an Element if path match of:
|
// this is an Element if path match of:
|
||||||
// - one ident
|
// - one ident
|
||||||
|
|
Loading…
Reference in New Issue