From 91162049ed3587d6af0ef9bb7ff40ea205aff7cf Mon Sep 17 00:00:00 2001 From: healtheloper <58503584+healtheloper@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:36:06 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Pagination=20=EC=9D=98=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=96=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Pagination/icons/ChevronLeft.tsx | 9 +++++++++ .../components/Pagination/icons/ChevronRight.tsx | 14 ++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 packages/co-design-core/src/components/Pagination/icons/ChevronLeft.tsx create mode 100644 packages/co-design-core/src/components/Pagination/icons/ChevronRight.tsx diff --git a/packages/co-design-core/src/components/Pagination/icons/ChevronLeft.tsx b/packages/co-design-core/src/components/Pagination/icons/ChevronLeft.tsx new file mode 100644 index 0000000..695bbce --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/icons/ChevronLeft.tsx @@ -0,0 +1,9 @@ +import React, { SVGProps } from 'react'; + +const ChevronLeft = (props: SVGProps) => ( + + + +); + +export default ChevronLeft; diff --git a/packages/co-design-core/src/components/Pagination/icons/ChevronRight.tsx b/packages/co-design-core/src/components/Pagination/icons/ChevronRight.tsx new file mode 100644 index 0000000..b3bdcf2 --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/icons/ChevronRight.tsx @@ -0,0 +1,14 @@ +import React, { SVGProps } from 'react'; + +const ChevronRight = (props: SVGProps) => ( + + + +); + +export default ChevronRight; From 5fc190275bb735be41736e9582d7370f9484ef94 Mon Sep 17 00:00:00 2001 From: healtheloper <58503584+healtheloper@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:37:21 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Pagination=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=B6=94=EA=B0=80=ED=96=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Pagination/Pagination.style.ts | 74 +++++++++ .../src/components/Pagination/Pagination.tsx | 144 ++++++++++++++++++ .../src/components/Pagination/index.ts | 2 + .../Pagination/stories/Pagination.stories.tsx | 53 +++++++ .../co-design-core/src/components/index.ts | 1 + 5 files changed, 274 insertions(+) create mode 100644 packages/co-design-core/src/components/Pagination/Pagination.style.ts create mode 100644 packages/co-design-core/src/components/Pagination/Pagination.tsx create mode 100644 packages/co-design-core/src/components/Pagination/index.ts create mode 100644 packages/co-design-core/src/components/Pagination/stories/Pagination.stories.tsx diff --git a/packages/co-design-core/src/components/Pagination/Pagination.style.ts b/packages/co-design-core/src/components/Pagination/Pagination.style.ts new file mode 100644 index 0000000..aa2efe5 --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/Pagination.style.ts @@ -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', + }, + }, +})); diff --git a/packages/co-design-core/src/components/Pagination/Pagination.tsx b/packages/co-design-core/src/components/Pagination/Pagination.tsx new file mode 100644 index 0000000..20e5d74 --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/Pagination.tsx @@ -0,0 +1,144 @@ +import React, { useState, useEffect } 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'; + +export interface PaginationProps { + activePage?: number; + itemsCountPerView?: number; + totalItemsCount: number; + showFirst?: boolean; + showLast?: boolean; + onChange?(page: number): void; + className?: string; + style?: React.CSSProperties; +} + +export const Pagination = ({ + activePage = 1, + itemsCountPerView = 10, + totalItemsCount, + showFirst = true, + showLast = true, + onChange, + className = '', + style, + ...props +}: PaginationProps) => { + const [currentPage, setCurrentPage] = useState(activePage); + const { cx, classes } = useStyles(null, { + 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]; + } + + useEffect(() => { + setCurrentPage(activePage); + }, [activePage]); + + 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); + } + }; + + const Bullet = () => { + return ( +
+ {[0, 1, 2].map((_, index) => ( +
+ ))} +
+ ); + }; + + return ( + + + + + + {currentPage > 3 && totalPage > pages.length && showFirst ? ( + <> +
handleChangePage(1)}> + 1 +
+ + + ) : null} + + {pages.map((index) => ( +
handleChangePage(index)}> + {index} +
+ ))} + + {totalPage - 2 > currentPage && totalPage > pages.length && showLast ? ( + <> + +
handleChangePage(totalPage)}> + {totalPage} +
+ + ) : null} + + + + +
+ ); +}; + +Pagination.displayName = '@co-design/core/Pagination'; diff --git a/packages/co-design-core/src/components/Pagination/index.ts b/packages/co-design-core/src/components/Pagination/index.ts new file mode 100644 index 0000000..e2b629b --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/index.ts @@ -0,0 +1,2 @@ +export { Pagination } from './Pagination'; +export type { PaginationProps } from './Pagination'; diff --git a/packages/co-design-core/src/components/Pagination/stories/Pagination.stories.tsx b/packages/co-design-core/src/components/Pagination/stories/Pagination.stories.tsx new file mode 100644 index 0000000..3f803b1 --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/stories/Pagination.stories.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Pagination } from '../Pagination'; +import { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +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; + +export const Default: Story = {}; + +export const NoShowBullet: Story = { + args: { + showFirst: false, + showLast: false, + }, +}; diff --git a/packages/co-design-core/src/components/index.ts b/packages/co-design-core/src/components/index.ts index c3732fa..7a312fd 100644 --- a/packages/co-design-core/src/components/index.ts +++ b/packages/co-design-core/src/components/index.ts @@ -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'; From b66e5bb0b4a4a70043553835312d9e2922d12420 Mon Sep 17 00:00:00 2001 From: healtheloper <58503584+healtheloper@users.noreply.github.com> Date: Mon, 14 Aug 2023 18:44:45 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Pagination=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EC=97=90=20CoComponent=20Props=20=EB=A5=BC=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=ED=96=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Pagination/Pagination.tsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/co-design-core/src/components/Pagination/Pagination.tsx b/packages/co-design-core/src/components/Pagination/Pagination.tsx index 20e5d74..58b5258 100644 --- a/packages/co-design-core/src/components/Pagination/Pagination.tsx +++ b/packages/co-design-core/src/components/Pagination/Pagination.tsx @@ -4,16 +4,28 @@ 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'; -export interface PaginationProps { +export type PaginationStylesNames = ClassNames; + +export interface PaginationProps extends CoComponentProps, Omit, 'onChange'> { + /** Pagination 의 초기 Active Page 를 설정합니다. */ activePage?: number; + + /** Pagination 의 한 페이지당 보여줄 아이템의 개수를 설정합니다. */ itemsCountPerView?: number; + + /** Pagination 의 전체 아이템의 개수를 설정합니다. */ totalItemsCount: number; + + /** 첫 페이지를 유지하여 보여주고 선택할 수 있도록 설정합니다. */ showFirst?: boolean; + + /** 마지막 페이지를 유지하여 보여주고 선택할 수 있도록 설정합니다. */ showLast?: boolean; + + /** Pagination 의 페이지를 변경했을 때 발생할 이벤트를 설정합니다. */ onChange?(page: number): void; - className?: string; - style?: React.CSSProperties; } export const Pagination = ({ @@ -25,10 +37,13 @@ export const Pagination = ({ onChange, className = '', style, + co, + overrideStyles, ...props }: PaginationProps) => { const [currentPage, setCurrentPage] = useState(activePage); const { cx, classes } = useStyles(null, { + overrideStyles, name: 'Pagination', }); @@ -81,7 +96,7 @@ export const Pagination = ({ }; return ( - + Date: Mon, 14 Aug 2023 18:56:46 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Bullet=20=EC=9D=84=20=EB=B6=84=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EA=B3=A0=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20eff?= =?UTF-8?q?ect=20=EB=A5=BC=20=EC=82=AD=EC=A0=9C=ED=96=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Pagination/Bullet.tsx | 18 ++++++++++++++++ .../src/components/Pagination/Pagination.tsx | 21 ++++--------------- 2 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 packages/co-design-core/src/components/Pagination/Bullet.tsx diff --git a/packages/co-design-core/src/components/Pagination/Bullet.tsx b/packages/co-design-core/src/components/Pagination/Bullet.tsx new file mode 100644 index 0000000..d2f9ac5 --- /dev/null +++ b/packages/co-design-core/src/components/Pagination/Bullet.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +interface BulletProps { + className?: string; + circleClassName?: string; +} + +const Bullet = ({ circleClassName, ...props }: BulletProps) => { + return ( +
+ {[0, 1, 2].map((_, index) => ( +
+ ))} +
+ ); +}; + +export default Bullet; diff --git a/packages/co-design-core/src/components/Pagination/Pagination.tsx b/packages/co-design-core/src/components/Pagination/Pagination.tsx index 58b5258..c098709 100644 --- a/packages/co-design-core/src/components/Pagination/Pagination.tsx +++ b/packages/co-design-core/src/components/Pagination/Pagination.tsx @@ -1,10 +1,11 @@ -import React, { useState, useEffect } from 'react'; +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; @@ -62,10 +63,6 @@ export const Pagination = ({ pages = [currentPage - 2, currentPage - 1, currentPage, currentPage + 1, currentPage + 2]; } - useEffect(() => { - setCurrentPage(activePage); - }, [activePage]); - const handleChangePage = (page: number) => { onChange?.(page); setCurrentPage(page); @@ -85,16 +82,6 @@ export const Pagination = ({ } }; - const Bullet = () => { - return ( -
- {[0, 1, 2].map((_, index) => ( -
- ))} -
- ); - }; - return ( handleChangePage(1)}> 1
- + ) : null} @@ -130,7 +117,7 @@ export const Pagination = ({ {totalPage - 2 > currentPage && totalPage > pages.length && showLast ? ( <> - +
handleChangePage(totalPage)}> {totalPage}