Skip to main content

dioxus_element_plug/components/
link.rs

1use dioxus::prelude::*;
2
3/// Link type variants
4#[derive(Clone, PartialEq)]
5pub enum LinkType {
6    Default,
7    Primary,
8    Success,
9    Warning,
10    Info,
11    Danger,
12}
13
14impl LinkType {
15    pub fn as_class(&self) -> &'static str {
16        match self {
17            LinkType::Default => "",
18            LinkType::Primary => "el-link--primary",
19            LinkType::Success => "el-link--success",
20            LinkType::Warning => "el-link--warning",
21            LinkType::Info => "el-link--info",
22            LinkType::Danger => "el-link--danger",
23        }
24    }
25}
26
27/// Link underline behavior
28#[derive(Clone, PartialEq)]
29pub enum LinkUnderline {
30    Always,
31    Never,
32    Hover,
33}
34
35/// Link props
36#[derive(Props, Clone, PartialEq)]
37pub struct LinkProps {
38    /// Link content
39    #[props(default)]
40    pub children: Element,
41
42    /// Link type
43    #[props(default = LinkType::Default)]
44    pub link_type: LinkType,
45
46    /// Whether the link is disabled
47    #[props(default = false)]
48    pub disabled: bool,
49
50    /// Whether to show underline
51    #[props(default = LinkUnderline::Hover)]
52    pub underline: LinkUnderline,
53
54    /// Hyperlink href
55    #[props(default)]
56    pub href: Option<String>,
57
58    /// Hyperlink target
59    #[props(default = "_self".to_string())]
60    pub target: String,
61
62    /// Icon CSS class
63    #[props(default)]
64    pub icon: Option<String>,
65
66    /// Click event handler
67    #[props(default)]
68    pub on_click: Option<EventHandler<MouseEvent>>,
69
70    /// Additional CSS classes
71    #[props(default)]
72    pub class: Option<String>,
73
74    /// Inline styles
75    #[props(default)]
76    pub style: Option<String>,
77}
78
79/// Link component for text hyperlinks
80///
81/// ## Example
82///
83/// ```rust,ignore
84/// rsx! {
85///     Link { link_type: LinkType::Primary, href: Some("https://example.com".to_string()), "Visit" }
86/// }
87/// ```
88#[component]
89pub fn Link(props: LinkProps) -> Element {
90    let mut class_names = vec!["el-link".to_string()];
91
92    let type_class = props.link_type.as_class();
93    if !type_class.is_empty() {
94        class_names.push(type_class.to_string());
95    }
96
97    if props.disabled {
98        class_names.push("is-disabled".to_string());
99    }
100
101    match props.underline {
102        LinkUnderline::Always => class_names.push("is-underline".to_string()),
103        LinkUnderline::Never => class_names.push("is-never-underline".to_string()),
104        LinkUnderline::Hover => {}
105    }
106
107    if let Some(ref custom_class) = props.class {
108        class_names.push(custom_class.clone());
109    }
110
111    let class_string = class_names.join(" ");
112    let style_string = props.style.clone().unwrap_or_default();
113    let href = props.href.clone().unwrap_or_default();
114
115    rsx! {
116        a {
117            class: "{class_string}",
118            style: "{style_string}",
119            href: if props.disabled { "" } else { "{href}" },
120            target: "{props.target}",
121            onclick: move |event| {
122                if props.disabled {
123                    return;
124                }
125                if let Some(handler) = props.on_click {
126                    handler.call(event);
127                }
128            },
129            if let Some(ref icon) = props.icon {
130                i { class: "{icon} el-link__icon" }
131            }
132            {props.children}
133        }
134    }
135}