Components participate in event handlers

This commit is contained in:
Jonathan Kelley 2024-01-11 12:11:27 -08:00
parent 8881b8a473
commit 1527b81e02
No known key found for this signature in database
GPG key ID: 1FBB50F7EB0A08BE
12 changed files with 86 additions and 54 deletions

View file

@ -14,9 +14,9 @@ fn app(cx: Scope) -> Element {
}
render! {
{(0..count).map(|_| rsx!{
for _ in 0..count {
drop_child {}
})}
}
}
}

View file

@ -17,11 +17,9 @@ fn app(cx: Scope) -> Element {
response.respond(Response::new(include_bytes!("./assets/logo.png").to_vec()));
});
cx.render(rsx! {
render! {
div {
img {
src: "/logos/logo.png"
}
img { src: "/logos/logo.png" }
}
})
}
}

View file

@ -22,9 +22,7 @@ fn DemoC(cx: Scope, x: i32) -> Element {
result.throw()?;
cx.render(rsx! {
h1 {
"{x}"
}
})
render! {
h1 { "{x}" }
}
}

View file

@ -35,18 +35,17 @@ fn app(cx: Scope) -> Element {
main {
{files.read().path_names.iter().enumerate().map(|(dir_id, path)| {
let path_end = path.split('/').last().unwrap_or(path.as_str());
let icon_type = if path_end.contains('.') {
"description"
} else {
"folder"
};
rsx! (
div {
class: "folder",
key: "{path}",
i { class: "material-icons",
onclick: move |_| files.write().enter_dir(dir_id),
"{icon_type}"
if path_end.contains('.') {
"description"
} else {
"folder"
}
p { class: "cooltip", "0 folders / 0 files" }
}
h1 { "{path_end}" }

View file

@ -7,9 +7,9 @@ fn main() {
}
fn app(cx: Scope) -> Element {
cx.render(rsx! { generic_child {
data: 0i32
} })
render! {
generic_child { data: 0 }
}
}
#[derive(PartialEq, Props)]
@ -18,9 +18,7 @@ struct GenericChildProps<T: Display + PartialEq> {
}
fn generic_child<T: Display + PartialEq>(cx: Scope<GenericChildProps<T>>) -> Element {
let data = &cx.props.data;
cx.render(rsx! { div {
"{data}"
} })
render! {
div { "{&cx.props.data}" }
}
}

View file

@ -5,7 +5,7 @@ fn main() {
}
fn app(cx: Scope) -> Element {
cx.render(rsx! (
render! {
div { "Hello, world!" }
))
}
}

View file

@ -35,11 +35,13 @@ fn main() {
dioxus_desktop::launch_cfg(app, cfg);
}
const STYLE: &str = include_str!("./assets/calculator.css");
fn app(cx: Scope) -> Element {
let state = use_ref(cx, Calculator::new);
cx.render(rsx! {
style { {include_str!("./assets/calculator.css")} }
style { {STYLE} }
div { id: "wrapper",
div { class: "app",
div { class: "calculator", onkeypress: move |evt| state.write().handle_keydown(evt),

View file

@ -51,26 +51,23 @@ pub fn App(cx: Scope) -> Element {
#[component]
fn DataEditor(cx: Scope, id: usize) -> Element {
let cool_data = use_shared_state::<CoolData>(cx).unwrap().read();
let data = use_shared_state::<CoolData>(cx)?;
let my_data = &cool_data.view(id).unwrap();
render!(p {
"{my_data}"
})
render! {
p {
{data.read().view(id)?}
}
}
}
#[component]
fn DataView(cx: Scope, id: usize) -> Element {
let cool_data = use_shared_state::<CoolData>(cx).unwrap();
let data = use_shared_state::<CoolData>(cx)?;
let oninput = |e: FormEvent| cool_data.write().set(*id, e.value());
let cool_data = cool_data.read();
let my_data = &cool_data.view(id).unwrap();
render!(input {
oninput: oninput,
value: "{my_data}"
})
render! {
input {
oninput: move |e: FormEvent| data.write().set(*id, e.value()),
value: data.read().view(id)?
}
}
}

View file

@ -11,22 +11,35 @@ fn app(cx: Scope) -> Element {
let class = "class";
let id = "id";
// todo: i'd like it for children to be inferred
// todo: i'd like it for children on elements to be inferred as the children of the element
// also should shorthands understand references/dereferences?
// ie **a, *a, &a, &mut a, etc
let children = render! { "Child" };
let onclick = move |_| println!("Clicked!");
render! {
div { class, id, {&children} }
Component { a, b, c, children }
Component { a, ..ComponentProps { a: 1, b: 2, c: 3, children: None } }
Component { a, b, c, children, onclick }
Component { a, ..ComponentProps { a: 1, b: 2, c: 3, children: None, onclick: Default::default() } }
}
}
#[component]
fn Component<'a>(cx: Scope<'a>, a: i32, b: i32, c: i32, children: Element<'a>) -> Element {
fn Component<'a>(
cx: Scope<'a>,
a: i32,
b: i32,
c: i32,
children: Element<'a>,
onclick: EventHandler<'a, ()>,
) -> Element {
render! {
div { "{a}" }
div { "{b}" }
div { "{c}" }
div { {children} }
div {
onclick: move |_| onclick.call(()),
}
}
}

View file

@ -804,6 +804,15 @@ impl<'a, 'b> IntoDynNode<'b> for &'a str {
}
}
impl IntoDynNode<'_> for &String {
fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode {
DynamicNode::Text(VText {
value: cx.bump().alloc_str(&self),
id: Default::default(),
})
}
}
impl IntoDynNode<'_> for String {
fn into_dyn_node(self, cx: &ScopeState) -> DynamicNode {
DynamicNode::Text(VText {
@ -898,6 +907,12 @@ impl<'a> IntoAttributeValue<'a> for String {
}
}
impl<'a> IntoAttributeValue<'a> for &String {
fn into_value(self, cx: &'a Bump) -> AttributeValue<'a> {
AttributeValue::Text(cx.alloc_str(&self))
}
}
impl<'a> IntoAttributeValue<'a> for f64 {
fn into_value(self, _: &'a Bump) -> AttributeValue<'a> {
AttributeValue::Float(self)

View file

@ -109,17 +109,25 @@ impl ToTokens for ElementAttrNamed {
};
let attribute = {
let value = &self.attr.value;
let is_shorthand_event = match &attr.value {
ElementAttrValue::Shorthand(s) => s.to_string().starts_with("on"),
_ => false,
};
match &attr.value {
ElementAttrValue::AttrLiteral(_)
| ElementAttrValue::AttrExpr(_)
| ElementAttrValue::Shorthand(_)
| ElementAttrValue::AttrOptionalExpr { .. } => {
| ElementAttrValue::AttrOptionalExpr { .. }
if !is_shorthand_event =>
{
let name = &self.attr.name;
let ns = ns(name);
let volitile = volitile(name);
let attribute = attribute(name);
let value = &self.attr.value;
let value = quote! { #value };
quote! {
__cx.attr(
#attribute,
@ -131,12 +139,13 @@ impl ToTokens for ElementAttrNamed {
}
ElementAttrValue::EventTokens(tokens) => match &self.attr.name {
ElementAttrName::BuiltIn(name) => {
quote! {
dioxus_elements::events::#name(__cx, #tokens)
}
quote! { dioxus_elements::events::#name(__cx, #tokens) }
}
ElementAttrName::Custom(_) => todo!(),
},
_ => {
quote! { dioxus_elements::events::#value(__cx, #value) }
}
}
};

View file

@ -241,6 +241,9 @@ impl ContentField {
impl ToTokens for ContentField {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
ContentField::Shorthand(i) if i.to_string().starts_with("on") => {
tokens.append_all(quote! { __cx.event_handler(#i) })
}
ContentField::Shorthand(i) => tokens.append_all(quote! { #i }),
ContentField::ManExpr(e) => e.to_tokens(tokens),
ContentField::Formatted(s) => tokens.append_all(quote! { __cx.raw_text(#s) }),