Skip to content

Commit

Permalink
Merge pull request #31 from cobaltinc/park/PRE-1707
Browse files Browse the repository at this point in the history
Pagination 컴포넌트 추가
  • Loading branch information
StellaKim1230 authored Aug 16, 2023
2 parents b525834 + e0236bd commit a1c9b49
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 0 deletions.
18 changes: 18 additions & 0 deletions packages/co-design-core/src/components/Pagination/Bullet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

interface BulletProps {
className?: string;
circleClassName?: string;
}

const Bullet = ({ circleClassName, ...props }: BulletProps) => {
return (
<div {...props}>
{[0, 1, 2].map((_, index) => (
<div key={index} className={circleClassName} />
))}
</div>
);
};

export default Bullet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { createStyles } from '@co-design/styles';

export default createStyles((theme) => ({
root: {
display: 'inline-flex',
alignItems: 'center',
},
page: {
display: 'inline-block',
minWidth: '32px',
height: '32px',
padding: '7px 11.5px',
textAlign: 'center',
fontSize: '14px',
lineHeight: '20px',
verticalAlign: 'middle',
color: '#171b24',
boxSizing: 'border-box',
marginRight: '8px',
cursor: 'pointer',
'@media (max-width: 500px)': {
minWidth: '24px',
height: '24px',
padding: '2px 4px',
},
'&:last-of-type': {
marginRight: '0px',
},
'&:hover': {
backgroundColor: 'rgba(35, 40, 48, 0.12)',
},
},
active: {
backgroundColor: theme.palettes.gray[9],
color: 'white',
'&:hover': {
backgroundColor: theme.palettes.gray[9],
},
},
arrow: {
display: 'inline-block',
width: '32px',
height: '32px',
verticalAlign: 'middle',
'&:first-of-type': {
marginRight: '8px',
},
'&:last-of-type': {
marginLeft: '8px',
},
},
disabled: {
pointerEvents: 'none',
cursor: 'not-allowed',
},
bullet: {
marginRight: '4px',
'@media (max-width: 500px)': {
width: '24px',
height: '24px',
},
},
circle: {
display: 'inline-block',
width: '3px',
height: '3px',
borderRadius: '50%',
marginRight: '4px',
backgroundColor: '#171b24',
'&:last-of-type': {
marginRight: '0px',
},
},
}));
146 changes: 146 additions & 0 deletions packages/co-design-core/src/components/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import React, { useState } from 'react';
import { View } from '../View';
import { IconButton } from '../IconButton';
import ChevronLeft from './icons/ChevronLeft';
import ChevronRight from './icons/ChevronRight';
import useStyles from './Pagination.style';
import { ClassNames, CoComponentProps } from '@co-design/styles';
import Bullet from './Bullet';

export type PaginationStylesNames = ClassNames<typeof useStyles>;

export interface PaginationProps extends CoComponentProps<PaginationStylesNames>, Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange'> {
/** Pagination 의 초기 Active Page 를 설정합니다. */
activePage?: number;

/** Pagination 의 한 페이지당 보여줄 아이템의 개수를 설정합니다. */
itemsCountPerView?: number;

/** Pagination 의 전체 아이템의 개수를 설정합니다. */
totalItemsCount: number;

/** 첫 페이지를 유지하여 보여주고 선택할 수 있도록 설정합니다. */
showFirst?: boolean;

/** 마지막 페이지를 유지하여 보여주고 선택할 수 있도록 설정합니다. */
showLast?: boolean;

/** Pagination 의 페이지를 변경했을 때 발생할 이벤트를 설정합니다. */
onChange?(page: number): void;
}

