Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions component.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"preview/src/components/skeleton",
"preview/src/components/card",
"preview/src/components/sheet",
"preview/src/components/pagination",
"preview/src/components/sidebar",
"preview/src/components/badge"
]
Expand Down
1 change: 1 addition & 0 deletions preview/src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ examples!(
label,
menubar,
navbar,
pagination,
popover,
progress,
radio_group,
Expand Down
21 changes: 21 additions & 0 deletions preview/src/components/pagination/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "pagination",
"description": "Navigation controls for paged content.",
"authors": [
"zhiyanzhaijie"
],
"exclude": [
"variants",
"docs.md",
"component.json"
],
"cargoDependencies": [
{
"name": "dioxus-primitives",
"git": "https://github.com/DioxusLabs/components"
}
],
"globalAssets": [
"../../../assets/dx-components-theme.css"
]
}
216 changes: 216 additions & 0 deletions preview/src/components/pagination/component.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use dioxus::prelude::*;

#[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! {
document::Link { rel: "stylesheet", href: asset!("./style.css") }
nav {
class: "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: "pagination-content",
"data-slot": "pagination-content",
..attributes,
{children}
}
}
}

#[component]
pub fn PaginationItem(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
rsx! {
li {
class: "pagination-item",
"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: "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 icon from lucide https://lucide.dev/icons/chevron-left
svg {
class: "pagination-icon",
view_box: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg",
polyline { points: "15 6 9 12 15 18" }
}
span { class: "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: "pagination-label", "Next" }
// ChevronRight icon from lucide https://lucide.dev/icons/chevron-right
svg {
class: "pagination-icon",
view_box: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg",
polyline { points: "9 6 15 12 9 18" }
}
}
}
}

#[component]
pub fn PaginationEllipsis(
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
) -> Element {
rsx! {
span {
class: "pagination-ellipsis",
"data-slot": "pagination-ellipsis",
aria_hidden: "true",
..attributes,
// MoreHorizontal icon from lucide https://lucide.dev/icons/more-horizontal
svg {
class: "pagination-icon",
view_box: "0 0 24 24",
xmlns: "http://www.w3.org/2000/svg",
circle { cx: "5", cy: "12", r: "1.5" }
circle { cx: "12", cy: "12", r: "1.5" }
circle { cx: "19", cy: "12", r: "1.5" }
}
span { class: "sr-only", "More pages" }
}
}
}
36 changes: 36 additions & 0 deletions preview/src/components/pagination/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
The pagination component provides navigational controls for paged content. It exposes a consistent structure for previous/next actions, individual page links, and an optional ellipsis for truncated ranges.

## Component Structure

```rust
// The Pagination component wraps the entire control.
Pagination {
// PaginationContent groups all items in a horizontal list.
PaginationContent {
// PaginationItem is the container for a single pagination element.
// Use one item at a time and swap the inner component as needed.
PaginationItem {
// PaginationPrevious renders a previous-page link.
// - Set href to your previous page url.
PaginationPrevious { href: "#" }

// PaginationLink renders a numbered page link.
// - is_active marks the current page.
// - href sets the target page.
PaginationLink { href: "#", is_active: true, "2" }

// PaginationEllipsis indicates truncated pages.
PaginationEllipsis {}

// PaginationNext renders a next-page link.
// - Set href to your next page url.
PaginationNext { href: "#" }
}
}
}
```

## Notes

- `PaginationLink` uses `is_active` to indicate the current page.
- `PaginationPrevious` and `PaginationNext` show labels on larger (non-mobile) screens; labels are hidden on smaller screens to keep the control compact.
2 changes: 2 additions & 0 deletions preview/src/components/pagination/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod component;
pub use component::*;
Loading
Loading