Skip to content

Commit 113a5f1

Browse files
Add props for sort indicators, checkboxes and expand to Skeleton Table (#139)
* add isSelectable and isExpandable to SkeletonTable * feat(SkeletonTable): Update packages/module/src/SkeletonTable/SkeletonTable.tsx --------- Co-authored-by: Filip Hlavac <50696716+fhlavac@users.noreply.github.com>
1 parent edbca71 commit 113a5f1

File tree

8 files changed

+200
-30
lines changed

8 files changed

+200
-30
lines changed
Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,70 @@
11
import React from 'react';
2+
import { Th } from '@patternfly/react-table';
23
import SkeletonTable from '../../packages/module/dist/dynamic/SkeletonTable';
34

45
describe('SkeletonTable', () => {
6+
beforeEach(() => {
7+
cy.viewport(1600, 800);
8+
});
9+
510
it('renders SkeletonTable', () => {
6-
const SkeletonTableExample = <SkeletonTable rowSize={10} columns={[ 'first', 'second' ]} />;
11+
const SkeletonTableExample = <SkeletonTable rows={10} columns={[ 'first', 'second' ]} />;
12+
cy.mount(SkeletonTableExample);
13+
cy.get('table').should('exist');
14+
cy.get('table thead tr').should('have.text', 'firstsecond');
15+
});
16+
17+
it ('can be used without passing columns', () => {
18+
const SkeletonTableExample = <SkeletonTable rows={10} numberOfColumns={2} />;
19+
cy.mount(SkeletonTableExample);
20+
cy.get('table').should('exist');
21+
cy.get('table thead tr').should('have.text', '');
22+
});
23+
24+
it('contains checkboxes when passed isSelectable', () => {
25+
const SkeletonTableExample = <SkeletonTable rows={10} columns={[ 'first', 'second' ]} isSelectable />;
26+
cy.mount(SkeletonTableExample);
27+
cy.get('table').should('exist');
28+
cy.get('table thead tr').should('have.text', 'firstsecond');
29+
cy.get('input[type="checkbox"]').should('have.length', 10);
30+
});
31+
32+
it('is expandable when passed isExpandable', () => {
33+
const SkeletonTableExample = <SkeletonTable rows={10} columns={[ 'first', 'second' ]} isExpandable />;
34+
cy.mount(SkeletonTableExample);
35+
cy.get('table').should('exist');
36+
cy.get('table thead tr').should('have.text', 'firstsecond');
37+
cy.get('.pf-v5-c-table__toggle-icon').should('have.length', 10);
38+
});
39+
40+
it('can be passed a selectVariant to render radio buttons', () => {
41+
const SkeletonTableExample = <SkeletonTable rows={10} columns={[ 'first', 'second' ]} isSelectable selectVariant="radio" />;
742
cy.mount(SkeletonTableExample);
843
cy.get('table').should('exist');
944
cy.get('table thead tr').should('have.text', 'firstsecond');
45+
cy.get('input[type="radio"]').should('have.length', 10);
1046
});
11-
})
47+
48+
it('can be passed custom columns', () => {
49+
const SkeletonTableExample = (
50+
<SkeletonTable
51+
rows={10}
52+
columns={[
53+
<Th key="1" sort={{ columnIndex: 0, sortBy: { index: 0, direction: 'asc' } }}>
54+
first
55+
</Th>,
56+
<Th key="2">second</Th>,
57+
<Th key="3">third</Th>
58+
]}
59+
/>
60+
);
61+
cy.mount(SkeletonTableExample);
62+
cy.get('table').should('exist');
63+
cy.get('table thead tr').should('have.text', 'firstsecondthird');
64+
cy.get('.pf-v5-c-table__sort-indicator').eq(0).find('path').should(
65+
'have.attr',
66+
'd',
67+
'M88 166.059V468c0 6.627 5.373 12 12 12h56c6.627 0 12-5.373 12-12V166.059h46.059c21.382 0 32.09-25.851 16.971-40.971l-86.059-86.059c-9.373-9.373-24.569-9.373-33.941 0l-86.059 86.059c-15.119 15.119-4.411 40.971 16.971 40.971H88z' // ascending
68+
);
69+
})
70+
});

packages/module/patternfly-docs/content/extensions/component-groups/examples/Skeleton/Skeleton.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,38 @@ To indicate that a table's cells are still loading, a basic skeleton table uses
2727

