From d68bcaa2efc725eac7e57d7fd1bf20f10e64aaa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matuzal=C3=A9m=20Teles?= Date: Wed, 20 Sep 2023 19:41:14 -0500 Subject: [PATCH] feat(@clayui/core): adds the implementation of the new data-oriented composition for Table Instead of implementing this on top of the Table currently, we are recreating the component parts in a new composition to avoid backward compatibility or mechanisms that have to identify when using the old or new composition to use the right component. So to use the new composition use the Table from `@clayui/core` and we leave the component in `@clayui/table` in deprecation mode. --- packages/clay-core/package.json | 1 + packages/clay-core/src/table/Body.tsx | 47 ++++++++++ packages/clay-core/src/table/Column.tsx | 93 ++++++++++++++++++++ packages/clay-core/src/table/Head.tsx | 49 +++++++++++ packages/clay-core/src/table/Row.tsx | 61 +++++++++++++ packages/clay-core/src/table/ScopeContext.ts | 17 ++++ packages/clay-core/src/table/Table.tsx | 8 ++ packages/clay-core/src/table/index.ts | 10 +++ packages/clay-core/stories/Table.stories.tsx | 81 +++++++++++++++++ 9 files changed, 367 insertions(+) create mode 100644 packages/clay-core/src/table/Body.tsx create mode 100644 packages/clay-core/src/table/Column.tsx create mode 100644 packages/clay-core/src/table/Head.tsx create mode 100644 packages/clay-core/src/table/Row.tsx create mode 100644 packages/clay-core/src/table/ScopeContext.ts create mode 100644 packages/clay-core/src/table/Table.tsx create mode 100644 packages/clay-core/src/table/index.ts create mode 100644 packages/clay-core/stories/Table.stories.tsx diff --git a/packages/clay-core/package.json b/packages/clay-core/package.json index 18f5a656f2..2327f50e7b 100644 --- a/packages/clay-core/package.json +++ b/packages/clay-core/package.json @@ -33,6 +33,7 @@ "@clayui/loading-indicator": "^3.60.0", "@clayui/modal": "^3.104.0", "@clayui/provider": "^3.93.0", + "@clayui/table": "^3.56.0", "@clayui/shared": "^3.104.0", "@tanstack/react-virtual": "3.0.0-beta.54", "aria-hidden": "^1.2.2", diff --git a/packages/clay-core/src/table/Body.tsx b/packages/clay-core/src/table/Body.tsx new file mode 100644 index 0000000000..34657d990d --- /dev/null +++ b/packages/clay-core/src/table/Body.tsx @@ -0,0 +1,47 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import React from 'react'; + +import {ChildrenFunction, Collection} from '../collection'; +import {Scope, ScopeContext} from './ScopeContext'; + +type Props = { + /** + * Children content to render a dynamic or static content. + */ + children: React.ReactNode | ChildrenFunction; + + /** + * Property to render content with dynamic data. + */ + items?: Array; +} & React.TableHTMLAttributes; + +function BodyInner>( + {children, items, ...otherProps}: Props, + ref: React.Ref +) { + return ( + + + + {children} + + + + ); +} + +type ForwardRef = { + displayName: string; + ( + props: Props & {ref?: React.Ref} + ): JSX.Element; +}; + +export const Body = React.forwardRef(BodyInner) as ForwardRef; + +Body.displayName = 'TableBody'; diff --git a/packages/clay-core/src/table/Column.tsx b/packages/clay-core/src/table/Column.tsx new file mode 100644 index 0000000000..c496d7a0d3 --- /dev/null +++ b/packages/clay-core/src/table/Column.tsx @@ -0,0 +1,93 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import classNames from 'classnames'; +import React from 'react'; + +import {Scope, useScope} from './ScopeContext'; + +type Props = { + /** + * Aligns the text inside the Cell. + */ + align?: 'center' | 'left' | 'right'; + + /** + * Children content to render content. + */ + children: React.ReactNode; + + /** + * Sometimes we are unable to remove specific table columns from the DOM + * and need to hide it using CSS. This property can be added to the "new" + * first or last cell to maintain table styles on the left and right side. + */ + delimiter?: 'start' | 'end'; + + /** + * Fills out the remaining space inside a Cell. + */ + expanded?: boolean; + + /** + * Aligns horizontally contents inside the Cell. + */ + textAlign?: 'center' | 'end' | 'start'; + + /** + * Truncates the text inside a Cell. + */ + truncate?: boolean; + + /* + * Break the text into lines when necessary. + */ + wrap?: boolean; +} & React.ThHTMLAttributes & + React.TdHTMLAttributes; + +export const Column = React.forwardRef( + function ColumnInner( + { + align, + children, + className, + delimiter, + expanded, + textAlign, + truncate, + wrap = true, + ...otherProps + }, + ref + ) { + const scope = useScope(); + const As = scope === Scope.Head ? 'th' : 'td'; + + return ( + + {truncate ? ( + + {children} + + ) : ( + children + )} + + ); + } +); + +Column.displayName = 'Item'; diff --git a/packages/clay-core/src/table/Head.tsx b/packages/clay-core/src/table/Head.tsx new file mode 100644 index 0000000000..15dfd39a84 --- /dev/null +++ b/packages/clay-core/src/table/Head.tsx @@ -0,0 +1,49 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import React from 'react'; + +import {ChildrenFunction, Collection} from '../collection'; +import {Scope, ScopeContext} from './ScopeContext'; + +type Props = { + /** + * Children content to render a dynamic or static content. + */ + children: React.ReactNode | ChildrenFunction; + + /** + * Property to render content with dynamic data. + */ + items?: Array; +} & React.TableHTMLAttributes; + +function HeadInner>( + {children, items, ...otherProps}: Props, + ref: React.Ref +) { + return ( + + + + + {children} + + + + + ); +} + +type ForwardRef = { + displayName: string; + ( + props: Props & {ref?: React.Ref} + ): JSX.Element; +}; + +export const Head = React.forwardRef(HeadInner) as ForwardRef; + +Head.displayName = 'TableHead'; diff --git a/packages/clay-core/src/table/Row.tsx b/packages/clay-core/src/table/Row.tsx new file mode 100644 index 0000000000..12041adcda --- /dev/null +++ b/packages/clay-core/src/table/Row.tsx @@ -0,0 +1,61 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import classNames from 'classnames'; +import React from 'react'; + +import {ChildrenFunction, Collection} from '../collection'; + +type Props = { + /** + * Children content to render a dynamic or static content. + */ + children: React.ReactNode | ChildrenFunction; + + /** + * This property can be added to the "new" first + * or last ClayTable.Row to maintain table styles on the top and bottom sides. + */ + delimiter?: 'start' | 'end'; + + /** + * Applies a divider style inside the row. + */ + divider?: boolean; + + /** + * Property to render content with dynamic data. + */ + items?: Array; +} & React.HTMLAttributes; + +function RowInner>( + {children, className, delimiter, divider, items, ...otherProps}: Props, + ref: React.Ref +) { + return ( + + + {children} + + + ); +} + +type ForwardRef = { + displayName: string; + (props: Props & {ref?: React.Ref}): JSX.Element; +}; + +export const Row = React.forwardRef(RowInner) as ForwardRef; + +Row.displayName = 'TableRow'; diff --git a/packages/clay-core/src/table/ScopeContext.ts b/packages/clay-core/src/table/ScopeContext.ts new file mode 100644 index 0000000000..3028acc0ef --- /dev/null +++ b/packages/clay-core/src/table/ScopeContext.ts @@ -0,0 +1,17 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import React, {useContext} from 'react'; + +export enum Scope { + Head = 'head', + Body = 'body', +} + +export const ScopeContext = React.createContext(Scope.Head); + +export function useScope() { + return useContext(ScopeContext); +} diff --git a/packages/clay-core/src/table/Table.tsx b/packages/clay-core/src/table/Table.tsx new file mode 100644 index 0000000000..b91ce9aa81 --- /dev/null +++ b/packages/clay-core/src/table/Table.tsx @@ -0,0 +1,8 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import RootTable from '@clayui/table'; + +export const Table = RootTable; diff --git a/packages/clay-core/src/table/index.ts b/packages/clay-core/src/table/index.ts new file mode 100644 index 0000000000..7c646c4b1b --- /dev/null +++ b/packages/clay-core/src/table/index.ts @@ -0,0 +1,10 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +export * from './Body'; +export * from './Column'; +export * from './Head'; +export * from './Row'; +export * from './Table'; diff --git a/packages/clay-core/stories/Table.stories.tsx b/packages/clay-core/stories/Table.stories.tsx new file mode 100644 index 0000000000..e3c95ca6bd --- /dev/null +++ b/packages/clay-core/stories/Table.stories.tsx @@ -0,0 +1,81 @@ +/** + * SPDX-FileCopyrightText: © 2023 Liferay, Inc. + * SPDX-License-Identifier: BSD-3-Clause + */ + +import React from 'react'; + +import {Body, Column, Head, Row, Table} from '../src/table'; + +export default { + title: 'Design System/Components/Table', +}; + +const columns = [ + { + id: '1', + name: 'Name', + }, + { + id: '2', + name: 'Type', + }, +]; + +const rows = [ + {id: 1, name: 'Games', type: 'File folder'}, + {id: 2, name: 'Program Files', type: 'File folder'}, +]; + +export const Dynamic = () => { + return ( + + + {(column) => {column.name}} + + + + {(row) => ( + + {row.name} + {row.type} + + )} + +
+ ); +}; + +const columns2 = [ + { + id: 'name', + name: 'Name', + }, + { + id: 'type', + name: 'Type', + }, +]; + +const rows2 = [ + {id: 1, name: 'Games', type: 'File folder'}, + {id: 2, name: 'Program Files', type: 'File folder'}, +]; + +export const DynamicCells = () => { + return ( + + + {(column) => {column.name}} + + + + {(row) => ( + + {(column) => {row[column.id]}} + + )} + +
+ ); +};