based/src/ui/primitives/div.rs
2025-01-15 21:31:12 +01:00

126 lines
2.8 KiB
Rust

use std::collections::HashMap;
use maud::{Markup, PreEscaped, Render, html};
use crate::ui::{AttrExtendable, UIWidget, htmx::HTMXAttributes};
#[allow(non_snake_case)]
/// `<div>` element
///
/// Useful for grouping values together
#[must_use]
pub fn Div() -> DivWidget {
DivWidget(Vec::new(), false, HashMap::new())
}
pub struct DivWidget(Vec<Box<dyn UIWidget>>, bool, HashMap<String, String>);
impl AttrExtendable for DivWidget {
fn add_attr(mut self, key: &str, val: &str) -> Self {
self.2.insert(key.to_string(), val.replace('\'', "\\'"));
self
}
fn id(self, id: &str) -> Self {
self.add_attr("id", id)
}
}
impl DivWidget {
/// Add an element to the `<div>`
#[must_use]
pub fn push<T: UIWidget + 'static>(mut self, element: T) -> Self {
self.0.push(Box::new(element));
self
}
/// Add an optional element to the `<div>`
///
/// # Example
///
/// ```ignore
/// use based::ui::basic::*;
///
/// let div = Div().push(Some("hello"), |value| Text(value));
/// ```
#[must_use]
pub fn push_some<T: UIWidget + 'static, X, U: Fn(&X) -> T>(
mut self,
option: Option<&X>,
then: U,
) -> Self {
if let Some(val) = option {
self.0.push(Box::new(then(val)));
}
self
}
/// Extract the `<div>`s innerHTML
///
/// This will render `<content>` instead of `<div> <content> </div>`
#[must_use]
pub const fn vanish(mut self) -> Self {
self.1 = true;
self
}
}
impl Render for DivWidget {
fn render(&self) -> Markup {
self.render_with_class("")
}
}
impl DivWidget {
pub fn extended_class_(&self) -> Vec<String> {
let mut c = self.base_class();
for e in &self.0 {
c.extend_from_slice(&e.extended_class());
}
c
}
}
impl UIWidget for DivWidget {
fn can_inherit(&self) -> bool {
false
}
fn base_class(&self) -> Vec<String> {
vec![]
}
fn extended_class(&self) -> Vec<String> {
if self.1 {
self.extended_class_()
} else {
vec![]
}
}
fn render_with_class(&self, _: &str) -> Markup {
let inner = html! {
@for e in &self.0 {
(e.as_ref())
}
};
if self.1 {
inner
} else {
let attrs = self
.2
.iter()
.map(|(k, v)| format!("{k}='{v}'"))
.collect::<Vec<_>>()
.join(" ");
PreEscaped(format!(
"<div class='{}' {attrs}> {} </a>",
self.extended_class_().join(" "),
inner.0
))
}
}
}
impl HTMXAttributes for DivWidget {}