use crate::prelude::*;
use beet_core::prelude::*;
pub type RsxDirectives = (SlotChild, SlotTarget);
#[derive(Debug, Default, Clone, PartialEq, Eq, Component, Reflect)]
#[reflect(Component)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
pub enum SlotChild {
#[default]
Default,
Named(String),
}
impl TemplateDirective for SlotChild {
fn try_from_attribute(key: &str, value: Option<&TextNode>) -> Option<Self> {
match (key, value) {
("slot", Some(value)) if value.as_str() == "default" => {
Some(Self::Default)
}
("slot", Some(value)) => Some(Self::Named(value.to_string())),
("slot", None) => Some(Self::Default),
_ => None,
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Component, Reflect)]
#[reflect(Component)]
#[require(FragmentNode)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "tokens", derive(ToTokens))]
pub enum SlotTarget {
#[default]
Default,
Named(String),
}
impl SlotTarget {
pub fn named(name: impl Into<String>) -> Self {
SlotTarget::Named(name.into())
}
pub fn name(&self) -> Option<&str> {
match self {
SlotTarget::Default => None,
SlotTarget::Named(name) => Some(name),
}
}
}
pub fn extract_slot_targets(
mut commands: Commands,
query: Populated<(Entity, &NodeTag), Added<ElementNode>>,
attributes: FindAttribute,
) {
for (node_ent, node_tag) in query.iter() {
if **node_tag != "slot" {
continue;
}
let target = attributes
.find(node_ent, "name")
.map(|(entity, value)| {
commands.entity(entity).despawn();
if let Some(value) = value.as_ref() {
SlotTarget::Named(value.0.clone())
} else {
SlotTarget::Default
}
})
.unwrap_or(SlotTarget::Default);
commands
.entity(node_ent)
.remove::<NodeTag>()
.remove::<ElementNode>()
.insert(target);
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
use bevy::ecs::system::RunSystemOnce;
#[test]
fn default_slot_target() {
let mut app = App::new();
let entity = app
.world_mut()
.spawn((ElementNode::self_closing(), NodeTag("slot".to_string())))
.id();
app.world_mut()
.run_system_once(extract_slot_targets)
.unwrap();
app.world_mut()
.entity(entity)
.get::<SlotTarget>()
.xpect_eq(Some(&SlotTarget::default()));
}
#[test]
fn named_slot_target() {
let mut app = App::new();
let entity = app
.world_mut()
.spawn((
ElementNode::self_closing(),
NodeTag("slot".to_string()),
related!(
Attributes
[(AttributeKey::new("name"), "foo".into_bundle())]
),
))
.id();
app.world_mut()
.run_system_once(extract_slot_targets)
.unwrap();
app.world_mut()
.entity(entity)
.get::<SlotTarget>()
.xpect_eq(Some(&SlotTarget::Named("foo".to_string())));
}
}