Skip to content

Commit

Permalink
♻️ Pagination Story to Typescript (#796)
Browse files Browse the repository at this point in the history
* ♻️ JSX to TSX

* ♻️ Template literal formatting

Fixed a TS lint error

* ♻️ Export props

* ♻️ Controls added to Pagination story

* ♻️ Added HTMLAttributes to PaginationProps and removed className + children

* 🔥 Remove <Body> wrapper in Story

Not needed anymore due to Docs page

* 🔥 Removed unused import

* 🚨 Fixed ts lint errors in all Pagination files
  • Loading branch information
pomfrida authored and vnys committed Nov 13, 2020
1 parent 103ac33 commit 1feaa6a
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import React from 'react'
import { Pagination, Typography } from '@equinor/eds-core-react'
import {
Pagination,
PaginationProps,
Typography,
} from '@equinor/eds-core-react'
import styled from 'styled-components'
import { withKnobs, number, boolean } from '@storybook/addon-knobs'

const Body = styled.div`
margin: 42px;
display: grid;
grid-auto-columns: auto;
grid-gap: 8px;
width: 750px;
`
import { Story, Meta } from '@storybook/react'

const PaddedTypography = styled(Typography)`
margin: 16px 0;
Expand All @@ -18,12 +14,26 @@ const PaddedTypography = styled(Typography)`
export default {
title: 'Components/Pagination',
component: Pagination,
decorators: [withKnobs],
argTypes: {
totalItems: {
defaultValue: 40,
control: {
type: 'number',
min: 10,
max: 1000,
step: 1,
},
},
},
} as Meta

export const Default: Story<PaginationProps> = (args) => {
return <Pagination {...args} />
}

export const Variants = () => {
export const Variants: Story<PaginationProps> = () => {
return (
<Body>
<>
<PaddedTypography variant="h2">Length before truncation</PaddedTypography>
<Pagination totalItems={7} itemsPerPage={1} />
<PaddedTypography variant="h2">Truncated</PaddedTypography>
Expand All @@ -39,22 +49,6 @@ export const Variants = () => {
withItemIndicator
defaultPage={6}
/>
</Body>
)
}

export const WithKnobs = () => {
const totalItems = number('Total Items', 20)
const itemsPerPage = number('Items per page', 1)
const withItemIndicator = boolean('With item indicator', true)

return (
<Body>
<Pagination
totalItems={totalItems}
itemsPerPage={itemsPerPage}
withItemIndicator={withItemIndicator}
/>
</Body>
</>
)
}
276 changes: 137 additions & 139 deletions libraries/core-react/src/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, {
forwardRef,
useState,
ReactNode,
MouseEvent,
KeyboardEvent,
HTMLAttributes,
} from 'react'
import styled from 'styled-components'
import { Button } from '../Button'
Expand All @@ -26,7 +26,7 @@ const icons = {

Icon.add(icons)

type NavigationStyledProps = Pick<Props, 'withItemIndicator'>
type NavigationStyledProps = Pick<PaginationProps, 'withItemIndicator'>

const Navigation = styled.nav<NavigationStyledProps>`
display: flex;
Expand Down Expand Up @@ -71,151 +71,149 @@ function getAriaLabel(page: number, selected: number) {
return `${selected === page ? 'Current page, ' : 'Go to '}page ${page}`
}

type Props = {
// Number of total items to be paginated
export type PaginationProps = {
/** Number of total items to be paginated */
totalItems: number
// To display total item count
/** To display total item count */
withItemIndicator?: boolean
// Choose number of items per page
/** Choose number of items per page */
itemsPerPage?: number
// Callback fired on page change
/** Callback fired on page change */
onChange?: (event: MouseEvent | KeyboardEvent, page: number) => void
// Default start page
/** Default start page */
defaultPage?: number
// ClassName
className?: string
// Children
children?: ReactNode
}

export const Pagination = forwardRef<HTMLElement, Props>(function Pagination(
{
totalItems,
defaultPage = 1,
withItemIndicator,
itemsPerPage = 10,
onChange,
className,
...other
},
ref,
) {
const pages = Math.ceil(totalItems / itemsPerPage) // Total page numbers
const columns = pages < 5 ? pages + 2 : 7 // Total pages to display on the control + 2: < and >

const [activePage, setActivePage] = useState(defaultPage)

const currentItemFirst =
activePage === 1 ? 1 : activePage * itemsPerPage - itemsPerPage + 1 // First number of range of items at current page
const currentItemLast =
activePage === pages ? totalItems : activePage * itemsPerPage // Last number of range of items at current page

const onPageChange = (event: MouseEvent | KeyboardEvent, page: number) => {
page && setActivePage(page)
if (event && onChange) {
// Callback for provided onChange func
onChange(event, page)
} else {
return undefined
} & HTMLAttributes<HTMLElement>

export const Pagination = forwardRef<HTMLElement, PaginationProps>(
function Pagination(
{
totalItems,
defaultPage = 1,
withItemIndicator,
itemsPerPage = 10,
onChange,
className,
...other
},
ref,
) {
const pages = Math.ceil(totalItems / itemsPerPage) // Total page numbers
const columns = pages < 5 ? pages + 2 : 7 // Total pages to display on the control + 2: < and >

const [activePage, setActivePage] = useState(defaultPage)

const currentItemFirst =
activePage === 1 ? 1 : activePage * itemsPerPage - itemsPerPage + 1 // First number of range of items at current page
const currentItemLast =
activePage === pages ? totalItems : activePage * itemsPerPage // Last number of range of items at current page

const onPageChange = (event: MouseEvent | KeyboardEvent, page: number) => {
page && setActivePage(page)
if (event && onChange) {
// Callback for provided onChange func
onChange(event, page)
} else {
return undefined
}
}
}

const items = PaginationControl(pages, activePage)
const items = PaginationControl(pages, activePage)

const props = {
ref,
withItemIndicator,
className,
...other,
}

const pagination = (
<Navigation aria-label="pagination" {...props}>
<OrderedList
style={{
gridTemplateColumns: 'repeat(' + columns + ', 48px)',
}}
>
<ListItem key="previous">
<Button
variant="ghost_icon"
onClick={
activePage > 1
? (event) => {
onPageChange(event, activePage - 1)
}
: undefined
}
disabled={activePage === 1}
aria-label="Go to previous page"
>
<Icon name="chevron_left" title="previous" />
</Button>
</ListItem>

{items.length > 0
? items.map((page, index) =>
page !== 'ELLIPSIS' ? (
// eslint-disable-next-line react/no-array-index-key
<ListItem key={'list-item' + index}>
<PaginationItem
{...page}
aria-label={getAriaLabel(page, activePage)}
aria-current={activePage}
page={page}
selected={page === activePage}
onClick={(event) => {
onPageChange(event, page)
}}
/>
</ListItem>
) : (
<ListItem
const props = {
ref,
withItemIndicator,
className,
...other,
}

const pagination = (
<Navigation aria-label="pagination" {...props}>
<OrderedList
style={{
gridTemplateColumns: `repeat(${columns}, 48px)`,
}}
>
<ListItem key="previous">
<Button
variant="ghost_icon"
onClick={
activePage > 1
? (event) => {
onPageChange(event, activePage - 1)
}
: undefined
}
disabled={activePage === 1}
aria-label="Go to previous page"
>
<Icon name="chevron_left" title="previous" />
</Button>
</ListItem>

{items.length > 0
? items.map((page, index) =>
page !== 'ELLIPSIS' ? (
// eslint-disable-next-line react/no-array-index-key
key={'ellipsis-' + index}
>
<StyledIcon name="more_horizontal" title="ellipsis" />
</ListItem>
),
)
: undefined}
<ListItem key="next">
<Button
variant="ghost_icon"
onClick={
activePage < pages
? (event) => {
onPageChange(event, activePage + 1)
}
: undefined
}
aria-label="Go to next page"
disabled={activePage === pages}
>
<Icon name="chevron_right" title="next" />
</Button>
</ListItem>
</OrderedList>
</Navigation>
)

return withItemIndicator ? (
<FlexContainer>
<Text>
{currentItemFirst !== currentItemLast
? currentItemFirst +
' - ' +
currentItemLast +
' of ' +
totalItems +
' items'
: currentItemFirst + ' of ' + totalItems + ' items'}
</Text>
{pagination}
</FlexContainer>
) : (
pagination
)
})
<ListItem key={`list-item ${index}`}>
<PaginationItem
{...page}
aria-label={getAriaLabel(page as number, activePage)}
aria-current={activePage}
page={page as number}
selected={page === activePage}
onClick={(event) => {
onPageChange(event, page as number)
}}
/>
</ListItem>
) : (
<ListItem
// eslint-disable-next-line react/no-array-index-key
key={`ellipsis-${index}`}
>
<StyledIcon name="more_horizontal" title="ellipsis" />
</ListItem>
),
)
: undefined}
<ListItem key="next">
<Button
variant="ghost_icon"
onClick={
activePage < pages
? (event) => {
onPageChange(event, activePage + 1)
}
: undefined
}
aria-label="Go to next page"
disabled={activePage === pages}
>
<Icon name="chevron_right" title="next" />
</Button>
</ListItem>
</OrderedList>
</Navigation>
)

return withItemIndicator ? (
<FlexContainer>
<Text>
{currentItemFirst !== currentItemLast
? `${currentItemFirst}
${' - '}
${currentItemLast}
${' of '}
${totalItems}
${' items'}`
: `${currentItemFirst} ${' of '} ${totalItems} ${' items'}`}
</Text>
{pagination}
</FlexContainer>
) : (
pagination
)
},
)

// Pagination.displayName = 'eds-pagination'
Loading

0 comments on commit 1feaa6a

Please sign in to comment.