Merge branch 'upstream' into router-typesafe
This commit is contained in:
commit
92755a381d
21 files changed
+297
-94
No files matched your search
+1
-1
@@ -72,7 +72,7 @@ tokio = { version = "1.16.1", features = ["full"] }
|
||||
reqwest = { version = "0.11.9", features = ["json"] }
|
||||
fern = { version = "0.6.0", features = ["colored"] }
|
||||
thiserror = "1.0.30"
|
||||
env_logger = "0.9.0"
|
||||
env_logger = "0.10.0"
|
||||
simple_logger = "4.0.0"
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#![allow(unused)]
|
||||
#![allow(non_snake_case)]
|
||||
// ANCHOR: all
|
||||
|
||||
// ANCHOR: main
|
||||
#![allow(non_snake_case)]
|
||||
use axum::{response::Html, routing::get, Router};
|
||||
// import the prelude to get access to the `rsx!` macro and the `Scope` and `Element` types
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
println!("listening on http://{}", addr);
|
||||
|
||||
axum::Server::bind(&addr)
|
||||
.serve(
|
||||
Router::new()
|
||||
.route("/", get(app_endpoint))
|
||||
.into_make_service(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// ANCHOR_END: main
|
||||
|
||||
// ANCHOR: endpoint
|
||||
async fn app_endpoint() -> Html<String> {
|
||||
// render the rsx! macro to HTML
|
||||
Html(dioxus_ssr::render_lazy(rsx! {
|
||||
div { "hello world!" }
|
||||
}))
|
||||
}
|
||||
// ANCHOR_END: endpoint
|
||||
|
||||
// ANCHOR: second_endpoint
|
||||
async fn second_app_endpoint() -> Html<String> {
|
||||
// create a component that renders a div with the text "hello world"
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx!(div { "hello world" }))
|
||||
}
|
||||
// create a VirtualDom with the app component
|
||||
let mut app = VirtualDom::new(app);
|
||||
// rebuild the VirtualDom before rendering
|
||||
let _ = app.rebuild();
|
||||
|
||||
// render the VirtualDom to HTML
|
||||
Html(dioxus_ssr::render(&app))
|
||||
}
|
||||
// ANCHOR_END: second_endpoint
|
||||
|
||||
// ANCHOR: component
|
||||
// define a component that renders a div with the text "Hello, world!"
|
||||
fn App(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
"Hello, world!"
|
||||
}
|
||||
})
|
||||
}
|
||||
// ANCHOR_END: component
|
||||
// ANCHOR_END: all
|
||||
@@ -40,54 +40,30 @@ tokio = { version = "1.15.0", features = ["full"] }
|
||||
Now, set up your Axum app to respond on an endpoint.
|
||||
|
||||
```rust
|
||||
use axum::{response::Html, routing::get, Router};
|
||||
use dioxus::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000));
|
||||
println!("listening on http://{}", addr);
|
||||
|
||||
axum::Server::bind(&addr)
|
||||
.serve(
|
||||
Router::new()
|
||||
.route("/", get(app_endpoint))
|
||||
.into_make_service(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
{{#include ../../../examples/hello_world_ssr.rs:main}}
|
||||
```
|
||||
|
||||
And then add our endpoint. We can either render `rsx!` directly:
|
||||
|
||||
```rust
|
||||
async fn app_endpoint() -> Html<String> {
|
||||
// render the rsx! macro to HTML
|
||||
Html(dioxus_ssr::render_lazy(rsx! {
|
||||
div { "hello world!" }
|
||||
}))
|
||||
}
|
||||
{{#include ../../../examples/hello_world_ssr.rs:endpoint}}
|
||||
```
|
||||
|
||||
Or we can render VirtualDoms.
|
||||
|
||||
```rust
|
||||
async fn app_endpoint() -> Html<String> {
|
||||
// create a component that renders a div with the text "hello world"
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx!(div { "hello world" }))
|
||||
}
|
||||
// create a VirtualDom with the app component
|
||||
let mut app = VirtualDom::new(app);
|
||||
// rebuild the VirtualDom before rendering
|
||||
let _ = app.rebuild();
|
||||
|
||||
// render the VirtualDom to HTML
|
||||
Html(dioxus_ssr::render_vdom(&app))
|
||||
}
|
||||
{{#include ../../../examples/hello_world_ssr.rs:second_endpoint}}
|
||||
```
|
||||
|
||||
And then add our app component:
|
||||
|
||||
```rust
|
||||
{{#include ../../../examples/hello_world_ssr.rs:component}}
|
||||
```
|
||||
|
||||
And that's it!
|
||||
|
||||
|
||||
## Multithreaded Support
|
||||
|
||||
The Dioxus VirtualDom, sadly, is not currently `Send`. Internally, we use quite a bit of interior mutability which is not thread-safe.
|
||||
|
||||
@@ -44,7 +44,7 @@ This is only possible because the two hooks are always called in the same order,
|
||||
|
||||
1. Hooks may be only used in components or other hooks (we'll get to that later)
|
||||
2. On every call to the component function
|
||||
1. The same hooks must be called
|
||||
1. The same hooks must be called (except in the case of early returns, as explained later in the [Error Handling chapter](../best_practices/error_handling.md))
|
||||
2. In the same order
|
||||
3. Hooks name's should start with `use_` so you don't accidentally confuse them with regular functions
|
||||
|
||||
|
||||
@@ -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%",
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Contributing
|
||||
|
||||
On Linux, install the following packages:
|
||||
|
||||
```bash
|
||||
sudo apt install libgdk3.0-cil libatk1.0-dev libcairo2-dev libpango1.0-dev libgdk-pixbuf2.0-dev libsoup-3.0-dev libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
cargo test --workspace --tests
|
||||
```
|
||||
@@ -38,6 +38,7 @@ slab = "0.4"
|
||||
|
||||
futures-util = "0.3.25"
|
||||
rfd = "0.11.3"
|
||||
urlencoding = "2.1.2"
|
||||
|
||||
[target.'cfg(target_os = "ios")'.dependencies]
|
||||
objc = "0.2.7"
|
||||
|
||||
@@ -43,7 +43,7 @@ fn module_loader(root_name: &str) -> String {
|
||||
let rootname = "{root_name}";
|
||||
let root = window.document.getElementById(rootname);
|
||||
if (root != null) {{
|
||||
window.interpreter = new Interpreter(root);
|
||||
window.interpreter = new Interpreter(root, new InterpreterConfig(true));
|
||||
window.ipc.postMessage(serializeIpcMessage("initialize"));
|
||||
}}
|
||||
</script>
|
||||
@@ -87,7 +87,9 @@ pub(super) fn desktop_handler(
|
||||
}
|
||||
|
||||
// Else, try to serve a file from the filesystem.
|
||||
let path = PathBuf::from(request.uri().path().trim_start_matches('/'));
|
||||
let decoded = urlencoding::decode(request.uri().path().trim_start_matches('/'))
|
||||
.expect("expected URL to be UTF-8 encoded");
|
||||
let path = PathBuf::from(&*decoded);
|
||||
|
||||
// If the path is relative, we'll try to serve it from the assets directory.
|
||||
let mut asset = get_asset_root()
|
||||
|
||||
@@ -41,17 +41,10 @@ impl Shortcut {
|
||||
|
||||
impl ShortcutRegistry {
|
||||
pub fn new<T>(target: &EventLoopWindowTarget<T>) -> Self {
|
||||
let myself = Self {
|
||||
Self {
|
||||
manager: Rc::new(RefCell::new(ShortcutManager::new(target))),
|
||||
shortcuts: Rc::new(RefCell::new(HashMap::new())),
|
||||
};
|
||||
// prevent CTRL+R from reloading the page which breaks apps
|
||||
let _ = myself.add_shortcut(
|
||||
Some(ModifiersState::CONTROL),
|
||||
KeyCode::KeyR,
|
||||
Box::new(|| {}),
|
||||
);
|
||||
myself
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn call_handlers(&self, id: AcceleratorId) {
|
||||
|
||||
@@ -35,7 +35,7 @@ log = "0.4.14"
|
||||
rand = { version = "0.8.4", features = ["small_rng"] }
|
||||
criterion = "0.3.5"
|
||||
thiserror = "1.0.30"
|
||||
env_logger = "0.9.0"
|
||||
env_logger = "0.10.0"
|
||||
tokio = { version = "1.21.2", features = ["full"] }
|
||||
# dioxus-edit-stream = { path = "../edit-stream" }
|
||||
|
||||
|
||||
@@ -70,6 +70,12 @@ impl<T: 'static> UseAtomRef<T> {
|
||||
self.value.borrow()
|
||||
}
|
||||
|
||||
/// This is silent operation
|
||||
/// call `.force_update()` manually if required
|
||||
pub fn with_mut_silent(&self, cb: impl FnOnce(&mut T)) {
|
||||
cb(&mut *self.write_silent())
|
||||
}
|
||||
|
||||
pub fn write(&self) -> RefMut<T> {
|
||||
self.root.force_update(self.ptr);
|
||||
self.value.borrow_mut()
|
||||
|
||||
@@ -13,7 +13,7 @@ keywords = ["dom", "ui", "gui", "react", "ssr", "fullstack"]
|
||||
|
||||
[dependencies]
|
||||
# server functions
|
||||
server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", features = ["stable"] }
|
||||
server_fn = { git = "https://github.com/leptos-rs/leptos", rev = "671b1e4a8fff7a2e05bb621ef08e87be2b18ccae", default-features = false, features = ["stable"] }
|
||||
dioxus_server_macro = { path = "server-macro" }
|
||||
|
||||
# warp
|
||||
@@ -56,9 +56,11 @@ dioxus-hot-reload = { path = "../hot-reload" }
|
||||
web-sys = { version = "0.3.61", features = ["Window", "Document", "Element", "HtmlDocument", "Storage", "console"] }
|
||||
|
||||
[features]
|
||||
default = ["hot-reload"]
|
||||
default = ["hot-reload", "default-tls"]
|
||||
hot-reload = ["serde_json", "tokio-stream", "futures-util"]
|
||||
warp = ["dep:warp", "http-body", "ssr"]
|
||||
axum = ["dep:axum", "tower-http", "ssr"]
|
||||
salvo = ["dep:salvo", "ssr"]
|
||||
ssr = ["server_fn/ssr", "tokio", "dioxus-ssr", "hyper", "http"]
|
||||
default-tls = ["server_fn/default-tls"]
|
||||
rustls = ["server_fn/rustls"]
|
||||
@@ -18,7 +18,7 @@ dioxus-html = { path = "../html", features = ["hot-reload-context"], version = "
|
||||
|
||||
interprocess = { version = "1.2.1" }
|
||||
notify = "5.0.0"
|
||||
chrono = "0.4.23"
|
||||
chrono = { version = "0.4.24", default-features = false, features = ["clock"] }
|
||||
serde_json = "1.0.91"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
execute = "0.2.11"
|
||||
|
||||
@@ -6,10 +6,14 @@ use web_sys::Element;
|
||||
|
||||
#[wasm_bindgen(module = "/src/interpreter.js")]
|
||||
extern "C" {
|
||||
pub type InterpreterConfig;
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(intercept_link_redirects: bool) -> InterpreterConfig;
|
||||
|
||||
pub type Interpreter;
|
||||
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(arg: Element) -> Interpreter;
|
||||
pub fn new(arg: Element, config: InterpreterConfig) -> Interpreter;
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn SaveTemplate(this: &Interpreter, template: JsValue);
|
||||
|
||||
@@ -53,8 +53,15 @@ class ListenerMap {
|
||||
}
|
||||
}
|
||||
|
||||
class InterpreterConfig {
|
||||
constructor(intercept_link_redirects) {
|
||||
this.intercept_link_redirects = intercept_link_redirects;
|
||||
}
|
||||
}
|
||||
|
||||
class Interpreter {
|
||||
constructor(root) {
|
||||
constructor(root, config) {
|
||||
this.config = config;
|
||||
this.root = root;
|
||||
this.listeners = new ListenerMap(root);
|
||||
this.nodes = [root];
|
||||
@@ -397,7 +404,7 @@ class Interpreter {
|
||||
);
|
||||
} else {
|
||||
this.NewEventListener(edit.name, edit.id, bubbles, (event) => {
|
||||
handler(event, edit.name, bubbles);
|
||||
handler(event, edit.name, bubbles, this.config);
|
||||
});
|
||||
}
|
||||
break;
|
||||
@@ -407,32 +414,34 @@ class Interpreter {
|
||||
|
||||
// this handler is only provided on the desktop and liveview implementations since this
|
||||
// method is not used by the web implementation
|
||||
function handler(event, name, bubbles) {
|
||||
function handler(event, name, bubbles, config) {
|
||||
let target = event.target;
|
||||
if (target != null) {
|
||||
let preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
|
||||
|
||||
if (event.type === "click") {
|
||||
// todo call prevent default if it's the right type of event
|
||||
let a_element = target.closest("a");
|
||||
if (a_element != null) {
|
||||
event.preventDefault();
|
||||
if (config.intercept_link_redirects) {
|
||||
let a_element = target.closest("a");
|
||||
if (a_element != null) {
|
||||
event.preventDefault();
|
||||
|
||||
let elementShouldPreventDefault =
|
||||
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
|
||||
let aElementShouldPreventDefault = a_element.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
let linkShouldPreventDefault =
|
||||
aElementShouldPreventDefault &&
|
||||
aElementShouldPreventDefault.includes(`onclick`);
|
||||
let elementShouldPreventDefault =
|
||||
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
|
||||
let aElementShouldPreventDefault = a_element.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
let linkShouldPreventDefault =
|
||||
aElementShouldPreventDefault &&
|
||||
aElementShouldPreventDefault.includes(`onclick`);
|
||||
|
||||
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
|
||||
const href = a_element.getAttribute("href");
|
||||
if (href !== "" && href !== null && href !== undefined) {
|
||||
window.ipc.postMessage(
|
||||
serializeIpcMessage("browser_open", { href })
|
||||
);
|
||||
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
|
||||
const href = a_element.getAttribute("href");
|
||||
if (href !== "" && href !== null && href !== undefined) {
|
||||
window.ipc.postMessage(
|
||||
serializeIpcMessage("browser_open", { href })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ once_cell = "1.17.1"
|
||||
# actix-ws = { version = "0.2.5", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_env_logger = { version = "0.4.0" }
|
||||
pretty_env_logger = { version = "0.5.0" }
|
||||
tokio = { version = "1.22.0", features = ["full"] }
|
||||
dioxus = { path = "../dioxus", version = "0.3.0" }
|
||||
warp = "0.3.3"
|
||||
|
||||
@@ -8,7 +8,7 @@ function main() {
|
||||
class IPC {
|
||||
constructor(root) {
|
||||
// connect to the websocket
|
||||
window.interpreter = new Interpreter(root);
|
||||
window.interpreter = new Interpreter(root, new InterpreterConfig(false));
|
||||
|
||||
let ws = new WebSocket(WS_ADDR);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use convert_case::{Case, Casing};
|
||||
use dioxus_rsx::{
|
||||
BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, IfmtInput,
|
||||
BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput,
|
||||
};
|
||||
pub use html_parser::{Dom, Node};
|
||||
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::Element(el) => {
|
||||
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
|
||||
.attributes
|
||||
|
||||
+109
-12
@@ -1,9 +1,13 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use super::*;
|
||||
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use quote::{quote, ToTokens, TokenStreamExt};
|
||||
use syn::{
|
||||
parse::{Parse, ParseBuffer, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
spanned::Spanned,
|
||||
Error, Expr, Ident, LitStr, Result, Token,
|
||||
};
|
||||
|
||||
@@ -12,7 +16,7 @@ use syn::{
|
||||
// =======================================
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
pub struct Element {
|
||||
pub name: Ident,
|
||||
pub name: ElementName,
|
||||
pub key: Option<IfmtInput>,
|
||||
pub attributes: Vec<ElementAttrNamed>,
|
||||
pub children: Vec<BodyNode>,
|
||||
@@ -22,7 +26,7 @@ pub struct Element {
|
||||
|
||||
impl Parse for Element {
|
||||
fn parse(stream: ParseStream) -> Result<Self> {
|
||||
let el_name = Ident::parse(stream)?;
|
||||
let el_name = ElementName::parse(stream)?;
|
||||
|
||||
// parse the guts
|
||||
let content: ParseBuffer;
|
||||
@@ -181,7 +185,7 @@ impl ToTokens for Element {
|
||||
|
||||
tokens.append_all(quote! {
|
||||
__cx.element(
|
||||
dioxus_elements::#name,
|
||||
#name,
|
||||
__cx.bump().alloc([ #(#listeners),* ]),
|
||||
__cx.bump().alloc([ #(#attr),* ]),
|
||||
__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)]
|
||||
pub enum ElementAttr {
|
||||
/// `attribute: "value"`
|
||||
@@ -234,7 +307,7 @@ impl ElementAttr {
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||
pub struct ElementAttrNamed {
|
||||
pub el_name: Ident,
|
||||
pub el_name: ElementName,
|
||||
pub attr: ElementAttr,
|
||||
}
|
||||
|
||||
@@ -242,24 +315,46 @@ impl ToTokens for ElementAttrNamed {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||
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 } => {
|
||||
let ns = ns(name);
|
||||
let volitile = volitile(name);
|
||||
let attribute = attribute(name);
|
||||
quote! {
|
||||
__cx.attr(
|
||||
dioxus_elements::#el_name::#name.0,
|
||||
#attribute,
|
||||
#value,
|
||||
dioxus_elements::#el_name::#name.1,
|
||||
dioxus_elements::#el_name::#name.2
|
||||
#ns,
|
||||
#volitile
|
||||
)
|
||||
}
|
||||
}
|
||||
ElementAttr::AttrExpression { name, value } => {
|
||||
let ns = ns(name);
|
||||
let volitile = volitile(name);
|
||||
let attribute = attribute(name);
|
||||
quote! {
|
||||
__cx.attr(
|
||||
dioxus_elements::#el_name::#name.0,
|
||||
#attribute,
|
||||
#value,
|
||||
dioxus_elements::#el_name::#name.1,
|
||||
dioxus_elements::#el_name::#name.2
|
||||
#ns,
|
||||
#volitile
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -288,7 +383,9 @@ impl ToTokens for ElementAttrNamed {
|
||||
dioxus_elements::events::#name(__cx, #tokens)
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
tokens.append_all(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-4
@@ -426,13 +426,25 @@ impl<'a> DynamicContext<'a> {
|
||||
match root {
|
||||
BodyNode::Element(el) => {
|
||||
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 {
|
||||
ElementAttr::AttrText { name, value } if value.is_static() => {
|
||||
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! {
|
||||
::dioxus::core::TemplateAttribute::Static {
|
||||
name: dioxus_elements::#el_name::#name.0,
|
||||
namespace: dioxus_elements::#el_name::#name.1,
|
||||
name: #name,
|
||||
namespace: #ns,
|
||||
value: #value,
|
||||
|
||||
// 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 children = quote! { #(#children),* };
|
||||
|
||||
let ns = ns(quote!(NAME_SPACE));
|
||||
let el_name = el_name.tag_name();
|
||||
|
||||
quote! {
|
||||
::dioxus::core::TemplateNode::Element {
|
||||
tag: dioxus_elements::#el_name::TAG_NAME,
|
||||
namespace: dioxus_elements::#el_name::NAME_SPACE,
|
||||
tag: #el_name,
|
||||
namespace: #ns,
|
||||
attrs: &[ #attrs ],
|
||||
children: &[ #children ],
|
||||
}
|
||||
|
||||
@@ -50,7 +50,16 @@ impl Parse for BodyNode {
|
||||
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();
|
||||
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>() {
|
||||
// this is an Element if path match of:
|
||||
// - one ident
|
||||
|
||||
Reference in new issue
Block a user