Skip to content

Commit

Permalink
Fix callback and node ref in leptos-struct-component
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielleHuisman committed Nov 23, 2024
1 parent fb54263 commit 99f0c01
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 168 deletions.
128 changes: 57 additions & 71 deletions packages/leptos-struct-component-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
extern crate proc_macro;

use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use quote::quote;
use syn::{
parse_macro_input, spanned::Spanned, AttrStyle, Attribute, Data, DeriveInput, Ident, LitBool,
LitStr, Meta, Type,
parse_macro_input, spanned::Spanned, AttrStyle, Attribute, Data, DeriveInput, GenericArgument,
LitBool, LitStr, Meta, PathArguments, Type,
};

#[derive(Debug, Default)]
Expand Down Expand Up @@ -114,107 +114,92 @@ pub fn derive_struct_component(input: proc_macro::TokenStream) -> proc_macro::To
}
}

// if ident == "attributes" {
// attributes_map = Some(quote! {
// .chain(
// self.attributes
// .into_iter()
// .flatten()
// .flat_map(|(key, value)| value.map(|value| (
// ::yew::virtual_dom::AttrValue::from(key),
// ::yew::virtual_dom::AttributeOrProperty::Attribute(AttrValue::from(value)),
// )),
// ),
// )
// });

// continue;
// }
if ident == "attributes" {
// TODO: dynamic attributes

// attributes_map = Some(quote! {
// .chain(
// self.attributes
// .into_iter()
// .flatten()
// .flat_map(|(key, value)| value.map(|value| (
// ::yew::virtual_dom::AttrValue::from(key),
// ::yew::virtual_dom::AttributeOrProperty::Attribute(AttrValue::from(value)),
// )),
// ),
// )
// });

continue;
}

if ident == "node_ref" {
node_ref = Some(quote! {
tag.node_ref = self.node_ref;
.node_ref(self.node_ref)
});

continue;
}

if ident.to_string().starts_with("on") {
if let Type::Path(path) = &field.ty {
let event = ident
.to_string()
.strip_prefix("on")
.expect("String should start with `on`.")
.parse::<TokenStream>()
.expect("String should parse as TokenStream.");

let first = path.path.segments.first();
let first_argument = first.and_then(|segment| match &segment.arguments {
PathArguments::None => None,
PathArguments::AngleBracketed(arguments) => {
arguments.args.first().and_then(|arg| match arg {
GenericArgument::Type(Type::Path(path)) => {
path.path.segments.first()
}
_ => None,
})
}
PathArguments::Parenthesized(_) => None,
});

if first.is_some_and(|segment| segment.ident == "Callback") {
// listeners.push(ident.clone());
listeners.push(quote! {
.on(::leptos::tachys::html::event::#event, move |event| {
self.#ident.run(event);
})
});

continue;
} else if first.is_some_and(|segment| segment.ident == "Option")
&& first_argument.is_some_and(|argument| argument.ident == "Callback")
{
listeners.push(quote! {
.#ident(move |event| self.#ident.run(event))
.on(::leptos::tachys::html::event::#event, move |event| {
if let Some(listener) = &self.#ident {
listener.run(event);
}
})
});

continue;
}
}
}

// if ident == "checked" {
// attribute_checked = Some(quote! {
// tag.set_checked(self.checked);
// });
// }

// if ident == "value" {
// attribute_value = Some(quote! {
// tag.set_value(self.value.clone());
// });
// }

