|
@@ -39,264 +39,263 @@
|
|
|
//! - Allow top-level fragments
|
|
|
|
|
|
fn main() {
|
|
|
- dioxus_desktop::launch(App);
|
|
|
-}
|
|
|
-
|
|
|
-use core::{fmt, str::FromStr};
|
|
|
-use std::fmt::Display;
|
|
|
-
|
|
|
-use baller::Baller;
|
|
|
-use dioxus::prelude::*;
|
|
|
-
|
|
|
-#[component]
|
|
|
-fn App() -> Element {
|
|
|
- let formatting = "formatting!";
|
|
|
- let formatting_tuple = ("a", "b");
|
|
|
- let lazy_fmt = format_args!("lazily formatted text");
|
|
|
- let asd = 123;
|
|
|
- rsx! {
|
|
|
- div {
|
|
|
- // Elements
|
|
|
- div {}
|
|
|
- h1 {"Some text"}
|
|
|
- h1 {"Some text with {formatting}"}
|
|
|
- h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
|
|
- h1 {"Formatting without interpolation " {formatting_tuple.0} "and" {formatting_tuple.1} }
|
|
|
- h2 {
|
|
|
- "Multiple"
|
|
|
- "Text"
|
|
|
- "Blocks"
|
|
|
- "Use comments as separators in html"
|
|
|
- }
|
|
|
- div {
|
|
|
- h1 {"multiple"}
|
|
|
- h2 {"nested"}
|
|
|
- h3 {"elements"}
|
|
|
- }
|
|
|
- div {
|
|
|
- class: "my special div",
|
|
|
- h1 {"Headers and attributes!"}
|
|
|
- }
|
|
|
- div {
|
|
|
- // pass simple rust expressions in
|
|
|
- class: lazy_fmt,
|
|
|
- id: format_args!("attributes can be passed lazily with std::fmt::Arguments"),
|
|
|
- class: "asd",
|
|
|
- class: "{asd}",
|
|
|
- // if statements can be used to conditionally render attributes
|
|
|
- class: if formatting.contains("form") { "{asd}" },
|
|
|
- div {
|
|
|
- class: {
|
|
|
- const WORD: &str = "expressions";
|
|
|
- format_args!("Arguments can be passed in through curly braces for complex {WORD}")
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Expressions can be used in element position too:
|
|
|
- {rsx!(p { "More templating!" })},
|
|
|
-
|
|
|
- // Iterators
|
|
|
- {(0..10).map(|i| rsx!(li { "{i}" }))},
|
|
|
-
|
|
|
- // Iterators within expressions
|
|
|
- {
|
|
|
- let data = std::collections::HashMap::<&'static str, &'static str>::new();
|
|
|
- // Iterators *should* have keys when you can provide them.
|
|
|
- // Keys make your app run faster. Make sure your keys are stable, unique, and predictable.
|
|
|
- // Using an "ID" associated with your data is a good idea.
|
|
|
- data.into_iter().map(|(k, v)| rsx!(li { key: "{k}", "{v}" }))
|
|
|
- }
|
|
|
-
|
|
|
- // Matching
|
|
|
- match true {
|
|
|
- true => rsx!( h1 {"Top text"}),
|
|
|
- false => rsx!( h1 {"Bottom text"})
|
|
|
- }
|
|
|
-
|
|
|
- // Conditional rendering
|
|
|
- // Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
|
|
|
- // You can convert a bool condition to rsx! with .then and .or
|
|
|
- {true.then(|| rsx!(div {}))},
|
|
|
-
|
|
|
- // Alternatively, you can use the "if" syntax - but both branches must be resolve to Element
|
|
|
- if false {
|
|
|
- h1 {"Top text"}
|
|
|
- } else {
|
|
|
- h1 {"Bottom text"}
|
|
|
- }
|
|
|
-
|
|
|
- // Using optionals for diverging branches
|
|
|
- // Note that since this is wrapped in curlies, it's interpreted as an expression
|
|
|
- {if true {
|
|
|
- Some(rsx!(h1 {"Top text"}))
|
|
|
- } else {
|
|
|
- None
|
|
|
- }}
|
|
|
-
|
|
|
- // returning "None" without a diverging branch is a bit noisy... but rare in practice
|
|
|
- {None as Option<()>},
|
|
|
-
|
|
|
- // can also just use empty fragments
|
|
|
- Fragment {}
|
|
|
-
|
|
|
- // Fragments let you insert groups of nodes without a parent.
|
|
|
- // This lets you make components that insert elements as siblings without a container.
|
|
|
- div {"A"}
|
|
|
- Fragment {
|
|
|
- div {"B"}
|
|
|
- div {"C"}
|
|
|
- Fragment {
|
|
|
- "D"
|
|
|
- Fragment {
|
|
|
- "E"
|
|
|
- "F"
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Components
|
|
|
- // Can accept any paths
|
|
|
- // Notice how you still get syntax highlighting and IDE support :)
|
|
|
- Baller {}
|
|
|
- baller::Baller {}
|
|
|
- crate::baller::Baller {}
|
|
|
-
|
|
|
- // Can take properties
|
|
|
- Taller { a: "asd" }
|
|
|
-
|
|
|
- // Can take optional properties
|
|
|
- Taller { a: "asd" }
|
|
|
-
|
|
|
- // Can pass in props directly as an expression
|
|
|
- {
|
|
|
- let props = TallerProps {a: "hello", children: None };
|
|
|
- rsx!(Taller { ..props })
|
|
|
- }
|
|
|
-
|
|
|
- // Spreading can also be overridden manually
|
|
|
- Taller {
|
|
|
- ..TallerProps { a: "ballin!", children: None },
|
|
|
- a: "not ballin!"
|
|
|
- }
|
|
|
-
|
|
|
- // Can take children too!
|
|
|
- Taller { a: "asd", div {"hello world!"} }
|
|
|
-
|
|
|
- // This component's props are defined *inline* with the `inline_props` macro
|
|
|
- WithInline { text: "using functionc all syntax" }
|
|
|
-
|
|
|
- // Components can be generic too
|
|
|
- // This component takes i32 type to give you typed input
|
|
|
- TypedInput::<i32> {}
|
|
|
-
|
|
|
- // Type inference can be used too
|
|
|
- TypedInput { initial: 10.0 }
|
|
|
-
|
|
|
- // geneircs with the `inline_props` macro
|
|
|
- Label { text: "hello geneirc world!" }
|
|
|
- Label { text: 99.9 }
|
|
|
-
|
|
|
- // Lowercase components work too, as long as they are access using a path
|
|
|
- baller::lowercase_component {}
|
|
|
-
|
|
|
- // For in-scope lowercase components, use the `self` keyword
|
|
|
- self::lowercase_helper {}
|
|
|
-
|
|
|
- // helper functions
|
|
|
- // Anything that implements IntoVnode can be dropped directly into Rsx
|
|
|
- {helper("hello world!")}
|
|
|
-
|
|
|
- // Strings can be supplied directly
|
|
|
- {String::from("Hello world!")}
|
|
|
-
|
|
|
- // So can format_args
|
|
|
- {format_args!("Hello {}!", "world")}
|
|
|
-
|
|
|
- // Or we can shell out to a helper function
|
|
|
- {format_dollars(10, 50)}
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn format_dollars(dollars: u32, cents: u32) -> String {
|
|
|
- format!("${dollars}.{cents:02}")
|
|
|
-}
|
|
|
-
|
|
|
-fn helper<'a>(cx: &'a ScopeState, text: &'a str) -> Element {
|
|
|
- rsx! {
|
|
|
- p { "{text}" }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// no_case_check disables PascalCase checking if you *really* want a snake_case component.
|
|
|
-// This will likely be deprecated/removed in a future update that will introduce a more polished linting system,
|
|
|
-// something like Clippy.
|
|
|
-#[component(no_case_check)]
|
|
|
-fn lowercase_helper() -> Element {
|
|
|
- rsx! {
|
|
|
- "asd"
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-mod baller {
|
|
|
- use super::*;
|
|
|
-
|
|
|
- #[component]
|
|
|
- /// This component totally balls
|
|
|
- pub fn Baller() -> Element {
|
|
|
- todo!()
|
|
|
- }
|
|
|
-
|
|
|
- // no_case_check disables PascalCase checking if you *really* want a snake_case component.
|
|
|
- // This will likely be deprecated/removed in a future update that will introduce a more polished linting system,
|
|
|
- // something like Clippy.
|
|
|
- #[component(no_case_check)]
|
|
|
- pub fn lowercase_component() -> Element {
|
|
|
- rsx! { "look ma, no uppercase" }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Documention for this component is visible within the rsx macro
|
|
|
-#[component]
|
|
|
-pub fn Taller(
|
|
|
- /// Fields are documented and accessible in rsx!
|
|
|
- a: &'static str,
|
|
|
- children: Element,
|
|
|
-) -> Element {
|
|
|
- rsx! {
|
|
|
- {&cx.props.children}
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[derive(Props, PartialEq, Eq)]
|
|
|
-pub struct TypedInputProps<T> {
|
|
|
- #[props(optional, default)]
|
|
|
- initial: Option<T>,
|
|
|
-}
|
|
|
-
|
|
|
-#[allow(non_snake_case)]
|
|
|
-pub fn TypedInput<T>(_: Scope<TypedInputProps<T>>) -> Element
|
|
|
-where
|
|
|
- T: FromStr + fmt::Display,
|
|
|
- <T as FromStr>::Err: std::fmt::Display,
|
|
|
-{
|
|
|
todo!()
|
|
|
+ // dioxus_desktop::launch(App);
|
|
|
}
|
|
|
|
|
|
-#[component]
|
|
|
-fn WithInline<'a>(cx: Scope<'a>, text: &'a str) -> Element {
|
|
|
- rsx! {
|
|
|
- p { "{text}" }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-#[component]
|
|
|
-fn Label<T>(text: T) -> Element
|
|
|
-where
|
|
|
- T: Display,
|
|
|
-{
|
|
|
- rsx! {
|
|
|
- p { "{text}" }
|
|
|
- }
|
|
|
-}
|
|
|
+// use core::{fmt, str::FromStr};
|
|
|
+// use std::fmt::Display;
|
|
|
+
|
|
|
+// use baller::Baller;
|
|
|
+// use dioxus::prelude::*;
|
|
|
+
|
|
|
+// #[component]
|
|
|
+// fn App() -> Element {
|
|
|
+// let formatting = "formatting!";
|
|
|
+// let formatting_tuple = ("a", "b");
|
|
|
+// let lazy_fmt = format_args!("lazily formatted text");
|
|
|
+// let asd = 123;
|
|
|
+// rsx! {
|
|
|
+// div {
|
|
|
+// // Elements
|
|
|
+// div {}
|
|
|
+// h1 {"Some text"}
|
|
|
+// h1 {"Some text with {formatting}"}
|
|
|
+// h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
|
|
+// h1 {"Formatting without interpolation " {formatting_tuple.0} "and" {formatting_tuple.1} }
|
|
|
+// h2 {
|
|
|
+// "Multiple"
|
|
|
+// "Text"
|
|
|
+// "Blocks"
|
|
|
+// "Use comments as separators in html"
|
|
|
+// }
|
|
|
+// div {
|
|
|
+// h1 {"multiple"}
|
|
|
+// h2 {"nested"}
|
|
|
+// h3 {"elements"}
|
|
|
+// }
|
|
|
+// div {
|
|
|
+// class: "my special div",
|
|
|
+// h1 {"Headers and attributes!"}
|
|
|
+// }
|
|
|
+// div {
|
|
|
+// // pass simple rust expressions in
|
|
|
+// class: lazy_fmt,
|
|
|
+// id: format_args!("attributes can be passed lazily with std::fmt::Arguments"),
|
|
|
+// class: "asd",
|
|
|
+// class: "{asd}",
|
|
|
+// // if statements can be used to conditionally render attributes
|
|
|
+// class: if formatting.contains("form") { "{asd}" },
|
|
|
+// div {
|
|
|
+// class: {
|
|
|
+// const WORD: &str = "expressions";
|
|
|
+// format_args!("Arguments can be passed in through curly braces for complex {WORD}")
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// // Expressions can be used in element position too:
|
|
|
+// {rsx!(p { "More templating!" })},
|
|
|
+
|
|
|
+// // Iterators
|
|
|
+// {(0..10).map(|i| rsx!(li { "{i}" }))},
|
|
|
+
|
|
|
+// // Iterators within expressions
|
|
|
+// {
|
|
|
+// let data = std::collections::HashMap::<&'static str, &'static str>::new();
|
|
|
+// // Iterators *should* have keys when you can provide them.
|
|
|
+// // Keys make your app run faster. Make sure your keys are stable, unique, and predictable.
|
|
|
+// // Using an "ID" associated with your data is a good idea.
|
|
|
+// data.into_iter().map(|(k, v)| rsx!(li { key: "{k}", "{v}" }))
|
|
|
+// }
|
|
|
+
|
|
|
+// // Matching
|
|
|
+// match true {
|
|
|
+// true => rsx!( h1 {"Top text"}),
|
|
|
+// false => rsx!( h1 {"Bottom text"})
|
|
|
+// }
|
|
|
+
|
|
|
+// // Conditional rendering
|
|
|
+// // Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
|
|
|
+// // You can convert a bool condition to rsx! with .then and .or
|
|
|
+// {true.then(|| rsx!(div {}))},
|
|
|
+
|
|
|
+// // Alternatively, you can use the "if" syntax - but both branches must be resolve to Element
|
|
|
+// if false {
|
|
|
+// h1 {"Top text"}
|
|
|
+// } else {
|
|
|
+// h1 {"Bottom text"}
|
|
|
+// }
|
|
|
+
|
|
|
+// // Using optionals for diverging branches
|
|
|
+// // Note that since this is wrapped in curlies, it's interpreted as an expression
|
|
|
+// {if true {
|
|
|
+// Some(rsx!(h1 {"Top text"}))
|
|
|
+// } else {
|
|
|
+// None
|
|
|
+// }}
|
|
|
+
|
|
|
+// // returning "None" without a diverging branch is a bit noisy... but rare in practice
|
|
|
+// {None as Option<()>},
|
|
|
+
|
|
|
+// // can also just use empty fragments
|
|
|
+// Fragment {}
|
|
|
+
|
|
|
+// // Fragments let you insert groups of nodes without a parent.
|
|
|
+// // This lets you make components that insert elements as siblings without a container.
|
|
|
+// div {"A"}
|
|
|
+// Fragment {
|
|
|
+// div {"B"}
|
|
|
+// div {"C"}
|
|
|
+// Fragment {
|
|
|
+// "D"
|
|
|
+// Fragment {
|
|
|
+// "E"
|
|
|
+// "F"
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// // Components
|
|
|
+// // Can accept any paths
|
|
|
+// // Notice how you still get syntax highlighting and IDE support :)
|
|
|
+// Baller {}
|
|
|
+// baller::Baller {}
|
|
|
+// crate::baller::Baller {}
|
|
|
+
|
|
|
+// // Can take properties
|
|
|
+// Taller { a: "asd" }
|
|
|
+
|
|
|
+// // Can take optional properties
|
|
|
+// Taller { a: "asd" }
|
|
|
+
|
|
|
+// // Can pass in props directly as an expression
|
|
|
+// {
|
|
|
+// let props = TallerProps {a: "hello", children: None };
|
|
|
+// rsx!(Taller { ..props })
|
|
|
+// }
|
|
|
+
|
|
|
+// // Spreading can also be overridden manually
|
|
|
+// Taller {
|
|
|
+// ..TallerProps { a: "ballin!", children: None },
|
|
|
+// a: "not ballin!"
|
|
|
+// }
|
|
|
+
|
|
|
+// // Can take children too!
|
|
|
+// Taller { a: "asd", div {"hello world!"} }
|
|
|
+
|
|
|
+// // This component's props are defined *inline* with the `inline_props` macro
|
|
|
+// WithInline { text: "using functionc all syntax" }
|
|
|
+
|
|
|
+// // Components can be generic too
|
|
|
+// // This component takes i32 type to give you typed input
|
|
|
+// TypedInput::<i32> {}
|
|
|
+
|
|
|
+// // Type inference can be used too
|
|
|
+// TypedInput { initial: 10.0 }
|
|
|
+
|
|
|
+// // geneircs with the `inline_props` macro
|
|
|
+// Label { text: "hello geneirc world!" }
|
|
|
+// Label { text: 99.9 }
|
|
|
+
|
|
|
+// // Lowercase components work too, as long as they are access using a path
|
|
|
+// baller::lowercase_component {}
|
|
|
+
|
|
|
+// // For in-scope lowercase components, use the `self` keyword
|
|
|
+// self::lowercase_helper {}
|
|
|
+
|
|
|
+// // helper functions
|
|
|
+// // Anything that implements IntoVnode can be dropped directly into Rsx
|
|
|
+// {helper("hello world!")}
|
|
|
+
|
|
|
+// // Strings can be supplied directly
|
|
|
+// {String::from("Hello world!")}
|
|
|
+
|
|
|
+// // So can format_args
|
|
|
+// {format_args!("Hello {}!", "world")}
|
|
|
+
|
|
|
+// // Or we can shell out to a helper function
|
|
|
+// {format_dollars(10, 50)}
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// fn format_dollars(dollars: u32, cents: u32) -> String {
|
|
|
+// format!("${dollars}.{cents:02}")
|
|
|
+// }
|
|
|
+
|
|
|
+// fn helper<'a>(cx: &'a ScopeState, text: &'a str) -> Element {
|
|
|
+// rsx! {
|
|
|
+// p { "{text}" }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// // no_case_check disables PascalCase checking if you *really* want a snake_case component.
|
|
|
+// // This will likely be deprecated/removed in a future update that will introduce a more polished linting system,
|
|
|
+// // something like Clippy.
|
|
|
+// #[component(no_case_check)]
|
|
|
+// fn lowercase_helper() -> Element {
|
|
|
+// rsx! {
|
|
|
+// "asd"
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// mod baller {
|
|
|
+// use super::*;
|
|
|
+
|
|
|
+// #[component]
|
|
|
+// /// This component totally balls
|
|
|
+// pub fn Baller() -> Element {
|
|
|
+// todo!()
|
|
|
+// }
|
|
|
+
|
|
|
+// // no_case_check disables PascalCase checking if you *really* want a snake_case component.
|
|
|
+// // This will likely be deprecated/removed in a future update that will introduce a more polished linting system,
|
|
|
+// // something like Clippy.
|
|
|
+// #[component(no_case_check)]
|
|
|
+// pub fn lowercase_component() -> Element {
|
|
|
+// rsx! { "look ma, no uppercase" }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /// Documention for this component is visible within the rsx macro
|
|
|
+// #[component]
|
|
|
+// pub fn Taller(
|
|
|
+// /// Fields are documented and accessible in rsx!
|
|
|
+// a: &'static str,
|
|
|
+// children: Element,
|
|
|
+// ) -> Element {
|
|
|
+// rsx! { {&children} }
|
|
|
+// }
|
|
|
+
|
|
|
+// #[derive(Props, PartialEq, Eq)]
|
|
|
+// pub struct TypedInputProps<T> {
|
|
|
+// #[props(optional, default)]
|
|
|
+// initial: Option<T>,
|
|
|
+// }
|
|
|
+
|
|
|
+// #[allow(non_snake_case)]
|
|
|
+// pub fn TypedInput<T>(_: Scope<TypedInputProps<T>>) -> Element
|
|
|
+// where
|
|
|
+// T: FromStr + fmt::Display,
|
|
|
+// <T as FromStr>::Err: std::fmt::Display,
|
|
|
+// {
|
|
|
+// todo!()
|
|
|
+// }
|
|
|
+
|
|
|
+// #[component]
|
|
|
+// fn WithInline(cx: Scope<'a>, text: &'a str) -> Element {
|
|
|
+// rsx! {
|
|
|
+// p { "{text}" }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// #[component]
|
|
|
+// fn Label<T: Clone + PartialEq>(text: T) -> Element
|
|
|
+// where
|
|
|
+// T: Display,
|
|
|
+// {
|
|
|
+// rsx! {
|
|
|
+// p { "{text}" }
|
|
|
+// }
|
|
|
+// }
|