diff --git a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx index 7fbc483..b79c313 100644 --- a/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx +++ b/packages/lsd-react/src/components/CSSBaseline/CSSBaseline.tsx @@ -18,7 +18,14 @@ import { IconButtonStyles } from '../IconButton/IconButton.styles' import { LsdIconStyles } from '../Icons/LsdIcon/LsdIcon.styles' import { ListBoxStyles } from '../ListBox/ListBox.styles' import { QuoteStyles } from '../Quote/Quote.styles' +import { RadioButtonStyles } from '../RadioButton/RadioButton.styles' +import { RadioButtonGroupStyles } from '../RadioButtonGroup/RadioButtonGroup.styles' import { TabItemStyles } from '../TabItem/TabItem.styles' +import { TableStyles } from '../Table/Table.styles' +import { TableBodyStyles } from '../TableBody/TableBody.styles' +import { TableHeaderStyles } from '../TableHeader/TableHeader.styles' +import { TableItemStyles } from '../TableItem/TableItem.styles' +import { TableRowStyles } from '../TableRow/TableRow.styles' import { TabsStyles } from '../Tabs/Tabs.styles' import { TagStyles } from '../Tag/Tag.styles' import { TextFieldStyles } from '../TextField/TextField.styles' @@ -50,6 +57,13 @@ const componentStyles: Array | SerializedStyles> = CollapseHeaderStyles, CheckboxGroupStyles, BadgeStyles, + RadioButtonStyles, + RadioButtonGroupStyles, + TableStyles, + TableHeaderStyles, + TableBodyStyles, + TableItemStyles, + TableRowStyles, ] export const CSSBaseline: React.FC<{ theme?: Theme }> = ({ diff --git a/packages/lsd-react/src/components/Icons/RemoveIcon/RemoveIcon.tsx b/packages/lsd-react/src/components/Icons/RemoveIcon/RemoveIcon.tsx new file mode 100644 index 0000000..40b790c --- /dev/null +++ b/packages/lsd-react/src/components/Icons/RemoveIcon/RemoveIcon.tsx @@ -0,0 +1,20 @@ +import { LsdIcon } from '../LsdIcon' + +export const RemoveIcon = LsdIcon( + (props) => ( + + + + ), + { filled: true }, +) diff --git a/packages/lsd-react/src/components/Icons/RemoveIcon/index.ts b/packages/lsd-react/src/components/Icons/RemoveIcon/index.ts new file mode 100644 index 0000000..d11148b --- /dev/null +++ b/packages/lsd-react/src/components/Icons/RemoveIcon/index.ts @@ -0,0 +1 @@ +export * from './RemoveIcon' diff --git a/packages/lsd-react/src/components/Icons/index.ts b/packages/lsd-react/src/components/Icons/index.ts index 40d3d8f..06fe2af 100644 --- a/packages/lsd-react/src/components/Icons/index.ts +++ b/packages/lsd-react/src/components/Icons/index.ts @@ -19,3 +19,4 @@ export * from './SearchIcon' export * from './PickIcon' export * from './RadioButtonIcon' export * from './RadioButtonFilledIcon' +export * from './RemoveIcon' diff --git a/packages/lsd-react/src/components/Table/Table.classes.ts b/packages/lsd-react/src/components/Table/Table.classes.ts new file mode 100644 index 0000000..ad76039 --- /dev/null +++ b/packages/lsd-react/src/components/Table/Table.classes.ts @@ -0,0 +1,7 @@ +export const tableClasses = { + root: `lsd-table`, + + small: 'lsd-table--small', + medium: 'lsd-table--medium', + large: 'lsd-table--large', +} diff --git a/packages/lsd-react/src/components/Table/Table.context.ts b/packages/lsd-react/src/components/Table/Table.context.ts new file mode 100644 index 0000000..132d11e --- /dev/null +++ b/packages/lsd-react/src/components/Table/Table.context.ts @@ -0,0 +1,14 @@ +import React from 'react' +import { DropdownOption } from '../Dropdown' +import { TableProps } from './Table' + +export type TableContextType = { + size?: TableProps['size'] + type?: 'default' | 'checkbox' | 'radio' + value?: string + headerOptions?: DropdownOption[] +} + +export const TableContext = React.createContext(null as any) + +export const useTableContext = () => React.useContext(TableContext) diff --git a/packages/lsd-react/src/components/Table/Table.stories.tsx b/packages/lsd-react/src/components/Table/Table.stories.tsx new file mode 100644 index 0000000..ced4e17 --- /dev/null +++ b/packages/lsd-react/src/components/Table/Table.stories.tsx @@ -0,0 +1,126 @@ +import { Meta, Story } from '@storybook/react' +import { useState } from 'react' +import { Button } from '../Button' +import { Dropdown } from '../Dropdown' +import { IconButton } from '../IconButton' +import { AddIcon, RemoveIcon } from '../Icons' +import { TableItem } from '../TableItem' +import { TableRow } from '../TableRow' +import { Table, TableProps } from './Table' + +export default { + title: 'Table', + component: Table, + argTypes: { + size: { + type: { + name: 'enum', + value: ['small', 'medium', 'large'], + }, + }, + type: { + type: { + name: 'enum', + value: ['default', 'checkbox', 'radio'], + }, + }, + }, +} as Meta + +const content = ( + + Content 1 + Content 2 + Content 3 + Content 4 + Content 5 + Content 6 + Content 7 + Content 8 + +) + +const header = ( +
+
Table header
+
Table description
+
+) + +const headerOptions = new Array(8).fill(null).map((value, index) => ({ + value: `${index}`, + name: `Title ${index + 1}`, +})) + +export const Root: Story = ({ type, ...args }) => { + const [rows, setRows] = useState(1) + + const toolbar = ( + <> + +
+ setRows((prev: number) => prev + 1)} + size="small" + > + + + + setRows((prev: number) => (prev > 1 ? prev - 1 : prev)) + } + size="small" + > + + + +
+ + ) + + return ( +
+ + + {headerOptions.map((item) => ( + {item.name} + ))} + + {Array(rows) + .fill(true) + .map(() => content)} +
+
+ ) +} + +Root.args = { + size: 'large', + type: 'default', +} diff --git a/packages/lsd-react/src/components/Table/Table.styles.ts b/packages/lsd-react/src/components/Table/Table.styles.ts new file mode 100644 index 0000000..d1bbcb4 --- /dev/null +++ b/packages/lsd-react/src/components/Table/Table.styles.ts @@ -0,0 +1,24 @@ +import { css } from '@emotion/react' +import { tableHeaderClasses } from '../TableHeader/TableHeader.classes' +import { tableClasses } from './Table.classes' + +export const TableStyles = css` + .${tableClasses.root} { + box-sizing: border-box; + display: flex; + flex-direction: column; + } + + .${tableClasses.root} > .${tableHeaderClasses.root} { + margin-bottom: -1px; + } + + .${tableClasses.large} { + } + + .${tableClasses.medium} { + } + + .${tableClasses.small} { + } +` diff --git a/packages/lsd-react/src/components/Table/Table.tsx b/packages/lsd-react/src/components/Table/Table.tsx new file mode 100644 index 0000000..5b4c190 --- /dev/null +++ b/packages/lsd-react/src/components/Table/Table.tsx @@ -0,0 +1,40 @@ +import clsx from 'clsx' +import React, { useState } from 'react' +import { DropdownOption } from '../Dropdown' +import { TableBody } from '../TableBody' +import { TableHeader } from '../TableHeader' +import { tableClasses } from './Table.classes' +import { TableContext } from './Table.context' + +export type TableProps = Omit, 'label'> & { + size?: 'small' | 'medium' | 'large' + type?: 'default' | 'checkbox' | 'radio' + headerOptions?: DropdownOption[] + header?: React.ReactNode + toolbar?: React.ReactNode +} + +export const Table: React.FC & { + classes: typeof tableClasses +} = ({ + size = 'large', + type = 'default', + headerOptions, + header, + toolbar, + children, + ...props +}) => { + return ( + +
+ {header} + + {children} + +
+
+ ) +} + +Table.classes = tableClasses diff --git a/packages/lsd-react/src/components/Table/index.ts b/packages/lsd-react/src/components/Table/index.ts new file mode 100644 index 0000000..a86149c --- /dev/null +++ b/packages/lsd-react/src/components/Table/index.ts @@ -0,0 +1 @@ +export * from './Table' diff --git a/packages/lsd-react/src/components/TableBody/TableBody.classes.ts b/packages/lsd-react/src/components/TableBody/TableBody.classes.ts new file mode 100644 index 0000000..4182e21 --- /dev/null +++ b/packages/lsd-react/src/components/TableBody/TableBody.classes.ts @@ -0,0 +1,10 @@ +export const tableBodyClasses = { + root: `lsd-table-body`, + + toolbar: `lsd-table-body__toolbar`, + buttons: `lsd-table-body__buttons`, + button: `lsd-table-body__button`, + + container: `lsd-table-container`, + row: `lsd-table-body__row`, +} diff --git a/packages/lsd-react/src/components/TableBody/TableBody.stories.tsx b/packages/lsd-react/src/components/TableBody/TableBody.stories.tsx new file mode 100644 index 0000000..3f92f0c --- /dev/null +++ b/packages/lsd-react/src/components/TableBody/TableBody.stories.tsx @@ -0,0 +1,32 @@ +import { Meta, Story } from '@storybook/react' +import { TableBody, TableBodyProps } from './TableBody' + +export default { + title: 'TableBody', + component: TableBody, + argTypes: { + size: { + type: { + name: 'enum', + value: ['small', 'medium', 'large'], + }, + }, + }, +} as Meta + +export const Root: Story = ({ + body, + ...args +}) => ( +
+ {body} +
+) + +Root.args = { + size: 'large', + options: new Array(4).fill(null).map((value, index) => ({ + value: `${index}`, + name: `Title ${index + 1}`, + })), +} diff --git a/packages/lsd-react/src/components/TableBody/TableBody.styles.ts b/packages/lsd-react/src/components/TableBody/TableBody.styles.ts new file mode 100644 index 0000000..e2805b5 --- /dev/null +++ b/packages/lsd-react/src/components/TableBody/TableBody.styles.ts @@ -0,0 +1,51 @@ +import { css } from '@emotion/react' +import { tableBodyClasses } from './TableBody.classes' + +export const TableBodyStyles = css` + .${tableBodyClasses.root} { + table { + border-collapse: collapse; + text-align: center; + table-layout: fixed; + width: 100%; + height: auto; + } + + table tr:first-child td label:has(input[type='radio']) { + display: none; + } + } + + .${tableBodyClasses.toolbar} { + box-sizing: border-box; + padding: 10px; + border: 1px solid rgb(var(--lsd-border-primary)); + border-bottom: none; + display: flex; + justify-content: space-between; + } + + .${tableBodyClasses.buttons} { + display: flex; + align-items: center; + gap: 10px; + } + + .${tableBodyClasses.button} { + height: 28px; + background: rgb(var(--lsd-border-primary)); + color: rgb(var(--lsd-icon-secondary)); + } + + .${tableBodyClasses.container} { + display: table; + width: 100%; + /* display: inline-grid; + grid-template-columns: auto auto auto auto; */ + + /* tr, + td { + border: 1px solid rgb(var(--lsd-border-primary)); + } */ + } +` diff --git a/packages/lsd-react/src/components/TableBody/TableBody.tsx b/packages/lsd-react/src/components/TableBody/TableBody.tsx new file mode 100644 index 0000000..93f7d09 --- /dev/null +++ b/packages/lsd-react/src/components/TableBody/TableBody.tsx @@ -0,0 +1,36 @@ +import clsx from 'clsx' +import React from 'react' +import { DropdownOption } from '../Dropdown' +import { tableBodyClasses } from './TableBody.classes' + +export type TableBodyProps = Omit< + React.HTMLAttributes, + 'buttonLabel' +> & { + options?: DropdownOption[] + buttonLabel?: 'Button' + size?: 'small' | 'medium' | 'large' + toolbar?: React.ReactNode +} + +export const TableBody: React.FC & { + classes: typeof tableBodyClasses +} = ({ + options = [], + size: _size = 'large', + buttonLabel = 'Button', + toolbar, + children, + ...props +}) => { + return ( +
+ {toolbar && ( +
{toolbar}
+ )} + {children}
+
+ ) +} + +TableBody.classes = tableBodyClasses diff --git a/packages/lsd-react/src/components/TableBody/index.ts b/packages/lsd-react/src/components/TableBody/index.ts new file mode 100644 index 0000000..955df8f --- /dev/null +++ b/packages/lsd-react/src/components/TableBody/index.ts @@ -0,0 +1 @@ +export * from './TableBody' diff --git a/packages/lsd-react/src/components/TableHeader/TableHeader.classes.ts b/packages/lsd-react/src/components/TableHeader/TableHeader.classes.ts new file mode 100644 index 0000000..df99266 --- /dev/null +++ b/packages/lsd-react/src/components/TableHeader/TableHeader.classes.ts @@ -0,0 +1,3 @@ +export const tableHeaderClasses = { + root: `lsd-table-header`, +} diff --git a/packages/lsd-react/src/components/TableHeader/TableHeader.stories.tsx b/packages/lsd-react/src/components/TableHeader/TableHeader.stories.tsx new file mode 100644 index 0000000..ba256bf --- /dev/null +++ b/packages/lsd-react/src/components/TableHeader/TableHeader.stories.tsx @@ -0,0 +1,38 @@ +import { Meta, Story } from '@storybook/react' +import { TableHeader, TableHeaderProps } from './TableHeader' + +export default { + title: 'TableHeader', + component: TableHeader, + argTypes: { + size: { + type: { + name: 'enum', + value: ['small', 'medium', 'large'], + }, + }, + }, +} as Meta + +export const Root: Story = ({ + title, + ...args +}) => ( +
+ +
+
Table header
+
Table description
+
+
+
+) + +Root.args = { + size: 'large', +} diff --git a/packages/lsd-react/src/components/TableHeader/TableHeader.styles.ts b/packages/lsd-react/src/components/TableHeader/TableHeader.styles.ts new file mode 100644 index 0000000..72c005b --- /dev/null +++ b/packages/lsd-react/src/components/TableHeader/TableHeader.styles.ts @@ -0,0 +1,9 @@ +import { css } from '@emotion/react' +import { tableHeaderClasses } from './TableHeader.classes' + +export const TableHeaderStyles = css` + .${tableHeaderClasses.root} { + box-sizing: border-box; + border: 1px solid rgb(var(--lsd-border-primary)); + } +` diff --git a/packages/lsd-react/src/components/TableHeader/TableHeader.tsx b/packages/lsd-react/src/components/TableHeader/TableHeader.tsx new file mode 100644 index 0000000..e8f977a --- /dev/null +++ b/packages/lsd-react/src/components/TableHeader/TableHeader.tsx @@ -0,0 +1,22 @@ +import clsx from 'clsx' +import React from 'react' +import { tableHeaderClasses } from './TableHeader.classes' + +export type TableHeaderProps = Omit< + React.HTMLAttributes, + 'label' +> & { + size?: 'small' | 'medium' | 'large' +} + +export const TableHeader: React.FC & { + classes: typeof tableHeaderClasses +} = ({ size: _size = 'large', children, ...props }) => { + return ( +
+ {children} +
+ ) +} + +TableHeader.classes = tableHeaderClasses diff --git a/packages/lsd-react/src/components/TableHeader/index.ts b/packages/lsd-react/src/components/TableHeader/index.ts new file mode 100644 index 0000000..6e319f3 --- /dev/null +++ b/packages/lsd-react/src/components/TableHeader/index.ts @@ -0,0 +1 @@ +export * from './TableHeader' diff --git a/packages/lsd-react/src/components/TableItem/TableItem.classes.ts b/packages/lsd-react/src/components/TableItem/TableItem.classes.ts new file mode 100644 index 0000000..33934ad --- /dev/null +++ b/packages/lsd-react/src/components/TableItem/TableItem.classes.ts @@ -0,0 +1,7 @@ +export const tableItemClasses = { + root: `lsd-table-item`, + + large: `lsd-table-item--large`, + medium: `lsd-table-item--medium`, + small: `lsd-table-item--small`, +} diff --git a/packages/lsd-react/src/components/TableItem/TableItem.stories.tsx b/packages/lsd-react/src/components/TableItem/TableItem.stories.tsx new file mode 100644 index 0000000..2db3fe7 --- /dev/null +++ b/packages/lsd-react/src/components/TableItem/TableItem.stories.tsx @@ -0,0 +1,22 @@ +import { Meta, Story } from '@storybook/react' +import { TableItem, TableItemProps } from './TableItem' + +export default { + title: 'TableItem', + component: TableItem, + argTypes: { + size: { + type: { + name: 'enum', + value: ['small', 'medium', 'large'], + }, + defaultValue: 'large', + }, + }, +} as Meta + +export const Root: Story = ({ ...args }) => { + return Content +} + +Root.args = {} diff --git a/packages/lsd-react/src/components/TableItem/TableItem.styles.ts b/packages/lsd-react/src/components/TableItem/TableItem.styles.ts new file mode 100644 index 0000000..70f548c --- /dev/null +++ b/packages/lsd-react/src/components/TableItem/TableItem.styles.ts @@ -0,0 +1,33 @@ +import { css } from '@emotion/react' +import { tableItemClasses } from './TableItem.classes' + +export const TableItemStyles = css` + .${tableItemClasses.root} { + border: 1px solid rgb(var(--lsd-border-primary)); + } + + .${tableItemClasses.root}:has(> label) { + width: 40px; + input { + position: relative; + width: 14px; + height: 14px; + margin: auto; + } + span { + margin-left: 14px !important; + } + } + + .${tableItemClasses.large} { + padding: 10px; + } + + .${tableItemClasses.medium} { + padding: 6px 8px; + } + + .${tableItemClasses.small} { + padding: 6px; + } +` diff --git a/packages/lsd-react/src/components/TableItem/TableItem.tsx b/packages/lsd-react/src/components/TableItem/TableItem.tsx new file mode 100644 index 0000000..7c60c90 --- /dev/null +++ b/packages/lsd-react/src/components/TableItem/TableItem.tsx @@ -0,0 +1,29 @@ +import clsx from 'clsx' +import React from 'react' +import { useTableContext } from '../Table/Table.context' +import { tableItemClasses } from './TableItem.classes' + +export type TableItemProps = React.HTMLAttributes & { + size?: 'large' | 'medium' | 'small' +} + +export const TableItem: React.FC & { + classes: typeof tableItemClasses +} = ({ size: _size = 'large', children, ...props }) => { + const table = useTableContext() + const size = table?.size ?? _size + return ( + + {children} + + ) +} + +TableItem.classes = tableItemClasses diff --git a/packages/lsd-react/src/components/TableItem/index.ts b/packages/lsd-react/src/components/TableItem/index.ts new file mode 100644 index 0000000..a8e5883 --- /dev/null +++ b/packages/lsd-react/src/components/TableItem/index.ts @@ -0,0 +1 @@ +export * from './TableItem' diff --git a/packages/lsd-react/src/components/TableRow/TableRow.classes.ts b/packages/lsd-react/src/components/TableRow/TableRow.classes.ts new file mode 100644 index 0000000..43fd092 --- /dev/null +++ b/packages/lsd-react/src/components/TableRow/TableRow.classes.ts @@ -0,0 +1,3 @@ +export const tableRowClasses = { + root: `lsd-table-row`, +} diff --git a/packages/lsd-react/src/components/TableRow/TableRow.stories.tsx b/packages/lsd-react/src/components/TableRow/TableRow.stories.tsx new file mode 100644 index 0000000..4108075 --- /dev/null +++ b/packages/lsd-react/src/components/TableRow/TableRow.stories.tsx @@ -0,0 +1,21 @@ +import { Meta, Story } from '@storybook/react' +import { TableRow, TableRowProps } from './TableRow' + +export default { + title: 'TableRow', + component: TableRow, + argTypes: { + type: { + type: { + name: 'enum', + value: ['default', 'checkbox', 'radio'], + }, + }, + }, +} as Meta + +export const Root: Story = ({ ...args }) => { + return Content +} + +Root.args = {} diff --git a/packages/lsd-react/src/components/TableRow/TableRow.styles.ts b/packages/lsd-react/src/components/TableRow/TableRow.styles.ts new file mode 100644 index 0000000..d80e9ee --- /dev/null +++ b/packages/lsd-react/src/components/TableRow/TableRow.styles.ts @@ -0,0 +1,8 @@ +import { css } from '@emotion/react' +import { tableRowClasses } from './TableRow.classes' + +export const TableRowStyles = css` + .${tableRowClasses.root} { + align-items: center; + } +` diff --git a/packages/lsd-react/src/components/TableRow/TableRow.tsx b/packages/lsd-react/src/components/TableRow/TableRow.tsx new file mode 100644 index 0000000..710acbd --- /dev/null +++ b/packages/lsd-react/src/components/TableRow/TableRow.tsx @@ -0,0 +1,42 @@ +import clsx from 'clsx' +import React from 'react' +import { Checkbox } from '../Checkbox' +import { RadioButton } from '../RadioButton' +import { useTableContext } from '../Table/Table.context' +import { tableItemClasses } from '../TableItem/TableItem.classes' +import { tableRowClasses } from './TableRow.classes' + +export type TableRowProps = React.HTMLAttributes & { + size?: 'large' | 'medium' | 'small' + type?: 'default' | 'checkbox' | 'radio' +} + +export const TableRow: React.FC & { + classes: typeof tableRowClasses +} = ({ + size: _size = 'large', + type: _type = 'default', + children, + ...props +}) => { + const table = useTableContext() + const type = table?.type ?? _type + + return ( + + {type === 'checkbox' && ( + + + + )} + {type === 'radio' && ( + + + + )} + {children} + + ) +} + +TableRow.classes = tableRowClasses diff --git a/packages/lsd-react/src/components/TableRow/index.ts b/packages/lsd-react/src/components/TableRow/index.ts new file mode 100644 index 0000000..2193508 --- /dev/null +++ b/packages/lsd-react/src/components/TableRow/index.ts @@ -0,0 +1 @@ +export * from './TableRow' diff --git a/packages/lsd-react/src/index.ts b/packages/lsd-react/src/index.ts index a7dda93..7bb7526 100644 --- a/packages/lsd-react/src/index.ts +++ b/packages/lsd-react/src/index.ts @@ -21,3 +21,8 @@ export * from './components/Theme' export * from './components/Checkbox' export * from './components/CheckboxGroup' export * from './components/Badge' +export * from './components/Table' +export * from './components/TableHeader' +export * from './components/TableBody' +export * from './components/TableItem' +export * from './components/TableRow'