match &field.ty {
Type::Path(path) => {
let name = ident.to_string().replace("_", "-");
let name = if name.starts_with("r#") {
name.strip_prefix("r#").expect("String should have prefix.")
} else {
name.as_str()
}
.to_token_stream();

let first = path.path.segments.first();

attributes.push(
if first.is_some_and(|segment| segment.ident == "MaybeProp") {
quote! {
.#ident(move || self.#ident.get())
}
} else if first.is_some_and(|segment| segment.ident == "Option") {
quote! {
.#ident(self.#ident)

// self.#ident.map(|value| (
// ::yew::virtual_dom::AttrValue::from(#name),
// ::yew::virtual_dom::AttributeOrProperty::Attribute(
// ::yew::virtual_dom::AttrValue::from(value)
// )
// ))
}
} else if first.is_some_and(|segment| segment.ident == "bool") {
quote! {
.#ident(self.#ident)

// self.#ident.then_some((
// ::yew::virtual_dom::AttrValue::from(#name),
// ::yew::virtual_dom::AttributeOrProperty::Attribute(
// ::yew::virtual_dom::AttrValue::from("")
// )
// ))
}
} else {
quote! {
.#ident(self.#ident)

// Some((
// ::yew::virtual_dom::AttrValue::from(#name),
// ::yew::virtual_dom::AttributeOrProperty::Attribute(
// ::yew::virtual_dom::AttrValue::from(self.#ident)
// )
// ))
}
},
);
Expand Down Expand Up @@ -261,6 +246,7 @@ pub fn derive_struct_component(input: proc_macro::TokenStream) -> proc_macro::To
// TODO: dynamic attributes

#tag
#node_ref
#(#attributes)*
#(#listeners)*
#children
Expand Down
140 changes: 44 additions & 96 deletions packages/leptos-struct-component/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::{
collections::HashMap,
ops::Deref,
option::{IntoIter, Iter, IterMut},
use std::{collections::HashMap, ops::Deref};

use leptos::{
attr::custom::{custom_attribute, CustomAttr},
html::button,
prelude::AddAnyAttr,
};

#[derive(Clone, Debug, Default, PartialEq)]
pub struct Attributes(Option<HashMap<AttrValue, Option<AttrValue>>>);
pub struct Attributes(Option<HashMap<String, Option<String>>>);

impl Attributes {
pub fn with_defaults<I: Into<Attributes>>(mut self, defaults: I) -> Attributes {
Expand All @@ -20,41 +22,39 @@ impl Attributes {

self
}

pub fn to_custom_attributes(self) -> Vec<CustomAttr<String, Option<String>>> {
self.0
.map(|map| {
map.into_iter()
.map(|(key, value)| custom_attribute(key, value))
.collect()
})
.unwrap_or_default()
}

// pub fn test(self) {
// let attrs = self.to_custom_attributes();

// let mut tag = button();

// let test = attrs
// .into_iter()
// .fold(tag, |tag, attr| tag.add_any_attr(attr));
// }
}

impl Deref for Attributes {
type Target = Option<HashMap<AttrValue, Option<AttrValue>>>;
type Target = Option<HashMap<String, Option<String>>>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl From<HashMap<AttrValue, Option<AttrValue>>> for Attributes {
fn from(value: HashMap<AttrValue, Option<AttrValue>>) -> Attributes {
Attributes(Some(value))
}
}

impl From<HashMap<AttrValue, AttrValue>> for Attributes {
fn from(value: HashMap<AttrValue, AttrValue>) -> Attributes {
Attributes(Some(
value
.into_iter()
.map(|(key, value)| (key, Some(value)))
.collect(),
))
}
}

impl From<HashMap<String, Option<String>>> for Attributes {
fn from(value: HashMap<String, Option<String>>) -> Attributes {
Attributes(Some(
value
.into_iter()
.map(|(key, value)| (AttrValue::from(key), value.map(AttrValue::from)))
.collect(),
))
Attributes(Some(value))
}
}

Expand All @@ -63,106 +63,54 @@ impl From<HashMap<String, String>> for Attributes {
Attributes(Some(
value
.into_iter()
.map(|(key, value)| (AttrValue::from(key), Some(AttrValue::from(value))))
.map(|(key, value)| (key, Some(value)))
.collect(),
))
}
}

impl<const N: usize> From<[(AttrValue, Option<AttrValue>); N]> for Attributes {
fn from(value: [(AttrValue, Option<AttrValue>); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value)))
}
}

impl<const N: usize> From<[(AttrValue, AttrValue); N]> for Attributes {
fn from(value: [(AttrValue, AttrValue); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(
value.map(|(key, value)| (key, Some(value))),
)))
}
}

impl<const N: usize> From<[(&str, Option<&str>); N]> for Attributes {
fn from(value: [(&str, Option<&str>); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(
AttrValue::from(key.to_string()),
value.map(|value| AttrValue::from(value.to_string())),
)
(key.to_string(), value.map(|value| value.to_string()))
}))))
}
}

impl<const N: usize> From<[(&str, &str); N]> for Attributes {
fn from(value: [(&str, &str); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(
AttrValue::from(key.to_string()),
Some(AttrValue::from(value.to_string())),
)
}))))
Attributes(Some(HashMap::from_iter(
value.map(|(key, value)| (key.to_string(), Some(value.to_string()))),
)))
}
}

impl<const N: usize> From<[(&str, Option<String>); N]> for Attributes {
fn from(value: [(&str, Option<String>); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(AttrValue::from(key.to_string()), value.map(AttrValue::from))
}))))
Attributes(Some(HashMap::from_iter(
value.map(|(key, value)| (key.to_string(), value)),
)))
}
}

impl<const N: usize> From<[(&str, String); N]> for Attributes {
fn from(value: [(&str, String); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(
AttrValue::from(key.to_string()),
Some(AttrValue::from(value)),
)
}))))
Attributes(Some(HashMap::from_iter(
value.map(|(key, value)| (key.to_string(), Some(value))),
)))
}
}

impl<const N: usize> From<[(String, Option<String>); N]> for Attributes {
fn from(value: [(String, Option<String>); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(AttrValue::from(key), value.map(AttrValue::from))
}))))
Attributes(Some(HashMap::from_iter(value)))
}
}

impl<const N: usize> From<[(String, String); N]> for Attributes {
fn from(value: [(String, String); N]) -> Attributes {
Attributes(Some(HashMap::from_iter(value.map(|(key, value)| {
(AttrValue::from(key), Some(AttrValue::from(value)))
}))))
}
}

impl<'a> IntoIterator for &'a Attributes {
type Item = &'a HashMap<AttrValue, Option<AttrValue>>;
type IntoIter = Iter<'a, HashMap<AttrValue, Option<AttrValue>>>;

fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}

impl<'a> IntoIterator for &'a mut Attributes {
type Item = &'a mut HashMap<AttrValue, Option<AttrValue>>;
type IntoIter = IterMut<'a, HashMap<AttrValue, Option<AttrValue>>>;

fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}

impl IntoIterator for Attributes {
type Item = HashMap<AttrValue, Option<AttrValue>>;
type IntoIter = IntoIter<HashMap<AttrValue, Option<AttrValue>>>;

fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
Attributes(Some(HashMap::from_iter(
value.map(|(key, value)| (key, Some(value))),
)))
}
}
Loading

0 comments on commit 99f0c01

Please sign in to comment.