From c79d9ae674e235c8e9c2c069d24902122b9c7464 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 12 Jul 2021 23:44:20 -0400 Subject: [PATCH] feat: buff up html allowed attributes --- packages/core/Cargo.toml | 2 +- packages/core/examples/alternative.rs | 32 +- packages/core/src/component.rs | 3 +- packages/core/src/diff.rs | 13 +- packages/core/src/lib.rs | 65 +- packages/core/src/nodebuilder.rs | 1 - packages/core/src/nodes.rs | 46 +- packages/html/src/lib.rs | 822 ++++++++++++++++++++++---- packages/ssr/src/lib.rs | 14 +- packages/webview/examples/test.rs | 5 +- packages/webview/src/lib.rs | 4 +- 11 files changed, 803 insertions(+), 204 deletions(-) delete mode 100644 packages/core/src/nodebuilder.rs diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml index eaa9ba214..c662c6732 100644 --- a/packages/core/Cargo.toml +++ b/packages/core/Cargo.toml @@ -41,5 +41,5 @@ smallvec = "1.6.1" [features] -default = [] +default = ["serialize"] serialize = ["slotmap/serde", "serde"] diff --git a/packages/core/examples/alternative.rs b/packages/core/examples/alternative.rs index 3b74d0472..b12a8f69c 100644 --- a/packages/core/examples/alternative.rs +++ b/packages/core/examples/alternative.rs @@ -1,20 +1,20 @@ fn main() {} -use dioxus::*; -use dioxus_core as dioxus; -use dioxus_core::prelude::*; +// use dioxus::*; +// use dioxus_core as dioxus; +// use dioxus_core::prelude::*; -static Example: FC<()> = |cx| { - let list = (0..10).map(|f| LazyNodes::new(move |f| todo!())); +// static Example: FC<()> = |cx| { +// let list = (0..10).map(|f| LazyNodes::new(move |f| todo!())); - cx.render(LazyNodes::new(move |cx| { - let bump = cx.bump(); - cx.raw_element("div") - .children([ - cx.text(format_args!("hello")), - cx.text(format_args!("hello")), - cx.fragment_from_iter(list), - ]) - .finish() - })) -}; +// cx.render(LazyNodes::new(move |cx| { +// let bump = cx.bump(); +// cx.raw_element("div") +// .children([ +// cx.text(format_args!("hello")), +// cx.text(format_args!("hello")), +// cx.fragment_from_iter(list), +// ]) +// .finish() +// })) +// }; diff --git a/packages/core/src/component.rs b/packages/core/src/component.rs index f5bc7ea79..c23e3d631 100644 --- a/packages/core/src/component.rs +++ b/packages/core/src/component.rs @@ -5,7 +5,7 @@ //! if the type suppports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder //! that ensures compile-time required and optional fields on cx. -use crate::innerlude::FC; +use crate::innerlude::{Context, LazyNodes, VNode, FC}; pub trait Properties: Sized { type Builder; @@ -50,7 +50,6 @@ pub fn fc_to_builder(_: FC) -> T::Builder { /// /// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase. /// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash. -use crate::prelude::*; #[allow(non_upper_case_globals, non_snake_case)] pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> { cx.render(LazyNodes::new(move |f| f.fragment_from_iter(cx.children()))) diff --git a/packages/core/src/diff.rs b/packages/core/src/diff.rs index 7498405bb..7843596de 100644 --- a/packages/core/src/diff.rs +++ b/packages/core/src/diff.rs @@ -107,18 +107,6 @@ pub trait RealDom<'a> { fn raw_node_as_any_mut(&self) -> &mut dyn Any; } -/// The DiffState is a cursor internal to the VirtualDOM's diffing algorithm that allows persistence of state while -/// diffing trees of components. This means we can "re-enter" a subtree of a component by queuing a "NeedToDiff" event. -/// -/// By re-entering via NodeDiff, we can connect disparate edits together into a single EditList. This batching of edits -/// leads to very fast re-renders (all done in a single animation frame). -/// -/// It also means diffing two trees is only ever complex as diffing a single smaller tree, and then re-entering at a -/// different cursor position. -/// -/// The order of these re-entrances is stored in the DiffState itself. The DiffState comes pre-loaded with a set of components -/// that were modified by the eventtrigger. This prevents doubly evaluating components if they were both updated via -/// subscriptions and props changes. pub struct DiffMachine<'real, 'bump, Dom: RealDom<'bump>> { pub dom: &'real mut Dom, pub components: &'bump SharedArena, @@ -170,6 +158,7 @@ where self.dom.set_text(new.text); self.dom.pop(); } + new_node.dom_id.set(root); } diff --git a/packages/core/src/lib.rs b/packages/core/src/lib.rs index 794bdc4dc..105de6a1a 100644 --- a/packages/core/src/lib.rs +++ b/packages/core/src/lib.rs @@ -8,23 +8,20 @@ //! //! -#[cfg(feature = "serialize")] -pub mod serialize; +pub use crate::innerlude::{ + format_args_f, html, rsx, DioxusElement, DomEdit, EventTrigger, LazyNodes, NodeFactory, + Properties, RealDom, RealDomNode, ScopeIdx, VNode, VNodeKind, VirtualDom, VirtualEvent, FC, +}; -pub mod arena; -pub mod bumpframe; -pub mod component; -pub mod context; -pub mod diff; -pub mod error; -pub mod events; -pub mod hooklist; -pub mod nodes; -pub mod scope; -pub mod signals; -pub mod tasks; -pub mod util; -pub mod virtual_dom; +pub mod prelude { + pub use crate::component::{fc_to_builder, Fragment, Properties}; + pub use crate::context::Context; + pub use crate::innerlude::DioxusElement; + pub use crate::innerlude::{LazyNodes, NodeFactory, FC}; + pub use crate::nodes::VNode; + pub use crate::VirtualDom; + pub use dioxus_core_macro::{format_args_f, html, rsx, Props}; +} // types used internally that are important pub(crate) mod innerlude { @@ -43,26 +40,26 @@ pub(crate) mod innerlude { pub type FC

