-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #56 from dlabaj/skeletonTable
feat(skeletonTable): Added skeleton table component.
- Loading branch information
Showing
8 changed files
with
1,125 additions
and
0 deletions.
There are no files selected for viewing
38 changes: 38 additions & 0 deletions
38
...tternfly-docs/content/extensions/component-groups/examples/Skeleton/Skeleton.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
# Sidenav top-level section | ||
# should be the same for all markdown files | ||
section: extensions | ||
subsection: Component groups | ||
# Sidenav secondary level section | ||
# should be the same for all markdown files | ||
id: Skeleton table | ||
# Tab (react | react-demos | html | html-demos | design-guidelines | accessibility) | ||
source: react | ||
# If you use typescript, the name of the interface to display props for | ||
# These are found through the sourceProps function provided in patternfly-docs.source.js | ||
propComponents: ['SkeletonTable'] | ||
--- | ||
import SkeletonTable from '@patternfly/react-component-groups/dist/dynamic/SkeletonTable'; | ||
|
||
The **skeleton table** component is used to display placeholder "skeletons" within a table as its contents load. | ||
|
||
## Examples | ||
|
||
### Basic skeleton table | ||
|
||
To indicate that a table's cells are still loading, a basic skeleton table uses the [skeleton](https://www.patternfly.org/components/skeleton) component to place a placeholder skeleton in each cell. Once the data is loaded, the skeleton table is replaced with a table containing the real data. | ||
|
||
```js file="./SkeletonTableExample.tsx" | ||
|
||
``` | ||
|
||
### Full loading simulation | ||
|
||
The following example demonstrates the typical behavior of a skeleton table transitioning to a normal table as the data becomes available. | ||
|
||
To simulate this loading process, select the `Reload table` button and wait for the data to populate. | ||
|
||
|
||
```js file="./SkeletonTableLoadingExample.tsx" | ||
|
||
``` |
4 changes: 4 additions & 0 deletions
4
...rnfly-docs/content/extensions/component-groups/examples/Skeleton/SkeletonTableExample.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import React from 'react'; | ||
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable'; | ||
|
||
export const SkeletonTableExample: React.FC = () => <SkeletonTable rowSize={10} columns={[ 'first', 'second' ]} /> |
101 changes: 101 additions & 0 deletions
101
...ocs/content/extensions/component-groups/examples/Skeleton/SkeletonTableLoadingExample.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React from 'react'; | ||
import SkeletonTable from '@patternfly/react-core/dist/js/components/Skeleton/SkeletonTable'; | ||
import { Table, Tbody, Td, Th, Tr, Thead } from '@patternfly/react-table'; | ||
import { Button, Stack, StackItem } from '@patternfly/react-core'; | ||
|
||
interface Repository { | ||
name: string; | ||
branches: string | null; | ||
prs: string | null; | ||
workspaces: string; | ||
lastCommit: string; | ||
} | ||
|
||
export const SkeletonTableExample: React.FC = () => { | ||
const [ isLoaded, setIsLoaded ] = React.useState(false); | ||
|
||
const simulatedAsyncCall = new Promise<boolean>((resolve) => { | ||
setTimeout(() => { | ||
resolve(true); | ||
}, 5000); | ||
}); | ||
|
||
const loadData = async () => { | ||
const result = await simulatedAsyncCall; | ||
setIsLoaded(result); | ||
}; | ||
|
||
const repositories: Repository[] = [ | ||
{ name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' }, | ||
{ name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' }, | ||
{ name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' } | ||
]; | ||
|
||
const columnNames = { | ||
name: 'Repositories', | ||
branches: 'Branches', | ||
prs: 'Pull requests', | ||
workspaces: 'Workspaces', | ||
lastCommit: 'Last commit' | ||
}; | ||
|
||
let table: React.ReactNode; | ||
|
||
if (!isLoaded) { | ||
table = ( | ||
<SkeletonTable | ||
rows={3} | ||
columns={[ | ||
columnNames.name, | ||
columnNames.branches, | ||
columnNames.prs, | ||
columnNames.workspaces, | ||
columnNames.lastCommit | ||
]} | ||
/> | ||
); | ||
} else { | ||
table = ( | ||
<Table> | ||
<Thead> | ||
<Tr> | ||
<Th>{columnNames.name}</Th> | ||
<Th>{columnNames.branches}</Th> | ||
<Th>{columnNames.prs}</Th> | ||
<Th>{columnNames.workspaces}</Th> | ||
<Th>{columnNames.lastCommit}</Th> | ||
</Tr> | ||
</Thead> | ||
<Tbody> | ||
{repositories.map((repo) => ( | ||
<Tr key={repo.name}> | ||
<Td dataLabel={columnNames.name}>{repo.name}</Td> | ||
<Td dataLabel={columnNames.branches}>{repo.branches}</Td> | ||
<Td dataLabel={columnNames.prs}>{repo.prs}</Td> | ||
<Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td> | ||
<Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td> | ||
</Tr> | ||
))} | ||
</Tbody> | ||
</Table> | ||
); | ||
} | ||
|
||
return ( | ||
<> | ||
<Stack hasGutter> | ||
<StackItem>{table}</StackItem> | ||
<StackItem> | ||
<Button | ||
onClick={() => { | ||
setIsLoaded(false); | ||
loadData(); | ||
}} | ||
> | ||
Reload table | ||
</Button> | ||
</StackItem> | ||
</Stack> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import React from 'react'; | ||
import { render } from '@testing-library/react'; | ||
import SkeletonTable from './SkeletonTable'; | ||
|
||
describe('SkeletonTable component', () => { | ||
it('should render correctly', () => { | ||
expect(render(<SkeletonTable columns={[ 'first', 'second' ]}/>)).toMatchSnapshot(); | ||
}); | ||
|
||
it('should render correctly with rows', () => { | ||
expect(render(<SkeletonTable columns={[ 'first', 'second' ]} rows={5} />)).toMatchSnapshot(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React, { ReactNode } from 'react'; | ||
import { Caption, Table, TableProps, TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table'; | ||
import { Skeleton } from '@patternfly/react-core'; | ||
|
||
export type SkeletonTableProps = TableProps & { | ||
/** Indicates the table variant */ | ||
variant?: TableVariant; | ||
/** The number of rows the skeleton table should contain */ | ||
rows?: number; | ||
/** Any captions that should be added to the table */ | ||
caption?: ReactNode; | ||
} & ( | ||
| { | ||
columns: ReactNode[]; | ||
} | ||
| { | ||
numberOfColumns: number; | ||
} | ||
); | ||
|
||
|
||
function hasCustomColumns(props: Record<string, any>): props is SkeletonTableProps & { | ||
columns: ReactNode[]; | ||
} { | ||
return Array.isArray(props.columns); | ||
} | ||
|
||
const SkeletonTable: React.FunctionComponent<SkeletonTableProps> = (props: SkeletonTableProps) => { | ||
const { variant, rows = 5, caption } = props; | ||
const rowCells = hasCustomColumns(props) ? props.columns.length : props.numberOfColumns; | ||
const rowArray = [ ...new Array(rowCells) ]; | ||
const bodyRows = [ ...new Array(rows) ].map((_, index) => ( | ||
<Tr key={index}> | ||
{rowArray.map((_, index) => ( | ||
<Td key={index}> | ||
<Skeleton /> | ||
</Td> | ||
))} | ||
</Tr> | ||
)); | ||
|
||
return ( | ||
<Table aria-label="Loading" variant={variant}> | ||
{caption && <Caption>{caption}</Caption>} | ||
<Thead> | ||
<Tr> | ||
{hasCustomColumns(props) | ||
? props.columns.map((c, index) => <Th key={index}>{c}</Th>) | ||
: rowArray.map((_, index) => ( | ||
<Th key={index}> | ||
<Skeleton /> | ||
</Th> | ||
))} | ||
</Tr> | ||
</Thead> | ||
<Tbody>{bodyRows}</Tbody> | ||
</Table> | ||
); | ||
}; | ||
|
||
export default SkeletonTable; |
Oops, something went wrong.