use crate::hook::{TagInputConfig, TagInputGroupConfig, use_tag_input_grouped, use_tag_input_with};
use crate::tag::TagLike;
use dioxus::prelude::*;
use std::cmp::Ordering;
#[derive(Props, Clone, PartialEq)]
#[allow(clippy::type_complexity, unpredictable_function_pointer_comparisons)]
pub struct RootProps<T: TagLike + 'static> {
pub available_tags: Vec<T>,
#[props(default)]
pub initial_selected: Vec<T>,
#[props(default)]
pub value: Option<Signal<Vec<T>>>,
#[props(default)]
pub query: Option<Signal<String>>,
#[props(default)]
pub max_tags: Option<usize>,
#[props(default)]
pub disabled: bool,
#[props(default)]
pub readonly: bool,
#[props(default)]
pub allow_duplicates: bool,
#[props(default)]
pub enforce_allow_list: bool,
#[props(default)]
pub select_mode: bool,
#[props(default)]
pub deny_list: Option<Vec<String>>,
#[props(default)]
pub paste_delimiters: Option<Vec<char>>,
#[props(default)]
pub delimiters: Option<Vec<char>>,
#[props(default)]
pub min_tags: Option<usize>,
#[props(default)]
pub max_tag_length: Option<usize>,
#[props(default)]
pub max_visible_tags: Option<usize>,
#[props(default)]
pub filter: Option<fn(&T, &str) -> bool>,
#[props(default)]
pub sort_selected: Option<fn(&T, &T) -> Ordering>,
#[props(default)]
pub validate: Option<Callback<T, Result<(), String>>>,
#[props(default)]
pub on_create: Option<Callback<String, Option<T>>>,
#[props(default)]
pub on_add: Option<EventHandler<T>>,
#[props(default)]
pub on_remove: Option<EventHandler<T>>,
#[props(default)]
pub on_duplicate: Option<EventHandler<T>>,
#[props(default)]
pub on_paste: Option<Callback<String, Vec<T>>>,
#[props(default)]
pub on_edit: Option<Callback<(T, String), Option<T>>>,
#[props(default)]
pub on_reorder: Option<EventHandler<(usize, usize)>>,
#[props(default)]
pub on_query_change: Option<EventHandler<String>>,
#[props(default)]
pub on_commit: Option<EventHandler<String>>,
#[props(default)]
pub sort_items: Option<fn(&T, &T) -> Ordering>,
#[props(default)]
pub sort_groups: Option<fn(&str, &str) -> Ordering>,
#[props(default)]
pub max_items_per_group: Option<usize>,
#[props(extends = GlobalAttributes)]
pub attributes: Vec<Attribute>,
pub children: Element,
}
pub fn Root<T: TagLike>(props: RootProps<T>) -> Element {
let has_grouping = props.sort_items.is_some()
|| props.sort_groups.is_some()
|| props.max_items_per_group.is_some();
let mut state = if has_grouping {
use_tag_input_grouped(TagInputGroupConfig {
available_tags: props.available_tags.clone(),
initial_selected: props.initial_selected.clone(),
filter: props.filter,
sort_items: props.sort_items,
sort_groups: props.sort_groups,
max_items_per_group: props.max_items_per_group,
value: props.value,
query: props.query,
})
} else {
use_tag_input_with(TagInputConfig {
available_tags: props.available_tags.clone(),
initial_selected: props.initial_selected.clone(),
value: props.value,
query: props.query,
})
};
let max_tags = props.max_tags;
let disabled = props.disabled;
let readonly = props.readonly;
let allow_duplicates = props.allow_duplicates;
let enforce_allow_list = props.enforce_allow_list;
let select_mode = props.select_mode;
let deny_list = props.deny_list.clone();
let paste_delimiters = props.paste_delimiters.clone();
let delimiters = props.delimiters.clone();
let min_tags = props.min_tags;
let max_tag_length = props.max_tag_length;
let max_visible_tags = props.max_visible_tags;
let filter = props.filter;
let sort_selected = props.sort_selected;
let validate = props.validate;
let on_create = props.on_create;
let on_paste = props.on_paste;
let on_edit = props.on_edit;
let on_add = props.on_add;
let on_remove = props.on_remove;
let on_duplicate = props.on_duplicate;
let on_reorder = props.on_reorder;
let on_query_change = props.on_query_change;
let on_commit = props.on_commit;
use_effect(move || {
state.max_tags.set(max_tags);
state.is_disabled.set(disabled);
state.is_readonly.set(readonly);
state.allow_duplicates.set(allow_duplicates);
state.enforce_allow_list.set(enforce_allow_list);
state.select_mode.set(select_mode);
state.deny_list.set(deny_list.clone());
state.paste_delimiters.set(paste_delimiters.clone());
state.delimiters.set(delimiters.clone());
state.min_tags.set(min_tags);
state.max_tag_length.set(max_tag_length);
state.max_visible_tags.set(max_visible_tags);
state.filter.set(filter);
state.sort_selected.set(sort_selected);
if let Some(cb) = validate {
state.validate.set(Some(cb));
} else {
state.validate.set(None);
}
if let Some(cb) = on_create {
state.on_create.set(Some(cb));
} else {
state.on_create.set(None);
}
if let Some(cb) = on_paste {
state.on_paste.set(Some(cb));
} else {
state.on_paste.set(None);
}
if let Some(cb) = on_edit {
state.on_edit.set(Some(cb));
} else {
state.on_edit.set(None);
}
if let Some(handler) = on_add {
state.on_add.set(Some(Callback::new(move |tag: T| {
handler.call(tag);
})));
} else {
state.on_add.set(None);
}
if let Some(handler) = on_remove {
state.on_remove.set(Some(Callback::new(move |tag: T| {
handler.call(tag);
})));
} else {
state.on_remove.set(None);
}
if let Some(handler) = on_duplicate {
state.on_duplicate.set(Some(Callback::new(move |tag: T| {
handler.call(tag);
})));
} else {
state.on_duplicate.set(None);
}
if let Some(handler) = on_reorder {
state
.on_reorder
.set(Some(Callback::new(move |pair: (usize, usize)| {
handler.call(pair);
})));
} else {
state.on_reorder.set(None);
}
state.on_query_change.set(on_query_change);
state.on_commit.set(on_commit);
});
use_context_provider(|| state);
rsx! {
div {
"data-slot": "root",
role: "group",
"data-disabled": *state.is_disabled.read(),
"data-readonly": *state.is_readonly.read(),
"data-state": if state.validation_error.read().is_some() { "invalid" } else { "valid" },
"data-at-limit": *state.is_at_limit.read(),
"data-below-minimum": *state.is_below_minimum.read(),
..props.attributes,
{props.children}
}
}
}