use std::marker::PhantomData;
use crate::{Attribute, DynamicValues, HasAttributes, IntoAttributeValue};
use dioxus_core_template::TemplateRawTree;
use super::{ElementBuilder, View, ViewTemplate};
pub trait AttributeDescriptor {
const NAME: &'static str;
const NAMESPACE: Option<&'static str> = None;
const VOLATILE: bool = false;
}
pub struct StaticAttributeBuilder<Descriptor, Value = Descriptor>(PhantomData<(Descriptor, Value)>);
#[inline]
pub const fn static_attribute<A: AttributeDescriptor + StaticAttributeValue>()
-> StaticAttributeBuilder<A> {
StaticAttributeBuilder(PhantomData)
}
impl<Descriptor, Value> ViewTemplate for StaticAttributeBuilder<Descriptor, Value>
where
Descriptor: AttributeDescriptor,
Value: StaticAttributeValue,
{
const TEMPLATE_TREE: &'static TemplateRawTree = &TemplateRawTree::StaticAttr {
name: Descriptor::NAME,
value: Value::VALUE,
namespace: Descriptor::NAMESPACE,
};
}
impl<Descriptor, Value> View for StaticAttributeBuilder<Descriptor, Value>
where
Descriptor: AttributeDescriptor,
Value: StaticAttributeValue,
{
}
pub trait StaticAttributeValue {
const VALUE: &'static str;
}
pub struct StaticAttributeValueBuilder<V>(#[doc(hidden)] pub PhantomData<V>);
#[doc(hidden)]
pub struct StaticAttributeValueBuilderMarker;
pub trait IntoAttributeBuilderValue<Target, Descriptor, Marker>
where
Target: AttributeBuilderTarget,
Descriptor: AttributeDescriptor,
{
type Output;
fn append_to(self, target: Target) -> Self::Output;
}
pub struct DynamicAttributesBuilder {
attrs: Box<[Attribute]>,
}
#[inline]
#[doc(hidden)]
pub fn dynamic_attributes_builder(attrs: Box<[Attribute]>) -> DynamicAttributesBuilder {
DynamicAttributesBuilder { attrs }
}
impl ViewTemplate for DynamicAttributesBuilder {
const TEMPLATE_TREE: &'static TemplateRawTree = &TemplateRawTree::DynamicAttr;
}
impl View for DynamicAttributesBuilder {
fn push(self, dynamic: &mut DynamicValues) {
dynamic.push_attrs(self.attrs);
}
}
pub trait AttributeBuilderTarget: Sized {
type Output;
fn append_attribute(self, attr: Attribute) -> Self::Output;
}
impl<Target> AttributeBuilderTarget for Target
where
Target: HasAttributes,
{
type Output = Self;
#[inline]
fn append_attribute(self, attr: Attribute) -> Self::Output {
self.push_attribute(attr.name, attr.namespace, attr.value, attr.volatile)
}
}
impl<Tag, Attributes, Children> AttributeBuilderTarget
for ElementBuilder<Tag, Attributes, Children>
{
type Output = ElementBuilder<Tag, (Attributes, DynamicAttributesBuilder), Children>;
#[inline]
fn append_attribute(self, attr: Attribute) -> Self::Output {
self.attribute(dynamic_attributes_builder(Box::new([attr])))
}
}
impl AttributeBuilderTarget for Vec<Attribute> {
type Output = Self;
#[inline]
fn append_attribute(mut self, attr: Attribute) -> Self::Output {
self.push(attr);
self
}
}
impl<Target, Descriptor, Marker, Value> IntoAttributeBuilderValue<Target, Descriptor, Marker>
for Value
where
Target: AttributeBuilderTarget,
Descriptor: AttributeDescriptor,
Value: IntoAttributeValue<Marker>,
{
type Output = <Target as AttributeBuilderTarget>::Output;
#[inline]
fn append_to(self, target: Target) -> Self::Output {
AttributeBuilderTarget::append_attribute(
target,
Attribute::new(
Descriptor::NAME,
self,
Descriptor::NAMESPACE,
Descriptor::VOLATILE,
),
)
}
}
impl<Tag, Attributes, Children, Descriptor, Value>
IntoAttributeBuilderValue<
ElementBuilder<Tag, Attributes, Children>,
Descriptor,
StaticAttributeValueBuilderMarker,
> for StaticAttributeValueBuilder<Value>
where
Descriptor: AttributeDescriptor,
Value: StaticAttributeValue,
{
type Output =
ElementBuilder<Tag, (Attributes, StaticAttributeBuilder<Descriptor, Value>), Children>;
#[inline]
fn append_to(self, target: ElementBuilder<Tag, Attributes, Children>) -> Self::Output {
target.attribute(StaticAttributeBuilder(PhantomData))
}
}