Skip to content

Commit

Permalink
feat(Table): Added isNoInset prop for flat tree tables (#9427)
Browse files Browse the repository at this point in the history
* feat(Table): Added isNoInset prop for flat tree tables

* address PR comments

* add example

* fix linting and a11y errors
  • Loading branch information
nicolethoen authored Aug 16, 2023
1 parent 3bcd263 commit 2d5df3d
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/react-table/src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export interface TableProps extends React.HTMLProps<HTMLTableElement>, OUIAProps
isStriped?: boolean;
/** Flag indicating this table contains expandable rows to maintain proper striping */
isExpandable?: boolean;
/** Flag indicating this table's rows will not have the inset typically reserved for expanding/collapsing rows in a tree table. Intended for use on tree tables with no visible rows with children. */
hasNoInset?: boolean;
/** Collection of column spans for nested headers. Deprecated: see https://github.com/patternfly/patternfly/issues/4584 */
nestedHeaderColumnSpans?: number[];
/** Visible text to add alongside the hidden a11y caption for tables with selectable rows. */
Expand Down Expand Up @@ -91,6 +93,7 @@ const TableBase: React.FunctionComponent<TableProps> = ({
isNested = false,
isStriped = false,
isExpandable = false,
hasNoInset = false,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
nestedHeaderColumnSpans,
selectableRowCaptionText,
Expand Down Expand Up @@ -206,6 +209,7 @@ const TableBase: React.FunctionComponent<TableProps> = ({
isTreeTable && stylesTreeView.modifiers.treeView,
isStriped && styles.modifiers.striped,
isExpandable && styles.modifiers.expandable,
hasNoInset && stylesTreeView.modifiers.noInset,
isNested && 'pf-m-nested'
)}
ref={tableRef}
Expand Down
7 changes: 7 additions & 0 deletions packages/react-table/src/components/Table/examples/Table.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,13 @@ the voice over technologies will recognize the flat table structure as a tree.
```ts file="TableTree.tsx"
```

### Flat tree table with no inset

To remove the inset used to leave space for the expand/collapse toggle in a flat tree table, use the `hasNoInset` prop on the `Table` component.

```ts file="TableTreeNoInset.tsx"
```

### Draggable row table

To make a row draggable:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import React from 'react';
import { Table, Thead, Tr, Th, Tbody, Td, TreeRowWrapper, TdProps } from '@patternfly/react-table';
import LeafIcon from '@patternfly/react-icons/dist/esm/icons/leaf-icon';

interface RepositoriesTreeNode {
name: string;
branches: string;
pullRequests: string;
workspaces: string;
children?: RepositoriesTreeNode[];
}

export const TableTreeNoInset: React.FunctionComponent = () => {
// In real usage, this data would come from some external source like an API via props.
const data: RepositoriesTreeNode[] = [
{
name: 'Repositories one',
branches: 'Branch one',
pullRequests: 'Pull request one',
workspaces: 'Workplace one',
children: []
},
{
name: 'Repositories seven',
branches: 'Branch seven',
pullRequests: 'Pull request seven',
workspaces: 'Workplace seven',
children: []
},
{
name: 'Repositories nine',
branches: 'Branch nine',
pullRequests: 'Pull request nine',
workspaces: 'Workplace nine'
}
];

const columnNames = {
name: 'Repositories',
branches: 'Branches',
prs: 'Pull requests',
workspaces: 'Workspaces'
};

const [selectedNodeNames, setSelectedNodeNames] = React.useState<string[]>([]);
const isNodeChecked = (node: RepositoriesTreeNode) => selectedNodeNames.includes(node.name);

/**
Recursive function which flattens the data into an array of flattened TreeRowWrapper components
params:
- nodes - array of a single level of tree nodes
- level - number representing how deeply nested the current row is
- posinset - position of the row relative to this row's siblings
- currentRowIndex - position of the row relative to the entire table
- isHidden - defaults to false, true if this row's parent is expanded
*/
const renderRows = (
[node, ...remainingNodes]: RepositoriesTreeNode[],
level = 1,
posinset = 1,
rowIndex = 0,
isHidden = false
): React.ReactNode[] => {
if (!node) {
return [];
}
const isChecked = isNodeChecked(node);
const icon = <LeafIcon />;

const treeRow: TdProps['treeRow'] = {
onCollapse: () => {},
onToggleRowDetails: () => {},
onCheckChange: (_event, isChecking) => {
setSelectedNodeNames(prevSelected => {
const otherSelectedNodeNames = prevSelected.filter(name => name === node.name);
return !isChecking ? otherSelectedNodeNames : [...otherSelectedNodeNames, node.name];
});
},
rowIndex,
props: {
isHidden,
'aria-level': level,
'aria-posinset': posinset,
'aria-setsize': node.children ? node.children.length : 0,
isChecked,
checkboxId: `flat_checkbox_id_${node.name.toLowerCase().replace(/\s+/g, '_')}`,
icon
}
};

const childRows =
node.children && node.children.length
? renderRows(node.children, level + 1, 1, rowIndex + 1, isHidden)
: [];

return [
<TreeRowWrapper key={node.name} row={{ props: treeRow.props }}>
<Td dataLabel={columnNames.name} treeRow={treeRow}>
{node.name}
</Td>
<Td dataLabel={columnNames.branches}>{node.branches}</Td>
<Td dataLabel={columnNames.prs}>{node.pullRequests}</Td>
<Td dataLabel={columnNames.workspaces}>{node.workspaces}</Td>
</TreeRowWrapper>,
...childRows,
...renderRows(remainingNodes, level, posinset + 1, rowIndex + 1 + childRows.length, isHidden)
];
};

return (
<Table isTreeTable aria-label="Tree table" hasNoInset>
<Thead>
<Tr>
<Th width={40}>{columnNames.name}</Th>
<Th>{columnNames.branches}</Th>
<Th>{columnNames.prs}</Th>
<Th>{columnNames.workspaces}</Th>
</Tr>
</Thead>
<Tbody>{renderRows(data)}</Tbody>
</Table>
);
};

0 comments on commit 2d5df3d

Please sign in to comment.