mod spacing;
use std::rc::Rc;
use yew::{
classes, function_component, html, AttrValue, ChildrenWithProps, Classes, Html, Properties,
};
use crate::avatar::{Avatar, Props as AvatarProps};
use crate::styles::shape_variant::ShapeVariant;
pub use spacing::Spacing;
pub const DEFAULT_MAX: i32 = 5;
const AVATAR_CLS: &str = "ZuAvatarGroup-avatar";
#[derive(Debug, Clone, PartialEq, Properties)]
pub struct Props {
#[prop_or_default]
pub children: ChildrenWithProps<Avatar>,
#[prop_or_default]
pub classes: Classes,
#[prop_or(AttrValue::from("div"))]
pub component: AttrValue,
#[prop_or(DEFAULT_MAX)]
pub max: i32,
#[prop_or_default]
pub spacing: Spacing,
#[prop_or(-1)]
pub total: i32,
#[prop_or_default]
pub variant: ShapeVariant,
}
#[function_component(AvatarGroup)]
pub fn avatar_group(props: &Props) -> Html {
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
let children_len = props.children.len() as i32;
let total_avatars = if props.total <= 0 {
children_len
} else {
props.total
};
let mut clamped_max = props.max.max(2);
if total_avatars == clamped_max {
clamped_max += 1;
}
clamped_max = clamped_max.min(total_avatars + 1);
let max_avatars = children_len.min(clamped_max - 1);
let extra_avatars = (total_avatars - clamped_max)
.max(total_avatars - max_avatars)
.max(0);
let margin_left = props.spacing.space();
let root_cls = classes!("ZuAvatarGroup-root", props.classes.clone());
let avatar_style = margin_left.map_or_else(String::new, |margin_left| {
format!("margin-left: {margin_left}px;")
});
#[allow(clippy::cast_sign_loss)]
let max_avatars = max_avatars as usize;
let avatar_style: AttrValue = avatar_style.into();
let mut children: Vec<_> = props
.children
.iter()
.map(|mut item| {
let props = Rc::<AvatarProps>::make_mut(&mut item.props);
props.classes.push(AVATAR_CLS);
if props.style.is_empty() {
props.style = avatar_style.clone();
} else {
props.style = format!("{}; {avatar_style}", props.style).into();
}
item
})
.collect();
children.truncate(max_avatars);
children.reverse();
let children = ChildrenWithProps::new(children);
html! {
<@{props.component.to_string()} class={root_cls}>
if extra_avatars > 0 {
<Avatar classes={AVATAR_CLS} style={avatar_style.clone()}>
{"+"}{extra_avatars}
</Avatar>
}
{ for children }
</@>
}
}