semantic-ui-react
Version:
The official Semantic-UI-React integration.
155 lines (128 loc) • 4.12 kB
JavaScript
import _ from 'lodash'
import PropTypes from 'prop-types'
import React from 'react'
import {
ModernAutoControlledComponent as Component,
createPaginationItems,
customPropTypes,
getUnhandledProps,
} from '../../lib'
import Menu from '../../collections/Menu'
import PaginationItem from './PaginationItem'
/**
* A component to render a pagination.
*/
export default class Pagination extends Component {
getInitialAutoControlledState() {
return { activePage: 1 }
}
handleItemClick = (e, { value: nextActivePage }) => {
const { activePage: prevActivePage } = this.state
// Heads up! We need the cast to the "number" type there, as `activePage` can be a string
if (+prevActivePage === +nextActivePage) return
this.setState({ activePage: nextActivePage })
_.invoke(this.props, 'onPageChange', e, { ...this.props, activePage: nextActivePage })
}
handleItemOverrides = (active, type, value) => (predefinedProps) => ({
active,
type,
key: `${type}-${value}`,
onClick: (e, itemProps) => {
_.invoke(predefinedProps, 'onClick', e, itemProps)
if (itemProps.type !== 'ellipsisItem') this.handleItemClick(e, itemProps)
},
})
render() {
const {
'aria-label': ariaLabel,
boundaryRange,
disabled,
ellipsisItem,
siblingRange,
totalPages,
} = this.props
const { activePage } = this.state
const items = createPaginationItems({
activePage,
boundaryRange,
hideEllipsis: _.isNil(ellipsisItem),
siblingRange,
totalPages,
})
const rest = getUnhandledProps(Pagination, this.props)
return (
<Menu {...rest} aria-label={ariaLabel} pagination role='navigation'>
{_.map(items, ({ active, type, value }) =>
PaginationItem.create(this.props[type], {
defaultProps: {
content: value,
disabled,
value,
},
overrideProps: this.handleItemOverrides(active, type, value),
}),
)}
</Menu>
)
}
}
Pagination.propTypes = {
/** A pagination item can have an aria label. */
'aria-label': PropTypes.string,
/** Initial activePage value. */
defaultActivePage: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Index of the currently active page. */
activePage: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Number of always visible pages at the beginning and end. */
boundaryRange: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** A pagination can be disabled. */
disabled: PropTypes.bool,
/** A shorthand for PaginationItem. */
ellipsisItem: customPropTypes.itemShorthand,
/** A shorthand for PaginationItem. */
firstItem: customPropTypes.itemShorthand,
/** A shorthand for PaginationItem. */
lastItem: customPropTypes.itemShorthand,
/** A shorthand for PaginationItem. */
nextItem: customPropTypes.itemShorthand,
/** A shorthand for PaginationItem. */
pageItem: customPropTypes.itemShorthand,
/** A shorthand for PaginationItem. */
prevItem: customPropTypes.itemShorthand,
/**
* Called on change of an active page.
*
* @param {SyntheticEvent} event - React's original SyntheticEvent.
* @param {object} data - All props.
*/
onPageChange: PropTypes.func,
/** Number of always visible pages before and after the current one. */
siblingRange: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Total number of pages. */
totalPages: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
}
Pagination.autoControlledProps = ['activePage']
Pagination.defaultProps = {
'aria-label': 'Pagination Navigation',
boundaryRange: 1,
ellipsisItem: '...',
firstItem: {
'aria-label': 'First item',
content: '«',
},
lastItem: {
'aria-label': 'Last item',
content: '»',
},
nextItem: {
'aria-label': 'Next item',
content: '⟩',
},
pageItem: {},
prevItem: {
'aria-label': 'Previous item',
content: '⟨',
},
siblingRange: 1,
}
Pagination.Item = PaginationItem