fc_dioxus/components/
badge.rs1use crate::{
3 core::{
4 assets,
5 attrs::{availability_attributes, component_attributes},
6 },
7 prelude::*,
8 theme::use_stylesheets,
9};
10const BEM: Bem = Bem::new("fc-badge");
11const TAG: Bem = Bem::new("fc-tag");
12const KBD: Bem = Bem::new("fc-kbd");
13fc_modifier! {
14 pub enum BadgeTone for BEM {
16 Neutral => None,
18 Accent => "accent",
20 Info => "info",
22 Success => "success",
24 Warning => "warning",
26 Danger => "danger",
28 Solid => "solid",
30 }
31}
32fc_modifier! { enum BadgeFill for BEM { Filled => None, Outline => "outline" } }
33fc_modifier! { enum BadgeShape for BEM { Pill => None, Square => "square" } }
34fc_modifier! { enum BadgeNumber for BEM { Text => None, Count => "count" } }
35#[component]
37pub fn Badge(
38 #[props(default)] tone: BadgeTone,
39 #[props(default)] solid: bool,
40 #[props(default)] outline: bool,
41 #[props(default)] square: bool,
42 #[props(default)] dot: bool,
43 #[props(default)] count: bool,
44 #[props(default)] clipped: bool,
45 #[props(default)] class: Option<String>,
46 #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
47 children: Element,
48) -> Element {
49 let classes = ClassList::new(BEM.block())
50 .with_modifier(BEM, tone)
51 .with_modifier(
52 BEM,
53 if solid {
54 BadgeTone::Solid
55 } else {
56 BadgeTone::Neutral
57 },
58 )
59 .with_modifier(
60 BEM,
61 if outline {
62 BadgeFill::Outline
63 } else {
64 BadgeFill::Filled
65 },
66 )
67 .with_modifier(
68 BEM,
69 if square {
70 BadgeShape::Square
71 } else {
72 BadgeShape::Pill
73 },
74 )
75 .with_modifier(
76 BEM,
77 if count {
78 BadgeNumber::Count
79 } else {
80 BadgeNumber::Text
81 },
82 )
83 .extend(class.as_deref());
84 let attributes = component_attributes(attributes, classes, &["tabindex"]);
85 rsx! {
86 if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_BADGE_CSS } }
87 span { ..attributes,
88 if dot { span { class: BEM.element("dot"), aria_hidden: "true" } }
89 if clipped { span { class: BEM.element("label"), {children} } } else { {children} }
90 }
91 }
92}
93#[derive(Clone, PartialEq)]
95pub struct TagRemove {
96 pub label: AccessibleName,
98 pub onremove: EventHandler<()>,
100}
101#[component]
103pub fn Tag(
104 #[props(default)] pressed: bool,
105 #[props(default)] onchange: Option<EventHandler<bool>>,
106 #[props(default)] remove: Option<TagRemove>,
107 #[props(default)] availability: Availability,
108 #[props(default)] class: Option<String>,
109 #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
110 children: Element,
111) -> Element {
112 let mut attributes = component_attributes(
113 attributes,
114 ClassList::new(TAG.block()).extend(class.as_deref()),
115 &[
116 "type",
117 "role",
118 "aria-pressed",
119 "aria-disabled",
120 "disabled",
121 "onclick",
122 ],
123 );
124 let state = availability_attributes(&availability);
125 let blocked = availability != Availability::Enabled;
126 if remove.is_none() {
127 attributes.extend(state.clone());
128 attributes.push(Attribute::new(
129 "aria-pressed",
130 pressed.to_string(),
131 None,
132 false,
133 ));
134 }
135 rsx! {
136 if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_BADGE_CSS } }
137 if let Some(remove) = remove {
138 span { ..attributes,
139 span { class: TAG.element("label"), {children} }
140 button { r#type: "button", class: TAG.element("remove"), aria_label: remove.label.to_string(),
141 onclick: move |event| { if blocked { event.prevent_default(); } else { remove.onremove.call(()); } },
142 ..state, "×"
143 }
144 }
145 } else {
146 button { r#type: "button",
147 onclick: move |event| { if blocked { event.prevent_default(); event.stop_propagation(); } else if let Some(onchange) = onchange { onchange.call(!pressed); } },
148 ..attributes, {children}
149 }
150 }
151 }
152}
153#[component]
155pub fn Kbd(
156 #[props(default)] class: Option<String>,
157 #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
158 children: Element,
159) -> Element {
160 let attributes = component_attributes(
161 attributes,
162 ClassList::new(KBD.block()).extend(class.as_deref()),
163 &[],
164 );
165 rsx! {
166 if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_BADGE_CSS } }
167 kbd { ..attributes, {children} }
168 }
169}