2828
```
2929

30+
### Compact skeleton table
31+
32+
The skeleton table can be displayed as a compact table by setting the `variant` prop to `compact`. Borders can be toggled off by setting `borders` to `false`.
33+
34+
```js file="./SkeletonTableCompactExample.tsx"
35+
36+
```
37+
38+
### Selectable columns
39+
40+
The skeleton table can display selectable columns by setting the `isSelectable` prop to `true`. The `selectVariant` prop determines if radio buttons or checkboxes are used.
41+
42+
```js file="./SkeletonTableSelectableExample.tsx"
43+
44+
```
45+
46+
### Expandable rows
47+
48+
The skeleton table can display the indicator for expandable rows by setting the `isExpandable` prop to `true`.
49+
50+
```js file="./SkeletonTableExpandableExample.tsx"
51+
52+
```
53+
54+
### Customizable column headers
55+
56+
Custom column headers can be provided by passing an array of strings or `Th` components to the `columns` prop instead of an array of strings. This allows you to support sorting on columns, add custom content, or style the column headers.
57+
58+
```js file="./SkeletonTableCustomExample.tsx"
59+
60+
```
61+
3062
### Full loading simulation
3163

3264
The following example demonstrates the typical behavior of a skeleton table transitioning to a normal table as the data becomes available.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import React from 'react';
2+
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable';
3+
4+
export const SkeletonTableExample: React.FC = () => <SkeletonTable rowSize={10} columns={[ 'first', 'second' ]} variant='compact' borders={false} />;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable';
3+
import { Th } from '@patternfly/react-table';
4+
5+
export const SkeletonTableExample: React.FC = () => (
6+
<SkeletonTable
7+
rowSize={10}
8+
columns={[
9+
<Th key="1" sort={{ columnIndex: 0, sortBy: {} }}>
10+
first
11+
</Th>,
12+
<Th key="2" sort={{ columnIndex: 1, sortBy: {} }}>
13+
second
14+
</Th>
15+
]}
16+
/>
17+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import React from 'react';
2+
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable';
3+
4+
export const SkeletonTableExample: React.FC = () => <SkeletonTable rowSize={10} columns={[ 'first', 'second' ]} isExpandable />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable';
3+
4+
export const SkeletonTableExample: React.FC = () => (
5+
<SkeletonTable rowSize={10} columns={[ 'first', 'second' ]} isSelectable selectVariant="radio" />
6+
);

packages/module/src/SkeletonTable/SkeletonTable.tsx

Lines changed: 76 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,80 @@
1-
import React, { ReactNode } from 'react';
2-
import { Caption, Table, TableProps, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
1+
import React from 'react';
2+
import {
3+
Caption,
4+
Table,
5+
TableProps,
6+
TableVariant,
7+
Tbody,
8+
Td,
9+
Th,
10+
Thead,
11+
Tr,
12+
RowSelectVariant
13+
} from '@patternfly/react-table';
314
import { Skeleton } from '@patternfly/react-core';
415

5-
export type SkeletonTableProps = Omit<TableProps, 'ref'> & {
16+
export interface SkeletonTableProps extends Omit<TableProps, 'ref'> {
617
/** Indicates the table variant */
718
variant?: TableVariant;
19+
/** Flag indicating if the table should have borders */
20+
borders?: boolean;
821
/** The number of rows the skeleton table should contain */
922
rows?: number;
1023
/** Any captions that should be added to the table */
11-
caption?: ReactNode;
24+
caption?: React.ReactNode;
1225
/** Custom OUIA ID */
1326
ouiaId?: string | number;
14-
} & (
15-
| {
16-
columns: ReactNode[];
17-
}
18-
| {
19-
numberOfColumns: number;
20-
}
21-
);
22-
23-
24-
function hasCustomColumns(props: Record<string, any>): props is SkeletonTableProps & {
25-
columns: ReactNode[];
26-
} {
27-
return Array.isArray(props.columns);
27+
/** Flag indicating if the table is selectable */
28+
isSelectable?: boolean;
29+
/** Flag indicating if the table is expandable */
30+
isExpandable?: boolean;
31+
/** Determines if the row selection variant (radio/checkbox) */
32+
selectVariant?: RowSelectVariant;
33+
/** Custom columns for the table */
34+
columns?: string[] | React.ReactElement<typeof Th>[];
35+
/** Number of columns in the table */
36+
numberOfColumns?: number;
2837
}
2938

30-
const SkeletonTable: React.FunctionComponent<SkeletonTableProps> = (props: SkeletonTableProps) => {
31-
const { variant, rows = 5, caption, ouiaId = 'SkeletonTable', ...rest } = props;
32-
const rowCells = hasCustomColumns(props) ? props.columns.length : props.numberOfColumns;
39+
const SkeletonTable: React.FunctionComponent<SkeletonTableProps> = ({
40+
variant,
41+
borders = true,
42+
rows = 5,
43+
caption,
44+
ouiaId = 'SkeletonTable',
45+
isSelectable,
46+
isExpandable,
47+
selectVariant = RowSelectVariant.checkbox,
48+
columns,
49+
numberOfColumns,
50+
...rest
51+
}: SkeletonTableProps) => {
52+
const hasCustomColumns = Array.isArray(columns);
53+
const rowCells = hasCustomColumns ? columns?.length ?? 0 : numberOfColumns;
3354
const rowArray = [ ...new Array(rowCells) ];
55+
3456
const bodyRows = [ ...new Array(rows) ].map((_, rowIndex) => (
3557
<Tr key={rowIndex} ouiaId={`${ouiaId}-tr-${rowIndex}`}>
58+
{isExpandable && (
59+
<Td
60+
data-ouia-component-id={`${ouiaId}-td-expand-${rowIndex}`}
61+
expand={{
62+
rowIndex,
63+
isExpanded: false
64+
}}
65+
/>
66+
)}
67+
{isSelectable && (
68+
<Td
69+
data-ouia-component-id={`${ouiaId}-td-select-${rowIndex}`}
70+
select={{
71+
rowIndex,
72+
isSelected: false,
73+
isDisabled: true,
74+
variant: selectVariant
75+
}}
76+
/>
77+
)}
3678
{rowArray.map((_, colIndex) => (
3779
<Td key={colIndex} data-ouia-component-id={`${ouiaId}-td-${rowIndex}-${colIndex}`}>
3880
<Skeleton />
@@ -42,12 +84,22 @@ const SkeletonTable: React.FunctionComponent<SkeletonTableProps> = (props: Skele
4284
));
4385

4486
return (
45-
<Table aria-label="Loading" variant={variant} ouiaId={ouiaId} {...rest}>
87+
<Table aria-label="Loading" variant={variant} borders={borders} ouiaId={ouiaId} {...rest}>
4688
{caption && <Caption>{caption}</Caption>}
4789
<Thead data-ouia-component-id={`${ouiaId}-thead`}>
4890
<Tr ouiaId={`${ouiaId}-tr-head`}>
49-
{hasCustomColumns(props)
50-
? props.columns.map((c, index) => <Th key={index} data-ouia-component-id={`${ouiaId}-th-${index}`}>{c}</Th>)
91+
{isExpandable && <Th key="expand" />}
92+
{isSelectable && <Th key="select" />}
93+
{hasCustomColumns
94+
? columns?.map((c, index) =>
95+
typeof c === 'string' ? (
96+
<Th key={index} data-ouia-component-id={`${ouiaId}-th-${index}`}>
97+
{c}
98+
</Th>
99+
) : (
100+
React.cloneElement(c, { key: index, 'data-ouia-component-id': `${ouiaId}-th-${index}` })
101+
)
102+
)
51103
: rowArray.map((_, index) => (
52104
<Th key={index} data-ouia-component-id={`${ouiaId}-th-${index}`}>
53105
<Skeleton />

packages/module/src/SkeletonTable/__snapshots__/SkeletonTable.test.tsx.snap

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ exports[`SkeletonTable component should render correctly 1`] = `
88
<table
99
aria-label="Loading"
1010
class="pf-v5-c-table pf-m-grid-md"
11-
columns="first,second"
1211
data-ouia-component-id="SkeletonTable"
1312
data-ouia-component-type="PF5/Table"
1413
data-ouia-safe="true"
@@ -220,7 +219,6 @@ exports[`SkeletonTable component should render correctly 1`] = `
220219
<table
221220
aria-label="Loading"
222221
class="pf-v5-c-table pf-m-grid-md"
223-
columns="first,second"
224222
data-ouia-component-id="SkeletonTable"
225223
data-ouia-component-type="PF5/Table"
226224
data-ouia-safe="true"
@@ -489,7 +487,6 @@ exports[`SkeletonTable component should render correctly with rows 1`] = `
489487
<table
490488
aria-label="Loading"
491489
class="pf-v5-c-table pf-m-grid-md"
492-
columns="first,second"
493490
data-ouia-component-id="SkeletonTable"
494491
data-ouia-component-type="PF5/Table"
495492
data-ouia-safe="true"
@@ -701,7 +698,6 @@ exports[`SkeletonTable component should render correctly with rows 1`] = `
701698
<table
702699
aria-label="Loading"
703700
class="pf-v5-c-table pf-m-grid-md"
704-
columns="first,second"
705701
data-ouia-component-id="SkeletonTable"
706702
data-ouia-component-type="PF5/Table"
707703
data-ouia-safe="true"

0 commit comments

Comments
 (0)