feat: add aria

This commit is contained in:
Jonathan Kelley committed 2021-07-13 00:56:39 -04:00
1 parent c79d9ae674
commit 4091846934
11 files changed
+322 -97

No files matched your search

+1 -1
View File
@@ -170,10 +170,10 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
| Suspense | 🛠 | ✅ | schedule future render from future/promise | | Suspense | 🛠 | ✅ | schedule future render from future/promise |
| Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events | | Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events |
| Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates | | Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates |
| Compile-time correct | ✅ | ❓ | Throw errors on invalid template layouts |
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) | | Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) |
| 1st class global state | ✅ | ❓ | redux/recoil/mobx on top of context | | 1st class global state | ✅ | ❓ | redux/recoil/mobx on top of context |
| Subtree Memoization | ✅ | ❓ | skip diffing static element subtrees | | Subtree Memoization | ✅ | ❓ | skip diffing static element subtrees |
| Compile-time correct | ✅ | ❓ | Throw errors on invalid template layouts |
| Heuristic Engine | 🛠 | ❓ | track component memory usage to minimize future allocations | | Heuristic Engine | 🛠 | ❓ | track component memory usage to minimize future allocations |
| NodeRef | 🛠 | ✅ | gain direct access to nodes [1] | | NodeRef | 🛠 | ✅ | gain direct access to nodes [1] |
+1 -1
View File
@@ -89,7 +89,7 @@ static Example: FC<()> = |cx| {
// Expressions can be used in element position too: // Expressions can be used in element position too:
{rsx!(p { "More templating!" })} {rsx!(p { "More templating!" })}
{html!(<p>"Even HTML templating!!"</p>)} // {html!(<p>"Even HTML templating!!"</p>)}
// Iterators // Iterators
{(0..10).map(|i| rsx!(li { "{i}" }))} {(0..10).map(|i| rsx!(li { "{i}" }))}
+4 -1
View File
@@ -2,7 +2,7 @@ use std::cell::Cell;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core::{ use dioxus_core::{
nodes::{NodeKey, VElement, VText}, nodes::{VElement, VText},
RealDomNode, RealDomNode,
}; };
@@ -23,6 +23,9 @@ const Example: FC<()> = |cx| {
Fragment { Fragment {
Fragment { Fragment {
"h1" "h1"
div {
}
} }
"h2" "h2"
} }
+1 -1
View File
@@ -188,7 +188,7 @@ impl ToTokens for Component {
#name, #name,
#builder, #builder,
#key_token, #key_token,
#children __cx.bump().alloc(#children)
) )
}) })
} }
+37 -34
View File
@@ -23,37 +23,18 @@ pub struct Element {
impl ToTokens for Element { impl ToTokens for Element {
fn to_tokens(&self, tokens: &mut TokenStream2) { fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = &self.name; let name = &self.name;
let attr = &self.attributes;
let childs = &self.children;
let listeners = &self.listeners;
tokens.append_all(quote! { tokens.append_all(quote! {
__cx.element(dioxus_elements::#name) __cx.element(
}); dioxus_elements::#name,
__cx.bump().alloc([ #(#listeners),* ]),
// By gating these methods, we can keep the output of `cargo expand` readable. __cx.bump().alloc([ #(#attr),* ]),
// We also prevent the issue where zero-sized arrays fail to have propery type inference. __cx.bump().alloc([ #(#childs),* ]),
None,
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()
}); });
} }
} }
@@ -83,7 +64,13 @@ impl Parse for Element {
} }
if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) { if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
parse_element_body(&content, &mut attributes, &mut listeners, &mut key)?; parse_element_body(
&content,
&mut attributes,
&mut listeners,
&mut key,
name.clone(),
)?;
} else { } else {
children.push(content.parse::<Node>()?); children.push(content.parse::<Node>()?);
} }
@@ -110,6 +97,7 @@ impl Parse for Element {
/// Parse a VElement's Attributes /// Parse a VElement's Attributes
/// ======================================= /// =======================================
struct ElementAttr { struct ElementAttr {
element_name: Ident,
name: Ident, name: Ident,
value: AttrType, value: AttrType,
namespace: Option<String>, namespace: Option<String>,
@@ -130,6 +118,7 @@ fn parse_element_body(
attrs: &mut Vec<ElementAttr>, attrs: &mut Vec<ElementAttr>,
listeners: &mut Vec<ElementAttr>, listeners: &mut Vec<ElementAttr>,
key: &mut Option<AttrType>, key: &mut Option<AttrType>,
element_name: Ident,
) -> Result<()> { ) -> Result<()> {
let mut name = Ident::parse_any(stream)?; let mut name = Ident::parse_any(stream)?;
let name_str = name.to_string(); let name_str = name.to_string();
@@ -159,6 +148,7 @@ fn parse_element_body(
name, name,
value: ty, value: ty,
namespace: None, namespace: None,
element_name: element_name.clone(),
}); });
return Ok(()); return Ok(());
} }
@@ -186,6 +176,7 @@ fn parse_element_body(
name, name,
value: ty, value: ty,
namespace: Some("style".to_string()), namespace: Some("style".to_string()),
element_name: element_name.clone(),
}); });
} }
@@ -227,13 +218,15 @@ fn parse_element_body(
name, name,
value: ty, value: ty,
namespace: None, namespace: None,
element_name,
}); });
Ok(()) Ok(())
} }
impl ToTokens for ElementAttr { impl ToTokens for ElementAttr {
fn to_tokens(&self, tokens: &mut TokenStream2) { fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = self.name.to_string(); let el_name = &self.element_name;
let name_str = self.name.to_string();
let nameident = &self.name; let nameident = &self.name;
let namespace = match &self.namespace { let namespace = match &self.namespace {
@@ -243,12 +236,22 @@ impl ToTokens for ElementAttr {
match &self.value { match &self.value {
AttrType::BumpText(value) => tokens.append_all(quote! { AttrType::BumpText(value) => tokens.append_all(quote! {
__cx.attr(#name, format_args_f!(#value), #namespace) dioxus_elements::#el_name.#nameident(__cx, format_args_f!(#value))
}), }),
// __cx.attr(#name, format_args_f!(#value), #namespace, false)
//
// AttrType::BumpText(value) => tokens.append_all(quote! {
// __cx.attr(#name, format_args_f!(#value), #namespace, false)
// }),
AttrType::FieldTokens(exp) => tokens.append_all(quote! { AttrType::FieldTokens(exp) => tokens.append_all(quote! {
__cx.attr(#name, #exp, #namespace) dioxus_elements::#el_name.#nameident(__cx, #exp)
}), }),
// __cx.attr(#name_str, #exp, #namespace, false)
// AttrType::FieldTokens(exp) => tokens.append_all(quote! {
// dioxus_elements::#el_name.#nameident(__cx, format_args_f!(#value))
// __cx.attr(#name_str, #exp, #namespace, false)
// }),
// todo: move event handlers on to the elements or onto the nodefactory // todo: move event handlers on to the elements or onto the nodefactory
AttrType::Event(event) => tokens.append_all(quote! { AttrType::Event(event) => tokens.append_all(quote! {
+4
View File
@@ -97,12 +97,16 @@ impl ToTokens for RsxRender {
// The `in cx` pattern allows directly rendering // The `in cx` pattern allows directly rendering
Some(ident) => out_tokens.append_all(quote! { Some(ident) => out_tokens.append_all(quote! {
#ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{ #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
use dioxus_elements::GlobalAttributes;
#inner #inner
})) }))
}), }),
// Otherwise we just build the LazyNode wrapper // Otherwise we just build the LazyNode wrapper
None => out_tokens.append_all(quote! { None => out_tokens.append_all(quote! {
dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{ dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
use dioxus_elements::GlobalAttributes;
#inner #inner
}) })
}), }),
+31 -3
View File
@@ -46,9 +46,14 @@ pub struct VFragment<'src> {
pub trait DioxusElement { pub trait DioxusElement {
const TAG_NAME: &'static str; const TAG_NAME: &'static str;
const NAME_SPACE: Option<&'static str>; const NAME_SPACE: Option<&'static str>;
#[inline]
fn tag_name(&self) -> &'static str { fn tag_name(&self) -> &'static str {
Self::TAG_NAME Self::TAG_NAME
} }
#[inline]
fn namespace(&self) -> Option<&'static str> {
Self::NAME_SPACE
}
} }
pub struct VElement<'a> { pub struct VElement<'a> {
// tag is always static // tag is always static
@@ -172,10 +177,33 @@ impl<'a> NodeFactory<'a> {
listeners: &[Listener], listeners: &[Listener],
attributes: &[Attribute], attributes: &[Attribute],
children: &'a [VNode<'a>], children: &'a [VNode<'a>],
) { ) -> VNode<'a> {
todo!()
} }
pub fn element() {} pub fn element(
&self,
el: impl DioxusElement,
listeners: &'a [Listener<'a>],
attributes: &'a [Attribute<'a>],
children: &'a [VNode<'a>],
key: Option<&'a str>,
) -> VNode<'a> {
VNode {
dom_id: RealDomNode::empty_cell(),
key,
kind: VNodeKind::Element(self.bump().alloc(VElement {
tag_name: el.tag_name(),
namespace: el.namespace(),
static_listeners: false,
listeners,
static_attrs: false,
attributes,
static_children: false,
children,
})),
}
}
pub fn suspended() -> VNode<'static> { pub fn suspended() -> VNode<'static> {
VNode { VNode {
@@ -202,7 +230,7 @@ impl<'a> NodeFactory<'a> {
} }
} }
pub fn virtual_child<P, C>( pub fn virtual_child<P>(
&self, &self,
component: FC<P>, component: FC<P>,
props: P, props: P,
+240 -56
View File
@@ -19,48 +19,213 @@ use std::fmt::Arguments;
use dioxus_core::{nodes::Attribute, DioxusElement, NodeFactory}; use dioxus_core::{nodes::Attribute, DioxusElement, NodeFactory};
trait GlobalAttributes { macro_rules! no_namespace_trait_methods {
fn accesskey<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> { (
cx.attr("accesskey", val, None, false) $(
$(#[$attr:meta])*
$name:ident;
)*
) => {
$(
$(#[$attr])*
fn $name<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr(stringify!(name), val, None, false)
}
)*
};
}
macro_rules! style_trait_methods {
(
$(
$(#[$attr:meta])*
$name:ident: $lit:literal,
)*
) => {
$(
$(#[$attr])*
fn $name<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr($lit, val, Some("style"), false)
}
)*
};
}
macro_rules! aria_trait_methods {
(
$(
$(#[$attr:meta])*
$name:ident: $lit:literal,
)*
) => {
$(
$(#[$attr])*
fn $name<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr($lit, val, None, false)
}
)*
};
}
pub trait GlobalAttributes {
no_namespace_trait_methods! {
accesskey;
class;
contenteditable;
data;
dir;
draggable;
hidden;
id;
lang;
spellcheck;
style;
tabindex;
title;
translate;
} }
fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { style_trait_methods! {
cx.attr("class", val, None, false) background: "background",
background_attachment: "background-attachment",
/// ## Definition and Usage
///
/// The background-color property sets the background color of an element.
///
/// The background of an element is the total size of the element, including padding and border (but not the margin).
///
/// Tip: Use a background color and a text color that makes the text easy to read.
///
/// ## Example
///
/// ```
/// body {
/// style: {
/// background_color: "coral"
/// }
/// }
/// ```
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 contenteditable<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_trait_methods! {
cx.attr("contenteditable", val, None, false) aria_current: "aria-current",
} aria_details: "aria-details",
fn data<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_disabled: "aria-disabled",
cx.attr("data", val, None, false) aria_hidden: "aria-hidden",
} aria_invalid: "aria-invalid",
fn dir<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_keyshortcuts: "aria-keyshortcuts",
cx.attr("dir", val, None, false) aria_label: "aria-label",
} aria_roledescription: "aria-roledescription",
fn draggable<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { // Widget Attributes
cx.attr("draggable", val, None, false) aria_autocomplete: "aria-autocomplete",
} aria_checked: "aria-checked",
fn hidden<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_expanded: "aria-expanded",
cx.attr("hidden", val, None, false) aria_haspopup: "aria-haspopup",
} aria_level: "aria-level",
fn id<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_modal: "aria-modal",
cx.attr("id", val, None, false) aria_multiline: "aria-multiline",
} aria_multiselectable: "aria-multiselectable",
fn lang<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_orientation: "aria-orientation",
cx.attr("lang", val, None, false) aria_placeholder: "aria-placeholder",
} aria_pressed: "aria-pressed",
fn spellcheck<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_readonly: "aria-readonly",
cx.attr("spellcheck", val, None, false) aria_required: "aria-required",
} aria_selected: "aria-selected",
fn style<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_sort: "aria-sort",
cx.attr("style", val, Some("style"), false) aria_valuemax: "aria-valuemax",
} aria_valuemin: "aria-valuemin",
fn tabindex<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_valuenow: "aria-valuenow",
cx.attr("tabindex", val, None, false) aria_valuetext: "aria-valuetext",
} // Live Region Attributes
fn title<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_atomic: "aria-atomic",
cx.attr("title", val, None, false) aria_busy: "aria-busy",
} aria_live: "aria-live",
fn translate<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { aria_relevant: "aria-relevant",
cx.attr("translate", val, None, false)
aria_dropeffect: "aria-dropeffect",
aria_grabbed: "aria-grabbed",
// Relationship Attributes
aria_activedescendant: "aria-activedescendant",
aria_colcount: "aria-colcount",
aria_colindex: "aria-colindex",
aria_colspan: "aria-colspan",
aria_controls: "aria-controls",
aria_describedby: "aria-describedby",
aria_errormessage: "aria-errormessage",
aria_flowto: "aria-flowto",
aria_labelledby: "aria-labelledby",
aria_owns: "aria-owns",
aria_posinset: "aria-posinset",
aria_rowcount: "aria-rowcount",
aria_rowindex: "aria-rowindex",
aria_rowspan: "aria-rowspan",
aria_setsize: "aria-setsize",
} }
} }
@@ -87,7 +252,7 @@ macro_rules! builder_constructors {
impl $name { impl $name {
$( $(
pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> {
cx.attr(stringify!($fil), val, None, false) cx.attr(stringify!($fil), val, None, false)
} }
)* )*
@@ -149,7 +314,7 @@ builder_constructors! {
rel: LinkType, rel: LinkType,
sizes: String, // FIXME sizes: String, // FIXME
title: String, // FIXME title: String, // FIXME
// type: Mime, r#type: Mime,
}; };
/// Build a /// Build a
@@ -166,7 +331,7 @@ builder_constructors! {
/// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style) /// [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style)
/// element. /// element.
style { style {
// type: Mime, r#type: Mime,
media: String, // FIXME media query media: String, // FIXME media query
nonce: Nonce, nonce: Nonce,
title: String, // FIXME title: String, // FIXME
@@ -307,6 +472,25 @@ builder_constructors! {
/// Build a /// Build a
/// [`<div>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div) /// [`<div>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div)
/// element. /// element.
///
/// ## Definition and Usage
/// - The <div> tag defines a division or a section in an HTML document.
/// - The <div> tag is used as a container for HTML elements - which is then styled with CSS or manipulated with JavaScript.
/// - The <div> tag is easily styled by using the class or id attribute.
/// - Any sort of content can be put inside the <div> tag!
///
/// Note: By default, browsers always place a line break before and after the <div> element.
///
/// ## Usage
/// ```
/// html!(<div> A header element </div>)
/// rsx!(div { "A header element" })
/// LazyNodes::new(|f| f.element(div, &[], &[], &[], None))
/// ```
///
/// ## References:
/// - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div
/// - https://www.w3schools.com/tags/tag_div.asp
div {}; div {};
/// Build a /// Build a
@@ -347,7 +531,7 @@ builder_constructors! {
ol { ol {
reversed: Bool, reversed: Bool,
start: isize, start: isize,
// type: OrderedListType, r#type: OrderedListType,
}; };
/// Build a /// Build a
@@ -376,7 +560,7 @@ builder_constructors! {
href: Uri, href: Uri,
hreflang: LanguageTag, hreflang: LanguageTag,
target: Target, target: Target,
// type: Mime, r#type: Mime,
// ping: SpacedList<Uri>, // ping: SpacedList<Uri>,
// rel: SpacedList<LinkType>, // rel: SpacedList<LinkType>,
}; };
@@ -553,10 +737,10 @@ builder_constructors! {
autoplay: Bool, autoplay: Bool,
controls: Bool, controls: Bool,
crossorigin: CrossOrigin, crossorigin: CrossOrigin,
// loop: Bool,
muted: Bool, muted: Bool,
preload: Preload, preload: Preload,
src: Uri, src: Uri,
r#loop: Bool,
}; };
/// Build a /// Build a
@@ -601,7 +785,7 @@ builder_constructors! {
controls: Bool, controls: Bool,
crossorigin: CrossOrigin, crossorigin: CrossOrigin,
height: usize, height: usize,
// loop: Bool, r#loop: Bool,
muted: Bool, muted: Bool,
preload: Preload, preload: Preload,
playsinline: Bool, playsinline: Bool,
@@ -619,7 +803,7 @@ builder_constructors! {
embed { embed {
height: usize, height: usize,
src: Uri, src: Uri,
// type: Mime, r#type: Mime,
width: usize, width: usize,
}; };
@@ -647,7 +831,7 @@ builder_constructors! {
form: Id, form: Id,
height: usize, height: usize,
name: Id, name: Id,
// type: Mime, r#type: Mime,
typemustmatch: Bool, typemustmatch: Bool,
usemap: String, // TODO should be a fragment starting with '#' usemap: String, // TODO should be a fragment starting with '#'
width: usize, width: usize,
@@ -671,7 +855,7 @@ builder_constructors! {
/// element. /// element.
source { source {
src: Uri, src: Uri,
// type: Mime, r#type: Mime,
}; };
@@ -701,8 +885,8 @@ builder_constructors! {
nonce: Nonce, nonce: Nonce,
src: Uri, src: Uri,
text: String, text: String,
// async: Bool, r#async: Bool,
// type: String, // TODO could be an enum r#type: String, // TODO could be an enum
}; };
@@ -807,7 +991,7 @@ builder_constructors! {
formnovalidate: Bool, formnovalidate: Bool,
formtarget: Target, formtarget: Target,
name: Id, name: Id,
// type: ButtonType, r#type: ButtonType,
value: String, value: String,
}; };
@@ -869,7 +1053,7 @@ builder_constructors! {
src: Uri, src: Uri,
step: String, step: String,
tabindex: usize, tabindex: usize,
// type: InputType, r#type: InputType,
value: String, value: String,
width: isize, width: isize,
}; };
@@ -878,7 +1062,7 @@ builder_constructors! {
/// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) /// [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label)
/// element. /// element.
label { label {
// for: Id, r#for: Id,
form: Id, form: Id,
}; };
@@ -924,7 +1108,7 @@ builder_constructors! {
output { output {
form: Id, form: Id,
name: Id, name: Id,
// for: SpacedSet<Id>, // r#for: SpacedSet<Id>,
}; };
/// Build a /// Build a
+1
View File
@@ -151,6 +151,7 @@ mod tests {
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html as dioxus_elements; use dioxus_html as dioxus_elements;
use dioxus_html::GlobalAttributes;
const SIMPLE_APP: FC<()> = |cx| { const SIMPLE_APP: FC<()> = |cx| {
cx.render(rsx!(div { cx.render(rsx!(div {
+1
View File
@@ -21,4 +21,5 @@ mod dioxus_elements {
const TAG_NAME: &'static str = "div"; const TAG_NAME: &'static str = "div";
const NAME_SPACE: Option<&'static str> = None; const NAME_SPACE: Option<&'static str> = None;
} }
pub trait GlobalAttributes {}
} }
+1
View File
@@ -188,6 +188,7 @@ pub use dioxus_webview as desktop;
pub mod prelude { pub mod prelude {
//! A glob import that includes helper types like FC, rsx!, html!, and required traits //! A glob import that includes helper types like FC, rsx!, html!, and required traits
pub use dioxus_core::prelude::*; pub use dioxus_core::prelude::*;
pub use dioxus_elements::GlobalAttributes;
pub use dioxus_hooks::*; pub use dioxus_hooks::*;
pub use dioxus_html as dioxus_elements; pub use dioxus_html as dioxus_elements;
} }