use web_sys::KeyboardEvent;
use yew::prelude::*;
use super::focus::{focusable_elements, focused_position, next_focus_index};
#[derive(Properties, Clone, PartialEq, Debug)]
pub struct NavTabsProps {
#[prop_or_default]
pub classes: Classes,
#[prop_or(AttrValue::Static("tablist"))]
pub role: AttrValue,
#[prop_or_default]
pub id: Option<AttrValue>,
#[prop_or_default]
pub full_width: bool,
#[prop_or_default]
pub vertical: bool,
pub children: Children
}
#[function_component]
pub fn NavTabs(props: &NavTabsProps) -> Html {
let mut classes = props.classes.clone();
classes.push("nav-tabs");
if props.full_width {
classes.push("nav-tabs-fill");
}
let list_ref = use_node_ref();
let vertical = props.vertical;
let onkeydown = {
let list_ref = list_ref.clone();
Callback::from(move |event: KeyboardEvent| {
let key = event.key();
let tabs = focusable_elements(&list_ref, "[role='tab']:not([disabled])");
if tabs.is_empty() {
return;
}
let position = focused_position(&tabs);
if let Some(tab) =
next_focus_index(&key, position, tabs.len(), vertical).and_then(|i| tabs.get(i))
{
event.prevent_default();
let _ = tab.focus();
}
})
};
let aria_orientation = props.vertical.then_some("vertical");
html! {
<ul
ref={list_ref}
class={classes}
id={props.id.clone()}
role={props.role.clone()}
aria-orientation={aria_orientation}
onkeydown={onkeydown}
>
{ for props.children.iter() }
</ul>
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nav_tabs_props_default() {
let props = NavTabsProps {
classes: Classes::default(),
role: AttrValue::Static("tablist"),
id: None,
full_width: false,
vertical: false,
children: Children::new(vec![])
};
assert_eq!(props.role, "tablist");
assert!(!props.full_width);
}
#[test]
fn nav_tabs_full_width() {
let props = NavTabsProps {
classes: Classes::default(),
role: AttrValue::Static("tablist"),
id: Some(AttrValue::Static("main-tabs")),
full_width: true,
vertical: false,
children: Children::new(vec![])
};
assert!(props.full_width);
assert_eq!(props.id.as_deref(), Some("main-tabs"));
}
}