dioxus-icons 0.0.1

Lucide icons for Dioxus, one component per icon.
Documentation
use dioxus::core::{
    Attribute, AttributeValue, DynamicNode, Element, Template, TemplateAttribute, TemplateNode,
    VNode,
};

use crate::IconProps;

type AttributeDescription = (&'static str, Option<&'static str>, bool);
const SVG_NAMESPACE: Option<&'static str> = Some("http://www.w3.org/2000/svg");
const EMPTY_CHILDREN: &[TemplateNode] = &[];
const ICON_ATTR_PATHS: &[&[u8]] = &[&[0u8], &[0u8], &[0u8], &[0u8], &[0u8], &[0u8], &[0u8]];
static DEFAULT_SVG_ATTRS: [TemplateAttribute; 10] = svg_attrs("0 0 24 24");

const WIDTH: AttributeDescription = ("width", None, false);
const HEIGHT: AttributeDescription = ("height", None, false);
const STROKE: AttributeDescription = ("stroke", None, false);
const STROKE_WIDTH: AttributeDescription = ("stroke-width", None, false);
const STROKE_LINECAP: AttributeDescription = ("stroke-linecap", None, false);
const STROKE_LINEJOIN: AttributeDescription = ("stroke-linejoin", None, false);
const CLASS: AttributeDescription = ("class", None, false);

#[inline]
pub(crate) const fn icon_template(roots: &'static [TemplateNode]) -> Template {
    Template {
        roots,
        node_paths: &[],
        attr_paths: ICON_ATTR_PATHS,
    }
}

#[inline]
pub(crate) const fn svg_attrs(view_box: &'static str) -> [TemplateAttribute; 10] {
    [
        attr("xmlns", "http://www.w3.org/2000/svg"),
        dynamic_attr(0),
        dynamic_attr(1),
        attr("viewBox", view_box),
        attr("fill", "none"),
        dynamic_attr(2),
        dynamic_attr(3),
        dynamic_attr(4),
        dynamic_attr(5),
        dynamic_attr(6),
    ]
}

#[inline]
pub(crate) const fn svg(children: &'static [TemplateNode]) -> TemplateNode {
    svg_with_attrs(&DEFAULT_SVG_ATTRS, children)
}

#[inline]
pub(crate) const fn svg_with_attrs(
    attrs: &'static [TemplateAttribute],
    children: &'static [TemplateNode],
) -> TemplateNode {
    TemplateNode::Element {
        tag: "svg",
        namespace: SVG_NAMESPACE,
        attrs,
        children,
    }
}

#[inline]
pub(crate) const fn path(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("path", attrs)
}

#[inline]
pub(crate) const fn circle(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("circle", attrs)
}

#[inline]
pub(crate) const fn rect(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("rect", attrs)
}

#[inline]
pub(crate) const fn line(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("line", attrs)
}

#[inline]
pub(crate) const fn polyline(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("polyline", attrs)
}

#[inline]
pub(crate) const fn polygon(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("polygon", attrs)
}

#[inline]
pub(crate) const fn ellipse(attrs: &'static [TemplateAttribute]) -> TemplateNode {
    child("ellipse", attrs)
}

#[inline]
const fn child(tag: &'static str, attrs: &'static [TemplateAttribute]) -> TemplateNode {
    TemplateNode::Element {
        tag,
        namespace: SVG_NAMESPACE,
        attrs,
        children: EMPTY_CHILDREN,
    }
}

#[inline]
pub(crate) const fn attr(name: &'static str, value: &'static str) -> TemplateAttribute {
    TemplateAttribute::Static {
        name,
        value,
        namespace: None,
    }
}

#[inline]
const fn dynamic_attr(id: usize) -> TemplateAttribute {
    TemplateAttribute::Dynamic { id }
}

#[inline]
fn icon_attr(
    (name, namespace, volatile): AttributeDescription,
    value: AttributeValue,
) -> Attribute {
    Attribute {
        name,
        value,
        namespace,
        volatile,
    }
}

#[inline]
pub(crate) fn icon_element(template: Template, props: IconProps) -> Element {
    let IconProps {
        size,
        color,
        stroke_width,
        stroke_linecap,
        stroke_linejoin,
        class,
    } = props;

    let class_value = if class.is_empty() {
        AttributeValue::None
    } else {
        AttributeValue::Text(class.into_owned())
    };
    let dynamic_attributes: [Box<[Attribute]>; 7] = [
        Box::new([icon_attr(WIDTH, AttributeValue::Text(size.to_string()))]),
        Box::new([icon_attr(HEIGHT, AttributeValue::Text(size.to_string()))]),
        Box::new([icon_attr(STROKE, AttributeValue::Text(color.into_owned()))]),
        Box::new([icon_attr(
            STROKE_WIDTH,
            AttributeValue::Text(stroke_width.to_string()),
        )]),
        Box::new([icon_attr(
            STROKE_LINECAP,
            AttributeValue::Text(stroke_linecap.into_owned()),
        )]),
        Box::new([icon_attr(
            STROKE_LINEJOIN,
            AttributeValue::Text(stroke_linejoin.into_owned()),
        )]),
        Box::new([icon_attr(CLASS, class_value)]),
    ];
    let dynamic_nodes: Box<[DynamicNode]> = Box::new([]);
    Ok(VNode::new(
        None,
        template,
        dynamic_nodes,
        Box::new(dynamic_attributes),
    ))
}