diff --git a/examples/rsx_usage.rs b/examples/rsx_usage.rs index e9cfa57aa..361a3839b 100644 --- a/examples/rsx_usage.rs +++ b/examples/rsx_usage.rs @@ -39,263 +39,266 @@ //! - Allow top-level fragments fn main() { - todo!() - //launch_desktop(App); + launch(app) } -// use core::{fmt, str::FromStr}; -// use std::fmt::Display; +use core::{fmt, str::FromStr}; +use std::fmt::Display; -// use baller::Baller; -// use dioxus::prelude::*; +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}") -// } -// } -// } +fn app() -> Element { + let formatting = "formatting!"; + let formatting_tuple = ("a", "b"); + let lazy_fmt = format_args!("lazily formatted text"); + let asd = 123; -// // Expressions can be used in element position too: -// {rsx!(p { "More templating!" })}, + 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}") + } + } + } -// // Iterators -// {(0..10).map(|i| rsx!(li { "{i}" }))}, + // Expressions can be used in element position too: + {rsx!(p { "More templating!" })}, -// // 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}" })) -// } + // Iterators + {(0..10).map(|i| rsx!(li { "{i}" }))}, -// // Matching -// match true { -// true => rsx!( h1 {"Top text"}), -// false => rsx!( h1 {"Bottom text"}) -// } + // 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}" })) + } -// // 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 {}))}, + // Matching + match true { + true => rsx!( h1 {"Top text"}), + false => rsx!( h1 {"Bottom text"}) + } -// // Alternatively, you can use the "if" syntax - but both branches must be resolve to Element -// if false { -// h1 {"Top text"} -// } else { -// 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 {}))}, -// // 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 -// }} + // Alternatively, you can use the "if" syntax - but both branches must be resolve to Element + if false { + h1 {"Top text"} + } else { + h1 {"Bottom text"} + } -// // returning "None" without a diverging branch is a bit noisy... but rare in practice -// {None as Option<()>}, + // 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 + }} -// // can also just use empty fragments -// Fragment {} + // returning "None" without a diverging branch is a bit noisy... but rare in practice + {None as Option<()>}, -// // 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" -// } -// } -// } + // can also just use empty fragments + Fragment {} -// // Components -// // Can accept any paths -// // Notice how you still get syntax highlighting and IDE support :) -// Baller {} -// baller::Baller {} -// crate::baller::Baller {} + // 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" + } + } + } -// // Can take properties -// Taller { a: "asd" } + // Components + // Can accept any paths + // Notice how you still get syntax highlighting and IDE support :) + Baller {} + baller::Baller {} + crate::baller::Baller {} -// // Can take optional properties -// Taller { a: "asd" } + // Can take properties + Taller { a: "asd" } -// // Can pass in props directly as an expression -// { -// let props = TallerProps {a: "hello", children: None }; -// rsx!(Taller { ..props }) -// } + // Can take optional properties + Taller { a: "asd" } -// // Spreading can also be overridden manually -// Taller { -// ..TallerProps { a: "ballin!", children: None }, -// a: "not ballin!" -// } + // Can pass in props directly as an expression + { + let props = TallerProps {a: "hello", children: None }; + rsx!(Taller { ..props }) + } -// // Can take children too! -// Taller { a: "asd", div {"hello world!"} } + // Spreading can also be overridden manually + Taller { + ..TallerProps { a: "ballin!", children: None }, + a: "not ballin!" + } -// // This component's props are defined *inline* with the `inline_props` macro -// WithInline { text: "using functionc all syntax" } + // Can take children too! + Taller { a: "asd", div {"hello world!"} } -// // Components can be generic too -// // This component takes i32 type to give you typed input -// TypedInput:: {} + // This component's props are defined *inline* with the `inline_props` macro + WithInline { text: "using functionc all syntax" } -// // Type inference can be used too -// TypedInput { initial: 10.0 } + // Components can be generic too + // This component takes i32 type to give you typed input + TypedInput:: {} -// // geneircs with the `inline_props` macro -// Label { text: "hello geneirc world!" } -// Label { text: 99.9 } + // Type inference can be used too + TypedInput { initial: 10.0 } -// // Lowercase components work too, as long as they are access using a path -// baller::lowercase_component {} + // geneircs with the `inline_props` macro + Label { text: "hello geneirc world!" } + Label { text: 99.9 } -// // For in-scope lowercase components, use the `self` keyword -// self::lowercase_helper {} + // Lowercase components work too, as long as they are access using a path + baller::lowercase_component {} -// // helper functions -// // Anything that implements IntoVnode can be dropped directly into Rsx -// {helper("hello world!")} + // For in-scope lowercase components, use the `self` keyword + self::lowercase_helper {} -// // Strings can be supplied directly -// {String::from("Hello world!")} + // helper functions + // Anything that implements IntoVnode can be dropped directly into Rsx + {helper("hello world!")} -// // So can format_args -// {format_args!("Hello {}!", "world")} + // Strings can be supplied directly + {String::from("Hello world!")} -// // Or we can shell out to a helper function -// {format_dollars(10, 50)} -// } -// } -// } + // So can format_args + {format_args!("Hello {}!", "world")} -// fn format_dollars(dollars: u32, cents: u32) -> String { -// format!("${dollars}.{cents:02}") -// } + // Or we can shell out to a helper function + {format_dollars(10, 50)} + } + } +} -// fn helper<'a>(cx: &'a ScopeState, text: &'a str) -> Element { -// rsx! { -// p { "{text}" } -// } -// } +fn format_dollars(dollars: u32, cents: u32) -> String { + format!("${dollars}.{cents:02}") +} -// // 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" -// } -// } +fn helper(text: &str) -> Element { + rsx! { + p { "{text}" } + } +} -// mod baller { -// use super::*; +// 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" + } +} -// #[component] -// /// This component totally balls -// pub fn Baller() -> Element { -// todo!() -// } +mod baller { + use super::*; -// // 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" } -// } -// } + #[component] + /// This component totally balls + pub fn Baller() -> Element { + rsx! { "ballin'" } + } -// /// 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} } -// } + // 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" } + } +} -// #[derive(Props, PartialEq, Eq)] -// pub struct TypedInputProps { -// #[props(optional, default)] -// initial: Option, -// } +/// 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} } +} -// #[allow(non_snake_case)] -// pub fn TypedInput(_: Scope>) -> Element -// where -// T: FromStr + fmt::Display, -// ::Err: std::fmt::Display, -// { -// todo!() -// } +#[derive(Props, Clone, PartialEq, Eq)] +pub struct TypedInputProps { + #[props(optional, default)] + initial: Option, +} -// #[component] -// fn WithInline(cx: Scope<'a>, text: &'a str) -> Element { -// rsx! { -// p { "{text}" } -// } -// } +#[allow(non_snake_case)] +pub fn TypedInput(props: TypedInputProps) -> Element +where + T: FromStr + fmt::Display + PartialEq + Clone + 'static, + ::Err: std::fmt::Display, +{ + if let Some(props) = props.initial { + return rsx! { "{props}" }; + } -// #[component] -// fn Label(text: T) -> Element -// where -// T: Display, -// { -// rsx! { -// p { "{text}" } -// } -// } + None +} + +#[component] +fn WithInline(text: String) -> Element { + rsx! { + p { "{text}" } + } +} + +#[component] +fn Label(text: T) -> Element +where + T: Display, +{ + rsx! { + p { "{text}" } + } +}