wip
This commit is contained in:
1 parent
4091846934
commit
996247a164
7 files changed
+171
-122
No files matched your search
+86
-1
@@ -1,6 +1,6 @@
|
||||
# Html (and SVG) Namespace for Dioxus
|
||||
|
||||
The Dioxus `rsx!` and `html!` macros can accept any compile-time correct namespace on top of NodeBuilder. This crate provides the HTML (and SVG) namespaces which get imported in the Dioxus prelude.
|
||||
The Dioxus `rsx!` and `html!` macros can accept any compile-time correct namespace on top of NodeFactory. This crate provides the HTML (and SVG) namespaces which get imported in the Dioxus prelude.
|
||||
|
||||
However, this abstraction enables you to add any namespace of elements, provided they're in scope when rsx! is called. For an example, a UI that is designed for Augmented Reality might use different primitives than HTML:
|
||||
|
||||
@@ -20,3 +20,88 @@ rsx! {
|
||||
```
|
||||
|
||||
This is currently a not-very-explored part of Dioxus. However, the namespacing system does make it possible to provide syntax highlighting, documentation, "go to definition" and compile-time correctness, so it's worth having it abstracted.
|
||||
|
||||
## How it works:
|
||||
|
||||
Elements for dioxus must implement the (simple) DioxusElement trait to be used in the rsx! macro.
|
||||
|
||||
```rust
|
||||
struct div;
|
||||
impl DioxusElement for div {
|
||||
const TAG_NAME: &'static str = "div";
|
||||
const NAME_SPACE: Option<&'static str> = None;
|
||||
}
|
||||
```
|
||||
|
||||
All elements should be defined as a zero-sized-struct (also known as unit struct). These structs are zero-cost and just provide the type-level trickery to Rust for compile-time correct templates.
|
||||
|
||||
Attributes would then be implemented as methods on these unit structs.
|
||||
|
||||
The HTML namespace is defined mostly with macros. However, the expanded form would look something like this:
|
||||
```rust
|
||||
struct base;
|
||||
impl DioxusElement for base {
|
||||
const TAG_NAME: &'static str = "base";
|
||||
const NAME_SPACE: Option<&'static str> = None;
|
||||
}
|
||||
impl base {
|
||||
#[inline]
|
||||
fn href<'a>(&self, f: NodeFactory<'a>, v: Arguments) -> Attribute<'a> {
|
||||
f.attr("href", v, None, false)
|
||||
}
|
||||
#[inline]
|
||||
fn target<'a>(&self, f: NodeFactory<'a>, v: Arguments) -> Attribute<'a> {
|
||||
f.attr("target", v, None, false)
|
||||
}
|
||||
}
|
||||
```
|
||||
Because attributes are defined as methods on the unit struct, they guard the attribute creation behind a compile-time correct interface.
|
||||
|
||||
|
||||
## How to extend it:
|
||||
|
||||
Whenever the rsx! macro is called, it relies on a module `dioxus_elements` to be in scope. When you enable the `html` feature in dioxus, this module gets imported in the prelude. However, you can extend this with your own set of custom elements by making your own `dioxus_elements` module and re-exporting the html namespace.
|
||||
|
||||
```rust
|
||||
mod dioxus_elements {
|
||||
use dioxus::prelude::dioxus_elements::*;
|
||||
struct my_element;
|
||||
impl DioxusElement for my_element {
|
||||
const TAG_NAME: &'static str = "base";
|
||||
const NAME_SPACE: Option<&'static str> = None;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations:
|
||||
-
|
||||
|
||||
## How to work around it:
|
||||
If an attribute in Dioxus is invalid (defined incorrectly) - first, make an issue - but then, you can work around it. The raw builder API is actually somewhat ergonomic to work with, and the NodeFactory type exposes a bunch of methods to make any type of tree - even invalid ones! So obviously, be careful, but there's basically anything you can do.
|
||||
|
||||
```rust
|
||||
cx.render(rsx!{
|
||||
div {
|
||||
h1 {}
|
||||
// Oh no! I need a super custom element
|
||||
{LazyNodes::new(move |f| {
|
||||
f.raw_element(
|
||||
// tag name
|
||||
"custom_element",
|
||||
|
||||
// attributes
|
||||
&[f.attr("billy", format_args!("goat"))],
|
||||
|
||||
// listeners
|
||||
&[f.listener(onclick(move |_| {}))],
|
||||
|
||||
// children
|
||||
&[cx.render(rsx!(div {} ))],
|
||||
|
||||
// key
|
||||
None
|
||||
)
|
||||
})}
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -68,6 +68,35 @@ macro_rules! aria_trait_methods {
|
||||
pub trait GlobalAttributes {
|
||||
no_namespace_trait_methods! {
|
||||
accesskey;
|
||||
|
||||
/// The HTML class attribute is used to specify a class for an HTML element.
|
||||
///
|
||||
/// ## Details
|
||||
/// Multiple HTML elements can share the same class.
|
||||
///
|
||||
/// The class global attribute is a space-separated list of the case-sensitive classes of the element.
|
||||
/// Classes allow CSS and Javascript to select and access specific elements via the class selectors or
|
||||
/// functions like the DOM method document.getElementsByClassName.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ### HTML:
|
||||
/// ```html
|
||||
/// <p class="note editorial">Above point sounds a bit obvious. Remove/rewrite?</p>
|
||||
/// ```
|
||||
///
|
||||
/// ### CSS:
|
||||
/// ```css
|
||||
/// .note {
|
||||
/// font-style: italic;
|
||||
/// font-weight: bold;
|
||||
/// }
|
||||
///
|
||||
/// .editorial {
|
||||
/// background: rgb(255, 0, 0, .25);
|
||||
/// padding: 10px;
|
||||
/// }
|
||||
/// ```
|
||||
class;
|
||||
contenteditable;
|
||||
data;
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
//! 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.
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
|
||||
use crate::innerlude::{Attribute, 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"))];
|
||||
}
|
||||
Reference in new issue
Block a user