= fn(Context

) -> VNode; - pub use dioxus_core_macro::{html, rsx}; -} - -pub use crate::{ - innerlude::{ - DioxusElement, DomEdit, LazyNodes, NodeFactory, RealDom, RealDomNode, ScopeIdx, FC, - }, - virtual_dom::VirtualDom, -}; - -pub mod prelude { - pub use crate::component::{fc_to_builder, Fragment, Properties}; - pub use crate::context::Context; - pub use crate::innerlude::DioxusElement; - pub use crate::innerlude::{LazyNodes, NodeFactory, FC}; - pub use crate::nodes::VNode; - pub use crate::VirtualDom; - pub use dioxus_core_macro::{format_args_f, html, rsx, Props}; + pub use dioxus_core_macro::{format_args_f, html, rsx}; } pub mod exports { // export important things here } + +pub mod arena; +pub mod bumpframe; +pub mod component; +pub mod context; +pub mod diff; +pub mod error; +pub mod events; +pub mod hooklist; +pub mod nodes; +pub mod scope; +#[cfg(feature = "serialize")] +pub mod serialize; +pub mod signals; +pub mod tasks; +pub mod util; +pub mod virtual_dom; diff --git a/packages/core/src/nodebuilder.rs b/packages/core/src/nodebuilder.rs deleted file mode 100644 index 8b1378917..000000000 --- a/packages/core/src/nodebuilder.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/core/src/nodes.rs b/packages/core/src/nodes.rs index af6a1b022..4b45e1066 100644 --- a/packages/core/src/nodes.rs +++ b/packages/core/src/nodes.rs @@ -40,6 +40,7 @@ pub struct VText<'src> { pub struct VFragment<'src> { pub children: &'src [VNode<'src>], + pub is_static: bool, } pub trait DioxusElement { @@ -52,6 +53,7 @@ pub trait DioxusElement { pub struct VElement<'a> { // tag is always static pub tag_name: &'static str, + pub namespace: Option<&'static str>, pub static_listeners: bool, pub listeners: &'a [Listener<'a>], @@ -61,9 +63,6 @@ pub struct VElement<'a> { pub static_children: bool, pub children: &'a [VNode<'a>], - - // namespace is always static - pub namespace: Option<&'static str>, } /// An attribute on a DOM node, such as `id="my-thing"` or @@ -92,14 +91,16 @@ pub struct Listener<'bump> { /// Only supports the functional syntax pub struct VComponent<'src> { pub ass_scope: Cell>, - pub caller: Rc VNode>, - pub children: &'src [VNode<'src>], - pub comparator: Option<&'src dyn Fn(&VComponent) -> bool>, - // a pointer into the bump arena (given by the 'src lifetime) - raw_props: *const (), - // a pointer to the raw fn typ - pub user_fc: *const (), + pub(crate) caller: Rc VNode>, + pub(crate) children: &'src [VNode<'src>], + pub(crate) comparator: Option<&'src dyn Fn(&VComponent) -> bool>, pub is_static: bool, + + // a pointer into the bump arena (given by the 'src lifetime) + pub(crate) raw_props: *const (), + + // a pointer to the raw fn typ + pub(crate) user_fc: *const (), } /// This struct provides an ergonomic API to quickly build VNodes. @@ -118,6 +119,20 @@ impl<'a> NodeFactory<'a> { &self.scope_ref.cur_frame().bump } + pub const fn const_text(&self, text: &'static str) -> VNodeKind<'static> { + VNodeKind::Text(VText { + is_static: true, + text, + }) + } + + pub const fn const_fragment(&self, children: &'static [VNode<'static>]) -> VNodeKind<'static> { + VNodeKind::Fragment(VFragment { + children, + is_static: true, + }) + } + pub fn static_text(text: &'static str) -> VNode { VNode { dom_id: RealDomNode::empty_cell(), @@ -151,8 +166,6 @@ impl<'a> NodeFactory<'a> { } } - pub const fn const_el(&self) {} - pub fn raw_element( &self, tag: &'static str, @@ -279,6 +292,7 @@ impl<'a> NodeFactory<'a> { key: None, kind: VNodeKind::Fragment(VFragment { children: nodes.into_bump_slice(), + is_static: false, }), } } @@ -385,12 +399,16 @@ impl<'a> Clone for VNode<'a> { }), VNodeKind::Fragment(fragment) => VNodeKind::Fragment(VFragment { children: fragment.children, + is_static: fragment.is_static, }), VNodeKind::Component(component) => VNodeKind::Component(component), VNodeKind::Suspended => VNodeKind::Suspended, }; - - todo!() + VNode { + kind, + dom_id: self.dom_id.clone(), + key: self.key.clone(), + } } } diff --git a/packages/html/src/lib.rs b/packages/html/src/lib.rs index 8c394c3ab..4bd425c0f 100644 --- a/packages/html/src/lib.rs +++ b/packages/html/src/lib.rs @@ -6,11 +6,73 @@ //! 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. +//! +//! All elements are used as zero-sized unit structs with trait impls. +//! +//! Currently, we don't validate for structures, but do validate attributes. +//! +//! +//! +//! -use dioxus_core::{DioxusElement, NodeFactory}; +use std::fmt::Arguments; + +use dioxus_core::{nodes::Attribute, DioxusElement, NodeFactory}; + +trait GlobalAttributes { + fn accesskey<'a>(&self, cx: NodeFactory<'a>, val: Arguments) -> Attribute<'a> { + cx.attr("accesskey", val, None, false) + } + fn class<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("class", val, None, false) + } + fn contenteditable<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("contenteditable", val, None, false) + } + fn data<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("data", val, None, false) + } + fn dir<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("dir", val, None, false) + } + fn draggable<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("draggable", val, None, false) + } + fn hidden<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("hidden", val, None, false) + } + fn id<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("id", val, None, false) + } + fn lang<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("lang", val, None, false) + } + fn spellcheck<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("spellcheck", val, None, false) + } + fn style<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("style", val, Some("style"), false) + } + fn tabindex<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("tabindex", val, None, false) + } + fn title<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("title", val, None, false) + } + fn translate<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr("translate", val, None, false) + } +} macro_rules! builder_constructors { - ( $( $(#[$attr:meta])* $name:ident; )* ) => { + ( + $( + $(#[$attr:meta])* + $name:ident { + $($fil:ident: $vil:ident,)* + }; + )* + ) => { $( #[allow(non_camel_case_types)] $(#[$attr])* @@ -20,6 +82,16 @@ macro_rules! builder_constructors { const TAG_NAME: &'static str = stringify!($name); const NAME_SPACE: Option<&'static str> = None; } + + impl GlobalAttributes for $name {} + + impl $name { + $( + pub fn $fil<'a>(&self, cx: NodeFactory<'a>, val: Arguments<'a>) -> Attribute<'a> { + cx.attr(stringify!($fil), val, None, false) + } + )* + } )* }; @@ -44,7 +116,7 @@ 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. @@ -55,63 +127,91 @@ builder_constructors! { /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base) /// element. /// - /// A base element is your mom! - base; + base { + href: Uri, + target: Target, + }; /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) /// element. - head; + head {}; /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link) /// element. - link; + link { + // as: Mime, + crossorigin: CrossOrigin, + href: Uri, + hreflang: LanguageTag, + media: String, // FIXME media query + rel: LinkType, + sizes: String, // FIXME + title: String, // FIXME + // type: Mime, + }; /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta) /// element. - meta; + meta { + charset: String, // FIXME IANA standard names + content: String, + http_equiv: HTTPEquiv, + name: Metadata, + }; /// Build a /// [`