-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KDS-1878-migrate-pagination-1 (#4244)
* add Pagination component * fix style import * Fix truncate style import * Fix truncate styles * Moved styles to correct location * Moved styles to correct location * update stories * replace snowflake directional and pagination links in Pagination component * Fix SCSS imports * shuffle stories around * add stickersheets * replace unit tests with storybook * remove circular dep * removed Enum * add changeset * update docs for subcomponents
- Loading branch information
Showing
28 changed files
with
494 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@kaizen/components": minor | ||
--- | ||
|
||
Migrate Pagination from `kaizen-legacy` |
4 changes: 2 additions & 2 deletions
4
packages/components/src/Button/GenericButton/GenericButton.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
export type { CustomButtonProps } from "./GenericButton" | ||
export * from "./Button" | ||
export * from "./IconButton" | ||
export * from "./PaginationLink" | ||
export * from "./DirectionalLink" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
@import "~@kaizen/design-tokens/sass/typography"; | ||
@import "~@kaizen/design-tokens/sass/color"; | ||
@import "~@kaizen/design-tokens/sass/border"; | ||
|
||
// Pagination | ||
.container { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
|
||
.pagesIndicatorWrapper { | ||
display: flex; | ||
flex-direction: row; | ||
justify-content: space-around; | ||
} | ||
|
||
.arrowIconWrapper { | ||
height: 36px; | ||
width: 36px; | ||
border-radius: 18px; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
border: $border-focus-ring-border-width $border-focus-ring-border-style | ||
$color-blue-300; | ||
margin: 0 5px; | ||
background-color: transparent; | ||
color: $color-blue-500; | ||
box-sizing: border-box; | ||
|
||
&:disabled { | ||
opacity: 35%; | ||
pointer-events: none; | ||
} | ||
|
||
&:hover { | ||
background-color: $color-blue-100; | ||
} | ||
|
||
&:focus { | ||
background-color: $color-blue-200; | ||
|
||
&:focus-visible { | ||
outline: none; | ||
} | ||
|
||
.pageIndicatorFocusRing { | ||
border: $border-focus-ring-border-width $border-focus-ring-border-style | ||
$color-blue-500; | ||
} | ||
} | ||
} | ||
|
||
// Truncate indicator | ||
.truncateIndicatorWrapper { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 36px; | ||
width: 36px; | ||
background-color: transparent; | ||
color: rgba($color-purple-800-rgb, 0.7); | ||
margin: 0 5px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from "react" | ||
import { render, screen, waitFor } from "@testing-library/react" | ||
import userEvent from "@testing-library/user-event" | ||
import { Pagination } from "./Pagination" | ||
|
||
const user = userEvent.setup() | ||
|
||
const defaultProps = { | ||
currentPage: 1, | ||
pageCount: 10, | ||
ariaLabelNextPage: "Next page", | ||
ariaLabelPreviousPage: "Previous page", | ||
ariaLabelPage: "Page", | ||
onPageChange: jest.fn<void, [number]>(), | ||
} | ||
|
||
describe("<Pagination />", () => { | ||
it("calls onPageChange when clicking page number", async () => { | ||
const onPageChange = jest.fn<void, [number]>() | ||
|
||
render(<Pagination {...defaultProps} onPageChange={onPageChange} />) | ||
|
||
expect(onPageChange).toHaveBeenCalledTimes(0) | ||
|
||
await user.click(screen.getByRole("button", { name: "Page 1" })) | ||
await waitFor(() => { | ||
expect(onPageChange).toHaveBeenCalledTimes(1) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import React, { HTMLAttributes } from "react" | ||
import classnames from "classnames" | ||
import { OverrideClassName } from "~types/OverrideClassName" | ||
import { DirectionalLink } from "./subcomponents/DirectionalLink" | ||
import { PaginationLink } from "./subcomponents/PaginationLink" | ||
import { TruncateIndicator } from "./subcomponents/TruncateIndicator" | ||
import { createRange } from "./utils/createRange" | ||
import styles from "./Pagination.module.scss" | ||
|
||
export type PaginationProps = { | ||
currentPage: number | ||
pageCount: number | ||
ariaLabelNextPage: string | ||
ariaLabelPreviousPage: string | ||
ariaLabelPage: string | ||
onPageChange: (newPage: number) => void | ||
} & OverrideClassName<HTMLAttributes<HTMLElement>> | ||
|
||
type PageAction = "prev" | "next" | ||
|
||
/** | ||
* {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3082092975/Pagination Guidance} | | ||
* {@link https://cultureamp.design/?path=/docs/components-pagination--docs Storybook} | ||
*/ | ||
export const Pagination = ({ | ||
currentPage = 1, | ||
pageCount, | ||
ariaLabelNextPage, | ||
ariaLabelPreviousPage, | ||
ariaLabelPage, | ||
onPageChange, | ||
classNameOverride, | ||
...restProps | ||
}: PaginationProps): JSX.Element => { | ||
// Click event for all pagination buttons (next, prev, and the actual numbers) | ||
const handleButtonClick = (newPage: number | PageAction): void => { | ||
if (newPage === "prev") { | ||
onPageChange(currentPage - 1) | ||
return | ||
} | ||
if (newPage === "next") { | ||
onPageChange(currentPage + 1) | ||
return | ||
} | ||
onPageChange(newPage) | ||
} | ||
|
||
const paginationIndicator = (page: number): JSX.Element => ( | ||
<PaginationLink | ||
key={page} | ||
pageNumber={page} | ||
isActive={currentPage === page} | ||
aria-label={`${ariaLabelPage} ${page}`} | ||
onClick={() => handleButtonClick(page)} | ||
/> | ||
) | ||
|
||
const pagination = (): JSX.Element[] => { | ||
const items: JSX.Element[] = [] | ||
|
||
const boundaryPagesRange = 1 | ||
const siblingPagesRange = 1 | ||
|
||
// truncateSize is 1 now but could be 0 if we add the ability to hide it. | ||
const truncateSize = 1 | ||
|
||
const showAllPages = | ||
1 + 2 * truncateSize + 2 * siblingPagesRange + 2 * boundaryPagesRange >= | ||
pageCount | ||
|
||
// Simplify generation of pages if number of available items is equal or greater than total pages to show | ||
if (showAllPages) { | ||
return createRange(1, pageCount).map(paginationIndicator) | ||
} else { | ||
// Calculate group of first pages | ||
const firstPagesStart = 1 | ||
const firstPagesEnd = boundaryPagesRange | ||
const firstPages = createRange(firstPagesStart, firstPagesEnd).map( | ||
paginationIndicator | ||
) | ||
|
||
// Calculate group of last pages | ||
const lastPagesStart = pageCount + 1 - boundaryPagesRange | ||
const lastPagesEnd = pageCount | ||
const lastPages = createRange(lastPagesStart, lastPagesEnd).map( | ||
paginationIndicator | ||
) | ||
|
||
// Calculate group of main pages | ||
const mainPagesStart = Math.min( | ||
Math.max( | ||
currentPage - siblingPagesRange, | ||
firstPagesEnd + truncateSize + 1 | ||
), | ||
lastPagesStart - truncateSize - 2 * siblingPagesRange - 1 | ||
) | ||
const mainPagesEnd = mainPagesStart + 2 * siblingPagesRange | ||
const mainPages = createRange(mainPagesStart, mainPagesEnd).map( | ||
paginationIndicator | ||
) | ||
|
||
// Add group of first pages | ||
items.push(...firstPages) | ||
|
||
// Calculate and add truncate before group of main pages | ||
const firstEllipsisPageNumber = mainPagesStart - 1 | ||
const showPageInsteadOfFirstEllipsis = | ||
firstEllipsisPageNumber === firstPagesEnd + 1 | ||
items.push( | ||
showPageInsteadOfFirstEllipsis ? ( | ||
paginationIndicator(firstEllipsisPageNumber) | ||
) : ( | ||
<TruncateIndicator key={firstEllipsisPageNumber} /> | ||
) | ||
) | ||
|
||
// Add group of main pages | ||
items.push(...mainPages) | ||
|
||
// Calculate and add truncate after group of main pages | ||
const secondEllipsisPageNumber = mainPagesEnd + 1 | ||
const showPageInsteadOfSecondEllipsis = | ||
secondEllipsisPageNumber === lastPagesStart - 1 | ||
items.push( | ||
showPageInsteadOfSecondEllipsis ? ( | ||
paginationIndicator(secondEllipsisPageNumber) | ||
) : ( | ||
<TruncateIndicator key={secondEllipsisPageNumber} /> | ||
) | ||
) | ||
|
||
// Add group of last pages | ||
items.push(...lastPages) | ||
} | ||
return items | ||
} | ||
|
||
const previousPageDisabled = currentPage <= 1 | ||
const nextPageDisabled = currentPage >= pageCount | ||
|
||
return ( | ||
<nav | ||
className={classnames(styles.container, classNameOverride)} | ||
{...restProps} | ||
> | ||
<DirectionalLink | ||
label={ariaLabelPreviousPage} | ||
direction="prev" | ||
disabled={previousPageDisabled} | ||
onClick={(): void => handleButtonClick("prev")} | ||
/> | ||
|
||
<div className={styles.pagesIndicatorWrapper}>{pagination()}</div> | ||
|
||
<DirectionalLink | ||
label={ariaLabelNextPage} | ||
direction="next" | ||
disabled={nextPageDisabled} | ||
onClick={(): void => handleButtonClick("next")} | ||
/> | ||
</nav> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { Canvas, Controls, Meta } from "@storybook/blocks" | ||
import { ResourceLinks, KaioNotification, Installation } from "~storybook/components" | ||
import * as PaginationStories from "./Pagination.stories" | ||
|
||
<Meta of={PaginationStories} /> | ||
|
||
# Pagination | ||
|
||
<ResourceLinks | ||
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/Pagination" | ||
figma="https://www.figma.com/file/ZRfnoNUXbGZv4eVWLbF4Az/%EF%B8%8F%F0%9F%96%BC%EF%B8%8F-Component-Gallery?node-id=9%3A39913&t=P1w10jr2cpPuaayw-1" | ||
designGuidelines="https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3082092975/Pagination" | ||
className="!mb-8" | ||
/> | ||
|
||
<KaioNotification /> | ||
|
||
<Installation | ||
installCommand="yarn add @kaizen/components" | ||
importStatement='import { Pagination } from "@kaizen/components"' | ||
/> | ||
|
||
## Overview | ||
|
||
Pagination separates large bodies of content into separate pages. You can access each page via a shared index of links. | ||
|
||
<Canvas of={PaginationStories.Playground} /> | ||
<Controls of={PaginationStories.Playground} /> |
Oops, something went wrong.