use autumn_web::Markup;
use super::{Behavior, button, marker};
use crate::markup::{Attributes, common};
#[derive(Debug, Clone, PartialEq, Eq)]
#[must_use]
pub struct Toggle {
target: String,
class: Option<String>,
extra: Attributes,
}
impl Toggle {
pub fn target(selector: impl Into<String>) -> Self {
Self {
target: selector.into(),
class: None,
extra: Vec::new(),
}
}
pub fn class(mut self, class: impl Into<String>) -> Self {
self.class = Some(class.into());
self
}
#[must_use]
pub fn attributes(&self) -> Attributes {
let mut attributes = vec![
marker(Behavior::Toggle),
("data-vanilla-toggle", self.target.clone()),
];
if let Some(class) = &self.class {
attributes.push(("data-vanilla-toggle-class", class.clone()));
}
attributes.extend(self.extra.iter().cloned());
attributes
}
#[must_use]
pub fn button(&self, content: Markup) -> Markup {
let mut attributes = self.attributes();
if let Some(id) = plain_id(&self.target) {
attributes.push(("aria-controls", id.to_owned()));
}
button(attributes, content)
}
}
common!(Toggle);
pub(crate) fn plain_id(selector: &str) -> Option<&str> {
let id = selector.strip_prefix('#')?;
let mut chars = id.chars();
let first = chars.next()?;
let valid = first.is_ascii_alphabetic()
&& chars.all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_');
valid.then_some(id)
}
#[cfg(test)]
mod tests {
use super::plain_id;
#[test]
fn plain_id_accepts_only_simple_ids() {
assert_eq!(plain_id("#menu"), Some("menu"));
assert_eq!(plain_id("#main-menu_2"), Some("main-menu_2"));
assert_eq!(plain_id("#"), None);
assert_eq!(plain_id("#1a"), None);
assert_eq!(plain_id("#a b"), None);
assert_eq!(plain_id("#a.b"), None);
assert_eq!(plain_id(".menu"), None);
assert_eq!(plain_id("menu"), None);
}
}