Skip to content

Commit

Permalink
feat(Pagination): add new Pagination component (#193)
Browse files Browse the repository at this point in the history
* feat(Pagination): add new Pagination component

* update
  • Loading branch information
evenchange4 authored Mar 22, 2019
1 parent b4e1f85 commit 3170b17
Show file tree
Hide file tree
Showing 10 changed files with 14,642 additions and 0 deletions.
82 changes: 82 additions & 0 deletions src/Pagination/PageLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// @flow
import * as React from 'react';
import styled from 'styled-components';
import { darken2, darken3 } from '../utils/darken';
import { type ThemeProps } from '../utils/type.flow';

export type Props = {
to: number,
onClick: number => void,
disabled?: boolean,
active?: boolean,
};
export type SquareButtonTextProps = {
disabled: boolean,
active: boolean,
};

export const SquareButtonText: React.ComponentType<SquareButtonTextProps> = styled.div`
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 3px;
border-width: 1px;
border-style: solid;
border-color: ${({ active, theme }: SquareButtonTextProps & ThemeProps) =>
active ? darken3(theme.color.primary) : 'transparent'};
transition: border-color cubic-bezier(0.47, 0, 0.75, 0.72) 0.3s;
background-color: ${({ active, theme }: SquareButtonTextProps & ThemeProps) =>
active ? darken2(theme.color.primary) : 'unset'};
color: ${({
active,
disabled,
theme,
}: SquareButtonTextProps & ThemeProps) => {
if (disabled) return theme.color.grayBase;
if (active) return theme.color.white;
return theme.color.primary;
}};
cursor: ${({ disabled }: SquareButtonTextProps & ThemeProps) =>
disabled ? 'unset' : 'pointer'};
&:hover {
border-color: ${({
active,
disabled,
theme,
}: SquareButtonTextProps & ThemeProps) => {
if (disabled) return 'transparent';
if (active) return darken3(theme.color.primary);
return theme.color.primary;
}};
}
`;

const PageLink = ({
to,
onClick,
disabled = false,
active = false,
...otherProps
}: Props) => {
const onClickableClick = React.useCallback(() => {
if (!disabled) {
onClick(to);
}
});

return (
<SquareButtonText
{...otherProps}
disabled={disabled}
onClick={onClickableClick}
active={active}
/>
);
};

export default React.memo<Props>(PageLink);
80 changes: 80 additions & 0 deletions src/Pagination/Pagination.example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// @flow
import * as React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Pagination from '.';

storiesOf('Pagination', module)
.add(
'10 pages',
() => (
<div>
<Pagination pages={10} value={1} onChange={action('onChange')} />
<Pagination pages={10} value={2} onChange={action('onChange')} />
<Pagination pages={10} value={3} onChange={action('onChange')} />
<Pagination pages={10} value={4} onChange={action('onChange')} />
<Pagination pages={10} value={5} onChange={action('onChange')} />
<Pagination pages={10} value={6} onChange={action('onChange')} />
<Pagination pages={10} value={7} onChange={action('onChange')} />
<Pagination pages={10} value={8} onChange={action('onChange')} />
<Pagination pages={10} value={9} onChange={action('onChange')} />
<Pagination pages={10} value={10} onChange={action('onChange')} />
</div>
),
{
info: {
text: ``,
inline: true,
source: false,
},
},
)
.add(
'1 page',
() => <Pagination pages={1} value={1} onChange={action('onChange')} />,
{
info: {
text: ``,
inline: true,
source: false,
},
},
)
.add(
'5 pages',
() => (
<div>
<Pagination pages={5} value={1} onChange={action('onChange')} />
<Pagination pages={5} value={2} onChange={action('onChange')} />
<Pagination pages={5} value={3} onChange={action('onChange')} />
<Pagination pages={5} value={4} onChange={action('onChange')} />
<Pagination pages={5} value={5} onChange={action('onChange')} />
</div>
),
{
info: {
text: ``,
inline: true,
source: false,
},
},
)
.add(
'useState',
() => {
const StatefulPagination = () => {
const [value, setValue] = React.useState(1);
const onChange = setValue;

return <Pagination pages={10} value={value} onChange={onChange} />;
};
return <StatefulPagination />;
},
{
info: {
text: ``,
inline: true,
source: false,
},
},
);
69 changes: 69 additions & 0 deletions src/Pagination/Pagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// @flow
import * as React from 'react';
import * as R from 'ramda';
import {
IconChevronLeft,
IconChevronRight,
IconChevronFirst,
IconChevronLast,
IconMoreHoriz,
} from '../Icons';
import { Container } from './styled-components';
import PageLink from './PageLink';
import getPaginationRange from '../utils/getPaginationRange';

export type Props = {
pages: number, // Total number of pages.
value: number, // Current page
onChange: (page: number) => void,
};

const Pagination = ({ pages, value, onChange, ...otherProps }: Props) => {
const range = React.useMemo(() => getPaginationRange({ pages, value }), [
pages,
value,
]);
const isFirstPage = React.useMemo(() => value === 1, [value]);
const isLastPage = React.useMemo(() => value === pages, [pages, value]);
const isFirstPageIncluded = React.useMemo(() => R.head(range) === 1, [range]);
const isLastPageIncluded = React.useMemo(() => R.last(range) === pages, [
range,
pages,
]);

return (
<Container {...otherProps}>
<PageLink to={1} onClick={onChange} disabled={isFirstPage}>
<IconChevronFirst height={24} width={24} />
</PageLink>
<PageLink to={value - 1} onClick={onChange} disabled={isFirstPage}>
<IconChevronLeft height={24} width={24} />
</PageLink>

{!isFirstPageIncluded && (
<PageLink to={0} disabled onClick={onChange}>
<IconMoreHoriz height={24} width={24} />
</PageLink>
)}
{range.map(n => (
<PageLink key={n} to={n} active={value === n} onClick={onChange}>
{n}
</PageLink>
))}
{!isLastPageIncluded && (
<PageLink to={0} disabled onClick={onChange}>
<IconMoreHoriz height={24} width={24} />
</PageLink>
)}

<PageLink to={value + 1} onClick={onChange} disabled={isLastPage}>
<IconChevronRight height={24} width={24} />
</PageLink>
<PageLink to={pages} onClick={onChange} disabled={isLastPage}>
<IconChevronLast height={24} width={24} />
</PageLink>
</Container>
);
};

export default React.memo<Props>(Pagination);
Loading

0 comments on commit 3170b17

Please sign in to comment.