Skip to content

Commit

Permalink
[Feature] 테이블 컴포넌트 구현 (#134)
Browse files Browse the repository at this point in the history
* feat: TableContainer 생성

* fix: 스토리북 문서 생성

* feat: Table 기본 CSS 적용

* feat: checkbox 생성

* feat:header checkbox body checkbox 구분 로직 생성

* feat: checkbox context 생성

* fix: table tree 방식 파괴

* feat: 체크박스 기능 추가

* feat: 체크박스 기능 생성

* feat: 체크박스 기능 추가

* feat: 선택시 배경 색상 변경

* fix: table 컴포넌트 접근성 관련 처리

* feat: table 컴포넌트 props 명확히 정리

* feat: 스토리북 문서 작성

* fix: rollup, package.json 설정 변경

* feat: 스크롤 가능한 table로 개선

* fix: 스토리북 문서화 잘못 되어 있는 부분 수정

* refac: 테이블 컴포넌트 합성 컴포넌트로 변경

* fix: Table 코드 깔끔하게 정리

* fix: 스타일 수정 사항 반영

* fix: 사용하지 않는 컨테이너 컴포넌트 제거

* fix: 패키지 버전 변경

* fix: 코드리뷰 반영

* fix: 코드리뷰 반영

* fix: changeset 작성, UI 어긋난 부분 수정

* fix: 코드리뷰 반영

* fix: 코드리뷰 반영 및 chagneset 반영

* fix: 스타일 카멜케이스 변경
  • Loading branch information
eugene028 authored Oct 24, 2024
1 parent 4fe76a4 commit 0583f9d
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 156 deletions.
5 changes: 5 additions & 0 deletions .changeset/weak-phones-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wowds-ui": patch
---

table 컴포넌트를 배포해요.
40 changes: 20 additions & 20 deletions packages/wow-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@
"require": "./dist/Tag.cjs",
"import": "./dist/Tag.js"
},
"./TabsContent": {
"types": "./dist/components/Tabs/TabsContent.d.ts",
"require": "./dist/TabsContent.cjs",
"import": "./dist/TabsContent.js"
},
"./TabsItem": {
"types": "./dist/components/Tabs/TabsItem.d.ts",
"require": "./dist/TabsItem.cjs",
"import": "./dist/TabsItem.js"
},
"./TabsList": {
"types": "./dist/components/Tabs/TabsList.d.ts",
"require": "./dist/TabsList.cjs",
"import": "./dist/TabsList.js"
},
"./Tabs": {
"types": "./dist/components/Tabs/index.d.ts",
"require": "./dist/Tabs.cjs",
"import": "./dist/Tabs.js"
},
"./Table": {
"types": "./dist/components/Table/Table.d.ts",
"require": "./dist/Table.cjs",
Expand Down Expand Up @@ -80,26 +100,6 @@
"require": "./dist/Tr.cjs",
"import": "./dist/Tr.js"
},
"./Tabs": {
"types": "./dist/components/Tabs/index.d.ts",
"require": "./dist/Tabs.cjs",
"import": "./dist/Tabs.js"
},
"./TabsContent": {
"types": "./dist/components/Tabs/TabsContent.d.ts",
"require": "./dist/TabsContent.cjs",
"import": "./dist/TabsContent.js"
},
"./TabsItem": {
"types": "./dist/components/Tabs/TabsItem.d.ts",
"require": "./dist/TabsItem.cjs",
"import": "./dist/TabsItem.js"
},
"./TabsList": {
"types": "./dist/components/Tabs/TabsList.d.ts",
"require": "./dist/TabsList.cjs",
"import": "./dist/TabsList.js"
},
"./Switch": {
"types": "./dist/components/Switch/index.d.ts",
"require": "./dist/Switch.cjs",
Expand Down
8 changes: 4 additions & 4 deletions packages/wow-ui/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ export default {
TextField: "./src/components/TextField",
TextButton: "./src/components/TextButton",
Tag: "./src/components/Tag",
TabsContent: "./src/components/Tabs/TabsContent",
TabsItem: "./src/components/Tabs/TabsItem",
TabsList: "./src/components/Tabs/TabsList",
Tabs: "./src/components/Tabs",
Table: "./src/components/Table/Table",
Tbody: "./src/components/Table/Tbody",
Td: "./src/components/Table/Td",
Th: "./src/components/Table/Th",
Thead: "./src/components/Table/Thead",
Tr: "./src/components/Table/Tr",
Tabs: "./src/components/Tabs",
TabsContent: "./src/components/Tabs/TabsContent",
TabsItem: "./src/components/Tabs/TabsItem",
TabsList: "./src/components/Tabs/TabsList",
Switch: "./src/components/Switch",
Stepper: "./src/components/Stepper",
BlueSpinner: "./src/components/Spinner/BlueSpinner",
Expand Down
64 changes: 0 additions & 64 deletions packages/wow-ui/src/components/Table/Table.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { styled } from "@styled-system/jsx";
import { useState } from "react";

import Button from "@/components/Button";
import Pagination from "@/components/Pagination";
import Table from "@/components/Table/Table";

const meta = {
Expand Down Expand Up @@ -318,66 +317,3 @@ const ControlledTable = () => {
export const ControlledTableState: Story = {
render: () => <ControlledTable />,
};

const TableWithPaginationComponent = () => {
const [selectedPage, setSelectedPage] = useState<number>(1);

const handleSelectionChange = (page: number) => {
setSelectedPage(page);
};

const data = [
{ id: 1, name: "김유진", studyId: "C035087", birth: "2000" },
{ id: 2, name: "이영지", studyId: "C023456", birth: "2001" },
{ id: 3, name: "모다니", studyId: "C045678", birth: "2005" },
{ id: 4, name: "민지", studyId: "C122222", birth: "2004" },
{ id: 5, name: "하니", studyId: "C133333", birth: "2004" },
{ id: 6, name: "다니엘", studyId: "C144444", birth: "2005" },
{ id: 7, name: "해린", studyId: "C155555", birth: "2006" },
{ id: 8, name: "혜인", studyId: "C166666", birth: "2008" },
{ id: 9, name: "카리나", studyId: "C177777", birth: "2000" },
{ id: 10, name: "윈터", studyId: "C188888", birth: "2001" },
{ id: 11, name: "지젤", studyId: "C199999", birth: "2000" },
{ id: 12, name: "이서", studyId: "C200000", birth: "2007" },
{ id: 13, name: "장원영", studyId: "C211111", birth: "2004" },
{ id: 14, name: "안유진", studyId: "C222222", birth: "2003" },
];

const itemsPerPage = 5;
const totalPages = Math.ceil(data.length / itemsPerPage);

const currentData = data.slice(
(selectedPage - 1) * itemsPerPage,
selectedPage * itemsPerPage
);

return (
<div style={{ display: "flex", flexDirection: "column", gap: "10px" }}>
<Table>
<Table.Thead>
<Table.Th>이름</Table.Th>
<Table.Th>학번</Table.Th>
</Table.Thead>
<Table.Tbody>
{currentData.map(({ name, studyId, id }) => {
return (
<Table.Tr key={id} value={id}>
<Table.Td>{name}</Table.Td>
<Table.Td>{studyId}</Table.Td>
</Table.Tr>
);
})}
</Table.Tbody>
</Table>
<Pagination
currentPage={selectedPage}
totalPages={totalPages}
onChange={handleSelectionChange}
/>
</div>
);
};

export const TableWithPagination: Story = {
render: () => <TableWithPaginationComponent />,
};
26 changes: 14 additions & 12 deletions packages/wow-ui/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@
import { css, cva } from "@styled-system/css";
import { styled } from "@styled-system/jsx";
import { clsx } from "clsx";
import type { CSSProperties, ReactNode, Ref } from "react";
import { forwardRef } from "react";
import type { CSSProperties, Dispatch, ReactNode, Ref } from "react";
import { forwardRef, useState } from "react";

import { TableContext } from "@/components/Table/TableContext";
import Tbody from "@/components/Table/Tbody";
import Td from "@/components/Table/Td";
import Th from "@/components/Table/Th";
import Thead from "@/components/Table/Thead";
import Tr from "@/components/Table/Tr";
import useCountRow from "@/hooks/useCountRow";
import useTableCheckState from "@/hooks/useTableCheckState";
import type { TableComponentType } from "@/types/table";

Expand Down Expand Up @@ -39,7 +38,7 @@ export interface TableProps {
}

const TableComponent = forwardRef<HTMLTableElement, TableProps>(
function TableFunction(
(
{
tableCaption = "",
children,
Expand All @@ -52,30 +51,33 @@ const TableComponent = forwardRef<HTMLTableElement, TableProps>(
...rest
}: TableProps,
ref: Ref<HTMLTableElement>
) {
const { rowValues } = useCountRow(children);
) => {
const [rowValues, setRowValues] = useState<Set<number>>(new Set());
const {
handleRowCheckboxChange,
handleHeaderCheckboxChange,
selectedRows,
} = useTableCheckState(rowValues, selectedRowsProp, onChange);

const contextValue: ReturnType<typeof useTableCheckState> &
Omit<TableProps, "children"> & { rowValues: number[] } = {
Omit<TableProps, "children"> & {
rowValues?: Set<number>;
setRowValues?: Dispatch<React.SetStateAction<Set<number>>>;
} = {
rowValues,
selectedRows,
setRowValues,
showCheckbox,
handleRowCheckboxChange,
handleHeaderCheckboxChange,
};

return (
<TableContext.Provider value={contextValue}>
<div className={TableContainerStyle} style={style}>
<div className={tableContainerStyle} style={style}>
<styled.table
aria-label="table"
aria-labelledby="table"
className={clsx(TableStyle({ fullWidth }), className)}
className={clsx(tableStyle({ fullWidth }), className)}
ref={ref}
role="table"
{...rest}
Expand Down Expand Up @@ -106,7 +108,7 @@ Table.Td = Td;

export default Table;

const TableStyle = cva({
const tableStyle = cva({
base: {
borderCollapse: "collapse",
backgroundColor: "white",
Expand All @@ -124,7 +126,7 @@ const TableStyle = cva({
},
});

const TableContainerStyle = css({
const tableContainerStyle = css({
overflow: "auto",
position: "relative",
_scrollbar: {
Expand Down
12 changes: 11 additions & 1 deletion packages/wow-ui/src/components/Table/TableContext.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import type { Dispatch } from "react";
import { createContext } from "react";

import type { TableProps } from "@/components/Table/Table";
import useSafeContext from "@/hooks/useSafeContext";
import type useTableCheckState from "@/hooks/useTableCheckState";

export const TableContext = createContext<any>(null);
export const TableContext = createContext<
| (ReturnType<typeof useTableCheckState> &
Omit<TableProps, "children"> & {
rowValues?: Set<number>;
setRowValues?: Dispatch<React.SetStateAction<Set<number>>>;
})
| null
>(null);

export const useTableContext = () => {
const context = useSafeContext(TableContext);
Expand Down
11 changes: 6 additions & 5 deletions packages/wow-ui/src/components/Table/Td.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { cva } from "@styled-system/css";
import { styled } from "@styled-system/jsx";
import type { CSSProperties, PropsWithChildren, Ref } from "react";
import { forwardRef, useContext } from "react";
import { forwardRef } from "react";

import {
TableCheckedContext,
useTableContext,
} from "@/components/Table/TableContext";
import useSafeContext from "@/hooks/useSafeContext";

interface TableCellProps extends PropsWithChildren {
style?: CSSProperties;
Expand All @@ -17,12 +18,12 @@ const Td = forwardRef(
(props: TableCellProps, ref: Ref<HTMLTableCellElement>) => {
const { children, ...rest } = props;
const { selectedRows } = useTableContext();
const value = useContext(TableCheckedContext);
const isSelected = selectedRows.some((row: number) => row === value);
const rowValue = useSafeContext(TableCheckedContext);
const isSelected = selectedRows.has(rowValue);

return (
<styled.td
className={TableCellStyle({ checked: isSelected })}
className={tableCellStyle({ checked: isSelected })}
ref={ref}
role="cell"
{...rest}
Expand All @@ -33,7 +34,7 @@ const Td = forwardRef(
}
);

const TableCellStyle = cva({
const tableCellStyle = cva({
base: {
maxWidth: "300px",
paddingX: "sm",
Expand Down
4 changes: 2 additions & 2 deletions packages/wow-ui/src/components/Table/Th.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ const Th = forwardRef<HTMLTableCellElement, TableHeaderProps>(
(props: TableHeaderProps, ref: Ref<HTMLTableCellElement>) => {
const { children, ...rest } = props;
return (
<th className={TableHeaderStyle} ref={ref} {...rest}>
<th className={tableHeaderStyle} ref={ref} scope="col" {...rest}>
{children}
</th>
);
}
);

const TableHeaderStyle = css({
const tableHeaderStyle = css({
alignItems: "center",
backgroundColor: "backgroundAlternative",
color: "sub",
Expand Down
11 changes: 4 additions & 7 deletions packages/wow-ui/src/components/Table/Thead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ interface TheadProps extends PropsWithChildren {
}

const Thead = forwardRef<HTMLTableSectionElement, TheadProps>(
function TheadFunction(
{ children, ...rest }: TheadProps,
ref: Ref<HTMLTableSectionElement>
) {
({ children, ...rest }: TheadProps, ref: Ref<HTMLTableSectionElement>) => {
const {
selectedRows,
showCheckbox,
Expand All @@ -24,7 +21,7 @@ const Thead = forwardRef<HTMLTableSectionElement, TheadProps>(
} = useTableContext();

const isHeaderCheckboxChecked =
selectedRows.length === rowValues.length && rowValues.length > 0;
selectedRows.size === rowValues?.size && rowValues.size > 0;
return (
<styled.thead
position="sticky"
Expand All @@ -36,7 +33,7 @@ const Thead = forwardRef<HTMLTableSectionElement, TheadProps>(
>
<tr>
{showCheckbox && (
<Th style={TableCheckBoxStyle}>
<Th style={tableCheckBoxStyle}>
<Checkbox
checked={isHeaderCheckboxChecked}
onChange={handleHeaderCheckboxChange}
Expand All @@ -52,7 +49,7 @@ const Thead = forwardRef<HTMLTableSectionElement, TheadProps>(

export default Thead;

const TableCheckBoxStyle = {
const tableCheckBoxStyle = {
minWidth: "15px",
display: "flex",
minHeight: "44px",
Expand Down
Loading

0 comments on commit 0583f9d

Please sign in to comment.