From 15ae16e292678038566f0f7a63876db3ed92252a Mon Sep 17 00:00:00 2001 From: Jessie Wei Date: Thu, 29 Jun 2023 17:51:13 +1000 Subject: [PATCH 1/2] feat(Table): Allow use of custom header and support more header props --- .../Table/components/FullDataTable/index.tsx | 25 ++++---- .../Table/components/Header/index.tsx | 60 +++++++++++++++++++ .../components/RemoteUpdateTable/index.tsx | 17 +++--- .../ui/src/components/Table/index.stories.tsx | 38 ++++++++++++ packages/ui/src/components/Table/types.ts | 12 +++- 5 files changed, 128 insertions(+), 24 deletions(-) create mode 100644 packages/ui/src/components/Table/components/Header/index.tsx diff --git a/packages/ui/src/components/Table/components/FullDataTable/index.tsx b/packages/ui/src/components/Table/components/FullDataTable/index.tsx index 4507aba1..0475b159 100644 --- a/packages/ui/src/components/Table/components/FullDataTable/index.tsx +++ b/packages/ui/src/components/Table/components/FullDataTable/index.tsx @@ -17,11 +17,10 @@ import { FC, useCallback } from 'react'; import TableComponent, { TableProps as CloudscapeTableProps } from '@cloudscape-design/components/table'; import Pagination from '@cloudscape-design/components/pagination'; import { useCollection } from '@cloudscape-design/collection-hooks'; - import TextFilter from '@cloudscape-design/components/text-filter'; -import Header from '@cloudscape-design/components/header'; import Button from '@cloudscape-design/components/button'; import { NonCancelableEventHandler } from '@cloudscape-design/components/internal/events'; +import Header from '../Header'; import EmptyState from '../EmptyState'; import { BaseTableProps, InternalTableProps } from '../../types'; import { @@ -118,16 +117,18 @@ const FullDataTable: FC = ({ )) } header={ -
- {header} -
+ header && ( +
+ {header} +
+ ) } /> ); diff --git a/packages/ui/src/components/Table/components/Header/index.tsx b/packages/ui/src/components/Table/components/Header/index.tsx new file mode 100644 index 00000000..44735baf --- /dev/null +++ b/packages/ui/src/components/Table/components/Header/index.tsx @@ -0,0 +1,60 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. * + ******************************************************************************************************************** */ +import { FC, isValidElement, createElement, PropsWithChildren, useMemo } from 'react'; +import CloudscapeHeader, { HeaderProps as CloudscapeHeaderProps } from '@cloudscape-design/components/header'; + +export interface HeaderProps { + actions?: CloudscapeHeaderProps['actions']; + info?: CloudscapeHeaderProps['info']; + variant?: CloudscapeHeaderProps['variant']; + description?: CloudscapeHeaderProps['description']; + allItemsLength?: number; + selectedItemsLength?: number; +} + +const CloudscapeHeaderType = createElement(CloudscapeHeader).type; + +const Header: FC> = ({ + selectedItemsLength, + allItemsLength, + children, + actions, + info, + description, + variant, +}) => { + const customHeader = isValidElement(children) && children.type === CloudscapeHeaderType; + + const counter = useMemo( + () => + allItemsLength + ? selectedItemsLength + ? `(${selectedItemsLength}/${allItemsLength})` + : `(${allItemsLength})` + : undefined, + [allItemsLength, selectedItemsLength] + ); + + return customHeader ? ( + children + ) : ( + + {children} + + ); +}; + +export default Header; diff --git a/packages/ui/src/components/Table/components/RemoteUpdateTable/index.tsx b/packages/ui/src/components/Table/components/RemoteUpdateTable/index.tsx index e7ea79d5..2fb29972 100644 --- a/packages/ui/src/components/Table/components/RemoteUpdateTable/index.tsx +++ b/packages/ui/src/components/Table/components/RemoteUpdateTable/index.tsx @@ -17,13 +17,13 @@ import { FC, useMemo, useState, useCallback, useEffect } from 'react'; import TableComponent, { TableProps as CloudscapeTableProps } from '@cloudscape-design/components/table'; import Pagination, { PaginationProps } from '@cloudscape-design/components/pagination'; import TextFilter, { TextFilterProps } from '@cloudscape-design/components/text-filter'; -import Header from '@cloudscape-design/components/header'; import Button from '@cloudscape-design/components/button'; import { NonCancelableEventHandler } from '@cloudscape-design/components/internal/events'; import { useDebouncedCallback } from 'use-debounce'; import getPageCount from '../../utils/getPageCount'; import EmptyState from '../EmptyState'; +import Header from '../Header'; import { RemoteUpdateTableProps, InternalTableProps, FetchDataOptions } from '../../types'; import { DEFAULT_TRACK_BY, @@ -184,18 +184,17 @@ const RemoteUpdateTable: FC = ({ )) } header={ - header && typeof header === 'string' ? ( + header && (
{header}
- ) : ( - header ) } /> diff --git a/packages/ui/src/components/Table/index.stories.tsx b/packages/ui/src/components/Table/index.stories.tsx index 8bbb5c80..f1ebcfed 100644 --- a/packages/ui/src/components/Table/index.stories.tsx +++ b/packages/ui/src/components/Table/index.stories.tsx @@ -22,6 +22,10 @@ import shortData from './data/short'; import longData from './data/long'; import { DataType } from './data/type'; import { NonCancelableEventHandler } from '@cloudscape-design/components/internal/events'; +import Header from '@cloudscape-design/components/header'; +import Button from '@cloudscape-design/components/button'; +import Link from '@cloudscape-design/components/link'; +import SpaceBetween from '@cloudscape-design/components/space-between'; export default { component: Table, @@ -49,6 +53,14 @@ Default.args = { columnDefinitions: columnDefinition, items: shortData, header: 'Table Title', + actions: ( + + + + + ), + info: Info, + description: 'Table description', onFetchData: undefined, }; @@ -108,6 +120,12 @@ DisableFilters.args = { disableFilters: true, }; +export const DisableSelect = Template.bind({}); +DisableSelect.args = { + ...Default.args, + disableRowSelect: true, +}; + export const PureTable = Template.bind({}); PureTable.args = { ...Default.args, @@ -133,6 +151,26 @@ DefaultSingleSelect.args = { ], }; +export const CustomHeader = Template.bind({}); +CustomHeader.args = { + columnDefinitions: columnDefinition, + items: shortData, + header: ( +
Info} + actions={ + + + + + } + > + Custom Header +
+ ), +}; + interface TestDataType { id: number; name: string; diff --git a/packages/ui/src/components/Table/types.ts b/packages/ui/src/components/Table/types.ts index 7aea3933..c3c36bce 100644 --- a/packages/ui/src/components/Table/types.ts +++ b/packages/ui/src/components/Table/types.ts @@ -14,9 +14,10 @@ limitations under the License. * ******************************************************************************************************************** */ import { TableProps as CloudscapeTableProps } from '@cloudscape-design/components/table'; +import { HeaderProps } from '@cloudscape-design/components/header'; import { CollectionPreferencesProps } from '@cloudscape-design/components/collection-preferences'; -export interface BaseTableProps extends CloudscapeTableProps { +export interface BaseTableProps extends CloudscapeTableProps, Pick { /** * Disable pagination * */ @@ -46,9 +47,14 @@ export interface BaseTableProps extends CloudscapeTableProps { * */ defaultPageIndex?: number; /** - * The actions displayed on the header + * The heading text (use actions, info and description to form a Table header)
+ * Or the heading element of the table container (use the [header component](/components/header/). */ - actions?: React.ReactNode; + header?: React.ReactNode; + /** + * The variant of the table header. + */ + headerVariant?: HeaderProps['variant']; } export interface FetchDataOptions { From 4b2551ff46986d6cc3516ae2b41dfaefd07a4bb2 Mon Sep 17 00:00:00 2001 From: Jessie Wei Date: Thu, 29 Jun 2023 18:03:30 +1000 Subject: [PATCH 2/2] docs(Table): Update docs --- packages/ui/src/components/Table/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/Table/types.ts b/packages/ui/src/components/Table/types.ts index c3c36bce..e2d5bcd0 100644 --- a/packages/ui/src/components/Table/types.ts +++ b/packages/ui/src/components/Table/types.ts @@ -47,8 +47,8 @@ export interface BaseTableProps extends CloudscapeTableProps, Pick - * Or the heading element of the table container (use the [header component](/components/header/). + * The heading text (together with actions, info and description props to form a Table header)
+ * or the Cloudscape header component. */ header?: React.ReactNode; /**