use dioxus::prelude::*;
use dioxus_icons::lucide::{ChevronLeft, ChevronRight, Ellipsis};
#[css_module("/src/components/pagination/style.css")]
struct Styles;
#[derive(Copy, Clone, PartialEq, Default)]
#[non_exhaustive]
pub enum PaginationLinkSize {
#[default]
Icon,
Default,
}
impl PaginationLinkSize {
pub fn class(&self) -> &'static str {
match self {
PaginationLinkSize::Icon => "icon",
PaginationLinkSize::Default => "default",
}
}
}
#[derive(Copy, Clone, PartialEq)]
#[non_exhaustive]
pub enum PaginationLinkKind {
Previous,
Next,
}
impl PaginationLinkKind {
pub fn attr(&self) -> &'static str {
match self {
PaginationLinkKind::Previous => "previous",
PaginationLinkKind::Next => "next",
}
}
}
#[component]
pub fn Pagination(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
nav {
class: Styles::dx_pagination,
"data-slot": "pagination",
role: "navigation",
aria_label: "pagination",
..attributes,
{children}
}
}
}
#[component]
pub fn PaginationContent(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
ul {
class: Styles::dx_pagination_content,
"data-slot": "pagination-content",
..attributes,
{children}
}
}
}
#[component]
pub fn PaginationItem(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
li {
"data-slot": "pagination-item",
..attributes,
{children}
}
}
}
#[derive(Props, Clone, PartialEq)]
pub struct PaginationLinkProps {
#[props(default)]
pub is_active: bool,
#[props(default)]
pub size: PaginationLinkSize,
#[props(default)]
pub data_kind: Option<PaginationLinkKind>,
onclick: Option<EventHandler<MouseEvent>>,
onmousedown: Option<EventHandler<MouseEvent>>,
onmouseup: Option<EventHandler<MouseEvent>>,
#[props(extends = GlobalAttributes)]
#[props(extends = a)]
pub attributes: Vec<Attribute>,
pub children: Element,
}
#[component]
pub fn PaginationLink(props: PaginationLinkProps) -> Element {
let aria_current = if props.is_active { Some("page") } else { None };
let data_kind = props.data_kind.map(|kind| kind.attr());
rsx! {
a {
class: Styles::dx_pagination_link,
"data-slot": "pagination-link",
"data-active": props.is_active,
"data-size": props.size.class(),
"data-kind": data_kind,
aria_current: aria_current,
onclick: move |event| {
if let Some(f) = &props.onclick {
f.call(event);
}
},
onmousedown: move |event| {
if let Some(f) = &props.onmousedown {
f.call(event);
}
},
onmouseup: move |event| {
if let Some(f) = &props.onmouseup {
f.call(event);
}
},
..props.attributes,
{props.children}
}
}
}
#[component]
pub fn PaginationPrevious(
onclick: Option<EventHandler<MouseEvent>>,
onmousedown: Option<EventHandler<MouseEvent>>,
onmouseup: Option<EventHandler<MouseEvent>>,
#[props(extends = GlobalAttributes)]
#[props(extends = a)]
attributes: Vec<Attribute>,
) -> Element {
rsx! {
PaginationLink {
size: PaginationLinkSize::Default,
aria_label: "Go to previous page",
data_kind: Some(PaginationLinkKind::Previous),
onclick,
onmousedown,
onmouseup,
attributes,
ChevronLeft { size: "1rem" }
span { class: Styles::dx_pagination_label, "Previous" }
}
}
}
#[component]
pub fn PaginationNext(
onclick: Option<EventHandler<MouseEvent>>,
onmousedown: Option<EventHandler<MouseEvent>>,
onmouseup: Option<EventHandler<MouseEvent>>,
#[props(extends = GlobalAttributes)]
#[props(extends = a)]
attributes: Vec<Attribute>,
) -> Element {
rsx! {
PaginationLink {
size: PaginationLinkSize::Default,
aria_label: "Go to next page",
data_kind: Some(PaginationLinkKind::Next),
onclick,
onmousedown,
onmouseup,
attributes,
span { class: Styles::dx_pagination_label, "Next" }
ChevronRight { size: "1rem" }
}
}
}
#[component]
pub fn PaginationEllipsis(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
) -> Element {
rsx! {
span {
class: Styles::dx_pagination_ellipsis,
"data-slot": "pagination-ellipsis",
aria_hidden: "true",
..attributes,
Ellipsis { size: "1rem" }
span { class: Styles::dx_sr_only, "More pages" }
}
}
}