use web_sys::Element;
use crate::dom::{state, query};
use crate::integration::aria;
#[derive(Debug)]
pub struct SelectionConfig {
pub item_selector: &'static str,
pub value_attr: &'static str,
pub aria_selected: bool,
pub aria_current: bool,
}
pub fn activate_by_value(root: &Element, value: &str, config: &SelectionConfig) {
for item in query::all(root, config.item_selector) {
let v = item.get_attribute(config.value_attr).unwrap_or_default();
let is_active = v == value;
state::remove(&item, "active");
state::remove(&item, "inactive");
if is_active {
state::add(&item, "active");
if config.aria_selected { aria::set_selected(&item, true); }
if config.aria_current { let _ = item.set_attribute("aria-current", "page"); }
} else {
state::add(&item, "inactive");
if config.aria_selected { aria::set_selected(&item, false); }
if config.aria_current { let _ = item.remove_attribute("aria-current"); }
}
}
}
pub fn activate(root: &Element, target: &Element, config: &SelectionConfig) {
for item in query::all(root, config.item_selector) {
state::remove(&item, "active");
state::remove(&item, "inactive");
state::add(&item, "inactive");
if config.aria_selected { aria::set_selected(&item, false); }
if config.aria_current { let _ = item.remove_attribute("aria-current"); }
}
state::remove(target, "inactive");
state::add(target, "active");
if config.aria_selected { aria::set_selected(target, true); }
if config.aria_current { let _ = target.set_attribute("aria-current", "page"); }
}
pub fn active_value(root: &Element, config: &SelectionConfig) -> Option<String> {
query::all(root, config.item_selector)
.into_iter()
.find(|el| state::has(el, "active"))
.and_then(|el| el.get_attribute(config.value_attr))
}
pub fn init_state(root: &Element, config: &SelectionConfig) {
let items = query::all(root, config.item_selector);
let has_active = items.iter().any(|el| state::has(el, "active"));
if !has_active {
if let Some(first) = items.first() {
activate(root, first, config);
}
} else {
for item in &items {
if !state::has(item, "active") {
state::remove(item, "active");
state::add(item, "inactive");
}
}
}
}
#[cfg(test)]
mod tests {
use super::SelectionConfig;
#[test]
fn selection_config_tabs() {
let config = SelectionConfig {
item_selector: "[data-rs-tabs-trigger]",
value_attr: "data-rs-value",
aria_selected: true,
aria_current: false,
};
assert_eq!(config.item_selector, "[data-rs-tabs-trigger]");
assert!(config.aria_selected);
assert!(!config.aria_current);
}
#[test]
fn selection_config_nav() {
let config = SelectionConfig {
item_selector: "[data-rs-nav-item]",
value_attr: "data-rs-value",
aria_selected: false,
aria_current: true,
};
assert!(!config.aria_selected);
assert!(config.aria_current);
}
}