use dioxus::prelude::*;
use crate::core::use_dnd;
#[component]
pub fn LiveRegion<T: Clone + PartialEq + 'static>(
#[props(default)]
phantom: std::marker::PhantomData<T>,
) -> Element {
let _ = phantom;
let dnd = use_dnd::<T>();
let text = dnd.announcement();
rsx! {
div {
aria_live: "polite",
aria_atomic: "true",
role: "status",
style: "position: absolute; width: 1px; height: 1px; padding: 0; \
margin: -1px; overflow: hidden; clip: rect(0 0 0 0); \
white-space: nowrap; border: 0;",
"{text}"
}
}
}
#[component]
pub fn ReorderButtons(
index: usize,
total: usize,
#[props(default)]
label: Option<String>,
on_sort: EventHandler<crate::sortable::SortEvent>,
#[props(extends = span, extends = GlobalAttributes)] attributes: Vec<Attribute>,
) -> Element {
let name = label.unwrap_or_else(|| format!("item {}", index + 1));
let up_label = format!("Move {name} up");
let down_label = format!("Move {name} down");
rsx! {
span {
onpointerdown: move |evt: PointerEvent| evt.stop_propagation(),
..attributes,
button {
r#type: "button",
"data-reorder": "up",
aria_label: "{up_label}",
disabled: index == 0,
onclick: move |evt| {
evt.stop_propagation();
if index > 0 {
on_sort.call(crate::sortable::SortEvent { from: index, to: index - 1 });
}
},
"↑"
}
button {
r#type: "button",
"data-reorder": "down",
aria_label: "{down_label}",
disabled: index + 1 >= total,
onclick: move |evt| {
evt.stop_propagation();
if index + 1 < total {
on_sort.call(crate::sortable::SortEvent { from: index, to: index + 1 });
}
},
"↓"
}
}
}
}
pub(crate) const REDUCED_MOTION_CSS: &str = "@media (prefers-reduced-motion: reduce) { \
[data-dnd-motion] { transition-duration: 0.01ms !important; } }";
#[derive(Clone, Copy)]
pub(crate) struct MotionCssProvided;
pub(crate) fn use_reduced_motion_css() -> Option<Element> {
let first = use_hook(|| {
if try_consume_context::<MotionCssProvided>().is_some() {
false
} else {
provide_context(MotionCssProvided);
true
}
});
first.then(|| {
rsx! {
style { {REDUCED_MOTION_CSS} }
}
})
}