diff --git a/src/components/DataTable/DataTable.stories.mdx b/src/components/DataTable/DataTable.stories.mdx new file mode 100644 index 000000000..433b6ae5d --- /dev/null +++ b/src/components/DataTable/DataTable.stories.mdx @@ -0,0 +1,352 @@ +import { Meta, Story, ArgsTable, Canvas } from "@storybook/addon-docs/blocks"; +import DataTable from "./DataTable"; +import Button from "../Button"; +import { data } from "./data"; + + + +# DataTable + + + +## Samples + +### Basic + + + + {(args) => ( + data.id, + }, + { + name: "Impression", + selector: (data) => data.imp, + }, + { + name: "Created at", + selector: (data) => data.created_at, + }, + ]} + {...args} + /> + )} + + + +### With vertical line + + + + {(args) => ( + data.id, + }, + { + name: "Impression", + selector: (data) => data.imp, + }, + { + name: "Created at", + selector: (data) => data.created_at, + }, + ]} + {...args} + /> + )} + + + +### With pagination + + + + {(args) => ( + data.id, + sortable: true, + }, + { + name: "Impression", + selector: (data) => data.imp, + sortable: true, + }, + ]} + {...args} + /> + )} + + + +### With sticky header + + + + {(args) => ( + data.id, + sortable: true, + }, + { + name: "Impression", + selector: (data) => data.imp, + sortable: true, + }, + ]} + {...args} + /> + )} + + + +### WithTabs + + + + {(args) => ( + data, + }, + { + label: "imp odd", + filter: (data) => data.filter((item) => item.imp % 2 !== 0), + }, + { + label: "imp even", + filter: (data) => data.filter((item) => item.imp % 2 === 0), + }, + { + label: "empty", + filter: () => [], + }, + ]} + data={data} + columns={[ + { + name: "ID", + selector: (data) => data.id, + }, + { + name: "Impression", + selector: (data) => data.imp, + sortable: true, + }, + { + name: "Created at", + selector: (data) => data.created_at, + sortable: true, + }, + ]} + {...args} + /> + )} + + + +### Selectable with checkbox + + + + {(args) => { + const [selectedRows, setSelectedRows] = React.useState([]); + const handleClick = () => { + alert(selectedRows.join(",")); + }; + return ( + <> + + data.id, + }, + { + name: "Impression", + selector: (data) => data.imp, + sortable: true, + }, + { + name: "Created at", + selector: (data) => data.created_at, + sortable: true, + }, + ]} + onSelectRowsChange={setSelectedRows} + {...args} + /> + + ); + }} + + + +### Selectable with radio button + + + + {(args) => { + const [selectedRow, setSelectedRow] = React.useState(); + const handleClick = () => { + alert(selectedRow.join(",")); + }; + return ( + <> + + data.id, + }, + { + name: "Impression", + selector: (data) => data.imp, + sortable: true, + }, + { + name: "Created at", + selector: (data) => data.created_at, + sortable: true, + }, + ]} + onRadioChange={setSelectedRow} + {...args} + /> + + ); + }} + + + +### Custom cell + + + + {(args) => ( + data.id, + sortable: true, + }, + { + name: "Impression", + selector: (data) => data.imp, + renderCell: (data) => ( +
{data.imp}
+ ), + sortable: true, + }, + ]} + {...args} + /> + )} +
+
+ +### With row span + + + + {(args) => { + const [selectedRows, setSelectedRows] = React.useState([]); + const handleClick = () => { + alert(selectedRows.join(",")); + }; + // MEMO: Need to sort data yourself. + const sampleDataWithDuplicateId = [ + { id: 1, name: "2name", count: 8 }, + { id: 1, name: "2name", count: 4 }, + { id: 1, name: "2name", count: 3 }, + { id: 2, name: "2name", count: 8 }, + { id: 3, name: "3name", count: 7 }, + { id: 5, name: "5name", count: 5 }, + ]; + return ( + <> + + data.id, + enableMergeCell: true, + }, + { + name: "name", + selector: (data) => data.name, + sortable: true, + enableMergeCell: true, + }, + { + name: "count", + selector: (data) => data.count, + // MEMO: Cannot use sort when using "enableMergeCall" + sortable: true, + }, + ]} + onSelectRowsChange={setSelectedRows} + {...args} + /> + + ); + }} + + + +### Empty + + + + {(args) => ( + data.id, + }, + ]} + {...args} + /> + )} + + diff --git a/src/components/DataTable/DataTable.stories.tsx b/src/components/DataTable/DataTable.stories.tsx deleted file mode 100644 index 2b1856b32..000000000 --- a/src/components/DataTable/DataTable.stories.tsx +++ /dev/null @@ -1,484 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import DataTable from "./"; -import Button from "../Button"; -import Flex from "../Flex"; -import Spacer from "../Spacer"; -import Icon from "../Icon"; -import TextField from "../TextField"; -import Typography from "../Typography"; -import ActionButton from "../ActionButton"; -import { data } from "./data"; -import { Column } from "./DataTable"; -import { useTheme } from "../../themes/useTheme"; -import { select, boolean, text } from "@storybook/addon-knobs"; -import FloatingTip from "../FloatingTip"; - -export default { - title: "Components/Data Display/DataTable", - component: DataTable, - parameters: { - docs: { page: null }, - }, -}; - -const Container = styled.div` - padding: ${({ theme }) => theme.spacing * 3}px; - background-color: ${({ theme }) => theme.palette.background.default}; -`; - -const Content = styled.div` - width: 300px; -`; - -type SampleObject = { - id: number; - name: string; - count: number; -}; - -const sampleData: SampleObject[] = [ - { id: 1, name: "1name", count: 4 }, - { id: 2, name: "2name", count: 8 }, - { id: 3, name: "3name", count: 7 }, - { id: 4, name: "4name", count: 6 }, - { id: 5, name: "5name", count: 5 }, - { id: 6, name: "6name", count: 4 }, - { id: 7, name: "7name", count: 3 }, - { id: 8, name: "8name", count: 2 }, - { id: 9, name: "9name", count: 1 }, - { id: 10, name: "9name", count: 1 }, - { id: 11, name: "9name", count: 2 }, - { id: 12, name: "9name", count: 2 }, - { id: 13, name: "9name", count: 3 }, - { id: 14, name: "9name", count: 3 }, -]; - -export const Overview = () => { - const verticalSpacing = select( - "VerticalSpacing", - { - Small: "small", - Medium: "medium", - Large: "large", - }, - "medium", - ); - const fullWidth = boolean("FullWidth", false); - const tableMaxHeight = text("TableMaxHeight", "none"); - return ( - - data.id, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - { - name: "カウント", - selector: (data) => data.count, - sortable: true, - align: "right", - }, - ]} - /> - - ); -}; - -export const WithRowSpan = () => { - const [selectedRows, setSelectedRows] = React.useState([]); - const handleClick = () => { - alert(selectedRows.join(",")); - }; - // MEMO: Need to sort data yourself. - const sampleDataWithDuplicateId: SampleObject[] = [ - { id: 1, name: "1name", count: 9 }, - { id: 1, name: "1name", count: 3 }, - { id: 1, name: "1name", count: 4 }, - { id: 1, name: "2name", count: 9 }, - { id: 1, name: "2name", count: 8 }, - { id: 1, name: "2name", count: 4 }, - { id: 1, name: "2name", count: 3 }, - { id: 2, name: "2name", count: 8 }, - { id: 3, name: "3name", count: 7 }, - { id: 4, name: "4name", count: 6 }, - { id: 5, name: "5name", count: 5 }, - { id: 6, name: "6name", count: 4 }, - ]; - return ( - - - data.id, - }, - { - name: "名前", - selector: (data) => data.name, - enableMergeCell: true, - sortable: true, - }, - { - name: "カウント", - selector: (data) => data.count, - // MEMO: Cannot use sort when using "enableMergeCall" - sortable: true, - align: "right", - }, - ]} - onSelectRowsChange={setSelectedRows} - /> - - ); -}; - -export const WithPagination = () => ( - - data.id, - sortable: true, - }, - { - name: "imp", - selector: (data) => data.imp, - sortable: true, - }, - ]} - /> - -); - -export const WithStickyHeader = () => ( - - data.id, - sortable: true, - }, - { - name: "imp", - selector: (data) => data.imp, - sortable: true, - }, - ]} - /> - -); - -export const WithTabs = () => ( - - data, - }, - { - label: "1~4", - filter: (data) => data.filter((item) => item.id < 5), - }, - { - label: "5~", - filter: (data) => data.filter((item) => item.id >= 5), - }, - { - label: "empty data", - filter: () => [], - }, - ]} - data={sampleData} - columns={[ - { - name: "ID", - selector: (data) => data.id, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - { - name: "カウント", - selector: (data) => data.count, - sortable: true, - align: "right", - }, - ...[...Array(10)].map((_, i) => ({ - name: `サンプル列${i}`, - selector: () => `${i}`, - })), - ]} - /> - -); - -export const WithSearch: React.FunctionComponent = () => { - const [searchText, setSearchText] = React.useState(""); - const searchedItems = sampleData.filter( - (item) => item.name && item.name.includes(searchText), - ); - const handleInput = (event: React.ChangeEvent) => { - setSearchText(event.target.value); - }; - return ( - - - data.id, - sortable: true, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - ]} - /> - - ); -}; - -export const SelectableRows: React.FunctionComponent = () => { - const [selectedRows, setSelectedRows] = React.useState([]); - const handleClick = () => { - alert(selectedRows.join(",")); - }; - return ( - - - data, - }, - { - label: "1~4", - filter: (data) => data.filter((item) => item.id < 5), - }, - { - label: "5~", - filter: (data) => data.filter((item) => item.id >= 5), - }, - { - label: "empty", - filter: () => [], - }, - ]} - columns={[ - { - name: "ID", - selector: (data) => data.id, - sortable: true, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - ]} - onSelectRowsChange={setSelectedRows} - /> - - ); -}; - -export const SelectableRow: React.FunctionComponent = () => { - const [selectedRow, setSelectedRow] = React.useState(); - const handleClick = () => { - alert(selectedRow); - }; - return ( - - - data.id, - sortable: true, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - ]} - onRadioChange={setSelectedRow} - /> - - ); -}; - -export const CustomCell: React.FunctionComponent = () => { - const theme = useTheme(); - - const [ - iconWrapperElement, - setIconWrapperElement, - ] = React.useState(null); - const [isOpen, setIsOpen] = React.useState(false); - const handleIsOpen = (isOpen: boolean) => () => { - setIsOpen(isOpen); - }; - - const columns: Column<{ id: number; imp: number }>[] = React.useMemo( - () => [ - { - name: "ID", - selector: (data) => data.id, - sortable: true, - }, - { - name: "imp", - selector: (data) => data.imp, - sortable: true, - renderCell: (data) => ( - - - - - {data.imp} - - ), - }, - { - name: "操作", - selector: (data) => data.id, - headerCell: ( - <> - - 操作 - -
- -
-
- - - - こんな感じで入れられます - - - - - ), - renderCell: () => ( - - - 変更 - - 削除 - - ), - }, - ], - [isOpen, iconWrapperElement, theme.palette.primary.main], - ); - return ( - - - - ); -}; - -export const WithenableRuledLine = () => ( - - data.id, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - { - name: "カウント", - selector: (data) => data.count, - sortable: true, - }, - ]} - /> - -); - -export const WithEmptyTable = () => { - const columns: Column<{ id: number; name: string; count: number }>[] = [ - { - name: "ID", - selector: (data) => data.id, - }, - { - name: "名前", - selector: (data) => data.name, - sortable: true, - }, - { - name: "カウント", - selector: (data) => data.count, - sortable: true, - align: "right", - }, - ]; - - return ( - - - - ); -}; diff --git a/src/components/DataTable/DataTable.tsx b/src/components/DataTable/DataTable.tsx index f6894ac14..36bbec2a1 100644 --- a/src/components/DataTable/DataTable.tsx +++ b/src/components/DataTable/DataTable.tsx @@ -144,19 +144,65 @@ type Tab = { }; export type DataTableProps = { + /** + * Array of some object that has `id: number` property. + */ data: T[]; + /** + * Define column of table. Please refer to the samples below. + */ columns: Column[]; enablePagination?: boolean; + /** + * Enable to use checkbox in table. + * The argument `rows` is array of `id: number` defined in `data` props. + * **Don't use with `onRadioChange={true}`** + */ onSelectRowsChange?: (rows: number[]) => void; + /** + * Enable to use radio button in table. + * The argument `radio` is `id: number` defined in `data` props. + * **Don't use with `onSelectRowsChange={true}`** + */ onRadioChange?: (radio: number) => void; + /** + * Reset selected checkboxes when this props changed to `true`. + */ clearSelectedRows?: boolean; + /** + * Define tabs of table. Please refer to the samples below. + */ tabs?: Tab[]; + /** + * props of [ItemEnpty](/?path=/docs/components-utils-itemempty) + */ itemEmptyProps?: ItemEmptyProps; - per?: number; // perが指定されている場合、初期値がそれに強制されます + /** + * Number of rows per page when `enablePagination={true}`. + * If `undefined` it, `dlc` of localStorage is referenced. + */ + per?: number; + /** + * If defined `name: string` of `Column` it, enable to specify default sort Field. + * **Please use `sortable: true` in `columns` props.** + */ defaultSortField?: string; + /** + * Specify default sort order. + * **Please use `sortable: true` in `columns` props.** + */ defaultSortOrder?: "desc" | "asc"; + /** + * Add verticale line in table. + */ enableRuledLine?: boolean; + /** + * Define vertical padding of rows. + */ verticalSpacing?: VerticalSpacing; + /** + * If `true` it, hidden both side border. + */ fullWidth?: boolean; tableMaxHeight?: string; horizontalScrollable?: boolean; diff --git a/src/components/DataTable/__tests__/__snapshots__/DataTable.test.tsx.snap b/src/components/DataTable/__tests__/__snapshots__/DataTable.test.tsx.snap index 2d71fc2b9..76ab8c111 100644 --- a/src/components/DataTable/__tests__/__snapshots__/DataTable.test.tsx.snap +++ b/src/components/DataTable/__tests__/__snapshots__/DataTable.test.tsx.snap @@ -6,7 +6,7 @@ exports[`DataTable component testing DataTable 1`] = ` class="sc-bdfBwQ fVMqjX" >
` border: ${({ fullWidth, theme }) => fullWidth ? "none" : `1px solid ${theme.palette.divider}`}; border-top: 1px solid ${({ theme }) => theme.palette.divider}; + border-bottom: 1px solid ${({ theme }) => theme.palette.divider}; border-radius: ${({ fullWidth, theme }) => fullWidth ? "none" : `${theme.radius}px`}; `; diff --git a/src/components/Divider/Divider.stories.mdx b/src/components/Divider/Divider.stories.mdx new file mode 100644 index 000000000..10966d1a5 --- /dev/null +++ b/src/components/Divider/Divider.stories.mdx @@ -0,0 +1,61 @@ +import { Meta, Story, ArgsTable, Canvas } from "@storybook/addon-docs/blocks"; +import Divider from "./Divider"; + + + +# Divider + +`` is wrapper of `
` tag that separate content into clear groups. + + + +## Samples + +### Normal + + + + {(args) => } + + + +### With space + +It can define margin and padding like [``](/?path=/docs/components-layout-spacer--example). + + + + {(args) => } + + + +### Override Color + + + + {(args) => } + + + +### vertical + + + + {(args) => ( +
+ +
+ )} +
+
diff --git a/src/components/Divider/Divider.stories.tsx b/src/components/Divider/Divider.stories.tsx deleted file mode 100644 index 03dbf8f21..000000000 --- a/src/components/Divider/Divider.stories.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import * as React from "react"; -import styled from "styled-components"; -import Divider from "."; -import Typography from "../Typography"; -import Spacer from "../Spacer"; -import Flex from "../Flex"; - -const Container = styled.div` - padding: ${({ theme }) => theme.spacing * 3}px; - background-color: ${({ theme }) => theme.palette.background.dark}; -`; - -const RowContainer = styled.div` - margin: ${({ theme }) => theme.spacing * 3}px; - padding: ${({ theme }) => theme.spacing * 3}px 0; - background-color: ${({ theme }) => theme.palette.background.default}; -`; - -export default { - title: "Components/Data Display/Divider", - component: Divider, - parameters: { - docs: { page: null }, - }, -}; - -export const Overview = () => ( - - - Normal - - - - - - With Space - - - - - - *It can define margin and padding like "Spacer" component. - - - - - Override Color - - - - - - - - - - Vertical - - - -
- -
- - - -); diff --git a/src/components/FixedPanel/FixedPanel.stories.mdx b/src/components/FixedPanel/FixedPanel.stories.mdx index 564e2f216..ffefacb4d 100644 --- a/src/components/FixedPanel/FixedPanel.stories.mdx +++ b/src/components/FixedPanel/FixedPanel.stories.mdx @@ -35,13 +35,13 @@ Usage example is included in ”Canvas” Tab at header. React.useEffect(() => { if (!buttonContainerRef.current) return; const observer = new IntersectionObserver((entries) => { - setIsOpen(!entries[0].isIntersecting); + if (args.isOpen) setIsOpen(!entries[0].isIntersecting); }); observer.observe(buttonContainerRef.current); return () => { observer.disconnect(); }; - }, [buttonContainerRef]); + }, [buttonContainerRef, args]); const handleClick = () => { setIsOpen(!isOpen); };