use crate::prelude::*;
use beet_core::prelude::*;
use bevy::ecs::system::SystemParam;
#[derive(Debug, Clone, Deref, Reflect, Component)]
#[reflect(Component)]
#[relationship(relationship_target = Attributes)]
pub struct AttributeOf(pub Entity);
impl AttributeOf {
pub fn new(value: Entity) -> Self { Self(value) }
}
#[derive(Debug, Clone, Deref, Reflect, Component)]
#[reflect(Component)]
#[relationship_target(relationship = AttributeOf,linked_spawn)]
pub struct Attributes(Vec<Entity>);
impl Attributes {
pub fn find<'a>(
&self,
attrs: &'a Query<(Entity, &AttributeKey, Option<&TextNode>)>,
key: &str,
) -> Option<(Entity, Option<&'a TextNode>)> {
self.iter().find_map(|entity| {
let (attr_entity, item_key, value) = attrs.get(entity).ok()?;
if item_key.as_str() == key {
Some((attr_entity, value))
} else {
None
}
})
}
}
#[derive(SystemParam)]
pub struct FindAttribute<'w, 's> {
elements: Query<'w, 's, (Entity, &'static Attributes)>,
attributes: Query<
'w,
's,
(Entity, &'static AttributeKey, Option<&'static TextNode>),
>,
}
impl FindAttribute<'_, '_> {
pub fn all<'a>(
&'a self,
entity: Entity,
) -> Vec<(Entity, &'a AttributeKey, Option<&'a TextNode>)> {
self.elements.get(entity).ok().map_or(vec![], |(_, attrs)| {
attrs
.iter()
.filter_map(|attr| self.attributes.get(attr).ok())
.collect()
})
}
pub fn events<'a>(
&'a self,
entity: Entity,
) -> Vec<(Entity, &'a AttributeKey)> {
self.elements.get(entity).ok().map_or(vec![], |(_, attrs)| {
attrs
.iter()
.filter_map(|attr| self.attributes.get(attr).ok())
.filter(|(_, key, _)| key.is_event())
.map(|(entity, key, _)| (entity, key))
.collect()
})
}
pub fn find(
&self,
entity: Entity,
key: &str,
) -> Option<(Entity, Option<&TextNode>)> {
self.elements
.get(entity)
.ok()
.and_then(|(_, attrs)| attrs.find(&self.attributes, key))
}
pub fn find_value(
&self,
entity: Entity,
key: &str,
) -> Option<(Entity, &TextNode)> {
self.find(entity, key)
.and_then(|(attr_entity, value)| value.map(|v| (attr_entity, v)))
}
pub fn classes(&self, entity: Entity) -> Vec<String> {
self.find(entity, "class").map_or(vec![], |(_, value)| {
value
.map(|text| {
text.as_str().split_whitespace().map(String::from).collect()
})
.unwrap_or_default()
})
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, Deref, DerefMut, Reflect, Component,
)]
#[reflect(Component)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
pub struct AttributeKey(pub String);
impl AttributeKey {
pub fn new(value: impl Into<String>) -> Self { Self(value.into()) }
pub fn is_event(&self) -> bool { self.0.starts_with("on") }
}