export const Pagination = ({
activePage = 1,
itemsCountPerView = 10,
totalItemsCount,
showFirst = true,
showLast = true,
onChange,
className = '',
style,
co,
overrideStyles,
...props
}: PaginationProps) => {
const [currentPage, setCurrentPage] = useState(activePage);
const { cx, classes } = useStyles(null, {
overrideStyles,
name: 'Pagination',
});

const totalPage = Math.ceil(totalItemsCount / itemsCountPerView);
let pages = [];

if (totalPage <= 5) {
pages = Array(totalPage)
.fill(0)
.map((_, index) => index + 1);
} else if (currentPage < 3) {
pages = [1, 2, 3, 4, 5];
} else if (totalPage - 2 < currentPage) {
pages = [totalPage - 4, totalPage - 3, totalPage - 2, totalPage - 1, totalPage];
} else {
pages = [currentPage - 2, currentPage - 1, currentPage, currentPage + 1, currentPage + 2];
}

const handleChangePage = (page: number) => {
onChange?.(page);
setCurrentPage(page);
};

const handlePrevPage = () => {
if (currentPage > 1) {
onChange?.(currentPage - 1);
setCurrentPage(currentPage - 1);
}
};

const handleNextPage = () => {
if (currentPage < totalPage) {
onChange?.(currentPage + 1);
setCurrentPage(currentPage + 1);
}
};

return (
<View className={classes.root} style={style} co={co} {...props}>
<IconButton
color="gray"
variant="text"
className={cx(classes.arrow, { [classes.disabled]: currentPage === 1 })}
onClick={handlePrevPage}
overrideStyles={{
text: {
'&:not(:disabled):hover': {
borderRadius: 0,
},
},
}}
>
<ChevronLeft color={currentPage === 1 ? '#D5DADF' : '#171B24'} />
</IconButton>

{currentPage > 3 && totalPage > pages.length && showFirst ? (
<>
<div className={cx(classes.page, { [classes.active]: 1 === currentPage })} onClick={() => handleChangePage(1)}>
1
</div>
<Bullet className={classes.bullet} circleClassName={classes.circle} />
</>
) : null}

{pages.map((index) => (
<div className={cx(classes.page, { [classes.active]: index === currentPage })} key={index} onClick={() => handleChangePage(index)}>
{index}
</div>
))}

{totalPage - 2 > currentPage && totalPage > pages.length && showLast ? (
<>
<Bullet className={classes.bullet} circleClassName={classes.circle} />
<div className={cx(classes.page, { [classes.active]: totalPage === currentPage })} onClick={() => handleChangePage(totalPage)}>
{totalPage}
</div>
</>
) : null}

<IconButton
color="gray"
variant="text"
className={cx(classes.arrow, { [classes.disabled]: currentPage === totalPage })}
onClick={handleNextPage}
overrideStyles={{
text: {
'&:not(:disabled):hover': {
borderRadius: 0,
},
},
}}
>
<ChevronRight color={currentPage === totalPage ? '#D5DADF' : '#171B24'} />
</IconButton>
</View>
);
};

Pagination.displayName = '@co-design/core/Pagination';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React, { SVGProps } from 'react';

const ChevronLeft = (props: SVGProps<SVGSVGElement>) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path fillRule="evenodd" clipRule="evenodd" d="M15.41 16.59L10.83 12L15.41 7.41L14 6L8 12L14 18L15.41 16.59Z" fill="#5D636D" />
</svg>
);

export default ChevronLeft;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React, { SVGProps } from 'react';

const ChevronRight = (props: SVGProps<SVGSVGElement>) => (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.58984 16.59L13.1698 12L8.58984 7.41L9.99984 6L15.9998 12L9.99984 18L8.58984 16.59Z"
fill="#5D636D"
/>
</svg>
);

export default ChevronRight;
2 changes: 2 additions & 0 deletions packages/co-design-core/src/components/Pagination/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Pagination } from './Pagination';
export type { PaginationProps } from './Pagination';
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import { Pagination } from '../Pagination';
import { Meta, StoryObj } from '@storybook/react';

type Story = StoryObj<typeof Pagination>;

export default {
title: '@co-design/core/Pagination',
component: Pagination,
argTypes: {
activePage: {
control: {
type: 'number',
},
},
itemsCountPerView: {
control: {
type: 'number',
},
},
totalItemsCount: {
control: {
type: 'number',
},
},
showFirst: {
control: {
type: 'boolean',
},
},
showLast: {
control: {
type: 'boolean',
},
},
},
args: {
activePage: 1,
itemsCountPerView: 10,
totalItemsCount: 120,
showFirst: true,
showLast: true,
},
} as Meta<typeof Pagination>;

export const Default: Story = {};

export const NoShowBullet: Story = {
args: {
showFirst: false,
showLast: false,
},
};
1 change: 1 addition & 0 deletions packages/co-design-core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export * from './Menu';
export * from './Modal';
export * from './NativeSelect';
export * from './Overlay';
export * from './Pagination';
export * from './PanelStack';
export * from './Paper';
export * from './Popover';
Expand Down

0 comments on commit a1c9b49

Please sign in to comment.