@patternfly/react-table 4.44.10 → 4.44.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/esm/components/Table/Table.d.ts +2 -1
  3. package/dist/esm/components/Table/Table.d.ts.map +1 -1
  4. package/dist/esm/components/Table/Table.js.map +1 -1
  5. package/dist/esm/components/Table/TableTypes.d.ts +2 -1
  6. package/dist/esm/components/Table/TableTypes.d.ts.map +1 -1
  7. package/dist/esm/components/Table/TableTypes.js.map +1 -1
  8. package/dist/esm/components/Table/base/provider.d.ts +2 -2
  9. package/dist/esm/components/Table/base/types.d.ts +2 -2
  10. package/dist/esm/components/TableComposable/TableComposable.d.ts +1 -1
  11. package/dist/esm/components/TableComposable/Td.d.ts +1 -1
  12. package/dist/js/components/Table/Table.d.ts +2 -1
  13. package/dist/js/components/Table/Table.d.ts.map +1 -1
  14. package/dist/js/components/Table/Table.js.map +1 -1
  15. package/dist/js/components/Table/TableTypes.d.ts +2 -1
  16. package/dist/js/components/Table/TableTypes.d.ts.map +1 -1
  17. package/dist/js/components/Table/TableTypes.js.map +1 -1
  18. package/dist/js/components/Table/base/provider.d.ts +2 -2
  19. package/dist/js/components/Table/base/types.d.ts +2 -2
  20. package/dist/js/components/TableComposable/TableComposable.d.ts +1 -1
  21. package/dist/js/components/TableComposable/Td.d.ts +1 -1
  22. package/dist/umd/react-table.css +5 -3
  23. package/dist/umd/react-table.min.css +17 -15
  24. package/package.json +6 -6
  25. package/src/components/Table/Table.tsx +2 -1
  26. package/src/components/Table/TableTypes.tsx +2 -1
  27. package/src/components/Table/examples/LegacyTableActions.tsx +218 -0
  28. package/src/components/Table/examples/LegacyTableBasic.tsx +90 -0
  29. package/src/components/Table/examples/LegacyTableCellWidth.tsx +66 -0
  30. package/src/components/Table/examples/LegacyTableCompoundExpandable.tsx +175 -0
  31. package/src/components/Table/examples/LegacyTableControllingText.tsx +51 -0
  32. package/src/components/Table/examples/LegacyTableEmptyState.tsx +48 -0
  33. package/src/components/Table/examples/LegacyTableExpandable.tsx +172 -0
  34. package/src/components/Table/examples/LegacyTableFavoritable.tsx +157 -0
  35. package/src/components/Table/examples/LegacyTableHoverable.tsx +125 -0
  36. package/src/components/Table/examples/LegacyTableMisc.tsx +56 -0
  37. package/src/components/Table/examples/LegacyTableSelectable.tsx +124 -0
  38. package/src/components/Table/examples/LegacyTableSelectableRadio.tsx +54 -0
  39. package/src/components/Table/examples/LegacyTableSortable.tsx +120 -0
  40. package/src/components/Table/examples/LegacyTableSortableCustom.tsx +189 -0
  41. package/src/components/Table/examples/LegacyTableTextModifiers.tsx +31 -0
  42. package/src/components/Table/examples/LegacyTableTree.tsx +213 -0
  43. package/src/components/Table/examples/Table.md +83 -1848
  44. package/src/components/TableComposable/examples/ComposableTable.md +31 -2805
  45. package/src/components/TableComposable/examples/ComposableTableActions.tsx +163 -0
  46. package/src/components/TableComposable/examples/ComposableTableBasic.tsx +89 -0
  47. package/src/components/TableComposable/examples/ComposableTableCellWidth.tsx +56 -0
  48. package/src/components/TableComposable/examples/ComposableTableCompoundExpandable.tsx +103 -0
  49. package/src/components/TableComposable/examples/ComposableTableControllingText.tsx +51 -0
  50. package/src/components/TableComposable/examples/ComposableTableDraggable.tsx +170 -0
  51. package/src/components/TableComposable/examples/ComposableTableEmptyState.tsx +45 -0
  52. package/src/components/TableComposable/examples/ComposableTableExpandable.tsx +195 -0
  53. package/src/components/TableComposable/examples/ComposableTableFavoritable.tsx +118 -0
  54. package/src/components/TableComposable/examples/ComposableTableHoverable.tsx +67 -0
  55. package/src/components/TableComposable/examples/ComposableTableMisc.tsx +92 -0
  56. package/src/components/TableComposable/examples/ComposableTableMultipleStickyColumns.tsx +153 -0
  57. package/src/components/TableComposable/examples/ComposableTableNestedExpandable.tsx +127 -0
  58. package/src/components/TableComposable/examples/ComposableTableNestedHeaders.tsx +202 -0
  59. package/src/components/TableComposable/examples/ComposableTableSelectable.tsx +125 -0
  60. package/src/components/TableComposable/examples/ComposableTableSelectableRadio.tsx +68 -0
  61. package/src/components/TableComposable/examples/ComposableTableSortable.tsx +107 -0
  62. package/src/components/TableComposable/examples/ComposableTableSortableCustom.tsx +175 -0
  63. package/src/components/TableComposable/examples/ComposableTableStickyColumn.tsx +144 -0
  64. package/src/components/TableComposable/examples/ComposableTableStickyColumnsAndHeader.tsx +167 -0
  65. package/src/components/TableComposable/examples/ComposableTableTextModifiers.tsx +33 -0
  66. package/src/components/TableComposable/examples/ComposableTableTree.tsx +201 -0
  67. package/src/demos/Table.md +7 -6
  68. package/src/components/Table/examples/DemoSortableTable.js +0 -65
  69. package/src/components/TableComposable/examples/DemoSortableTable.js +0 -65
@@ -0,0 +1,163 @@
1
+ /* eslint-disable no-console */
2
+ import React from 'react';
3
+ import {
4
+ ButtonVariant,
5
+ DropdownToggle,
6
+ ToggleGroup,
7
+ ToggleGroupItem,
8
+ ToggleGroupItemProps
9
+ } from '@patternfly/react-core';
10
+ import {
11
+ TableComposable,
12
+ Thead,
13
+ Tr,
14
+ Th,
15
+ Tbody,
16
+ Td,
17
+ CustomActionsToggleProps,
18
+ ActionsColumn,
19
+ IAction
20
+ } from '@patternfly/react-table';
21
+
22
+ interface Repository {
23
+ name: string;
24
+ branches: string;
25
+ prs: string;
26
+ workspaces: string;
27
+ lastCommit: string;
28
+ }
29
+
30
+ type ExampleType = 'defaultToggle' | 'customToggle';
31
+
32
+ export const ComposableTableActions: React.FunctionComponent = () => {
33
+ // In real usage, this data would come from some external source like an API via props.
34
+ const repositories: Repository[] = [
35
+ { name: 'one', branches: 'two', prs: 'a', workspaces: 'four', lastCommit: 'five' },
36
+ { name: 'a', branches: 'two', prs: 'k', workspaces: 'four', lastCommit: 'five' },
37
+ { name: 'p', branches: 'two', prs: 'b', workspaces: 'four', lastCommit: 'five' },
38
+ { name: '4', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five' },
39
+ { name: '5', branches: '2', prs: 'b', workspaces: 'four', lastCommit: 'five' }
40
+ ];
41
+
42
+ const columnNames = {
43
+ name: 'Repositories',
44
+ branches: 'Branches',
45
+ prs: 'Pull requests',
46
+ workspaces: 'Workspaces',
47
+ lastCommit: 'Last commit'
48
+ };
49
+
50
+ // This state is just for the ToggleGroup in this example and isn't necessary for TableComposable usage.
51
+ const [exampleChoice, setExampleChoice] = React.useState<ExampleType>('defaultToggle');
52
+ const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (_isSelected, event) => {
53
+ const id = event.currentTarget.id;
54
+ setExampleChoice(id as ExampleType);
55
+ };
56
+
57
+ const customActionsToggle = (props: CustomActionsToggleProps) => (
58
+ <DropdownToggle onToggle={props.onToggle} isDisabled={props.isDisabled}>
59
+ Actions
60
+ </DropdownToggle>
61
+ );
62
+
63
+ const defaultActions = (repo: Repository): IAction[] => [
64
+ {
65
+ title: 'Some action',
66
+ onClick: () => console.log(`clicked on Some action, on row ${repo.name}`)
67
+ },
68
+ {
69
+ title: <a href="https://www.patternfly.org">Link action</a>
70
+ },
71
+ {
72
+ isSeparator: true
73
+ },
74
+ {
75
+ title: 'Third action',
76
+ onClick: () => console.log(`clicked on Third action, on row ${repo.name}`)
77
+ },
78
+ {
79
+ title: 'Start',
80
+ variant: ButtonVariant.secondary,
81
+ onClick: () => console.log(`clicked on extra action, on row ${repo.name}`),
82
+ isOutsideDropdown: true
83
+ }
84
+ ];
85
+
86
+ const lastRowActions = (repo: Repository): IAction[] => [
87
+ {
88
+ title: 'Some action',
89
+ onClick: () => console.log(`clicked on Some action, on row ${repo.name}`)
90
+ },
91
+ {
92
+ title: <div>Another action</div>,
93
+ onClick: () => console.log(`clicked on Another action, on row ${repo.name}`)
94
+ },
95
+ {
96
+ isSeparator: true
97
+ },
98
+ {
99
+ title: 'Third action',
100
+ onClick: () => console.log(`clicked on Third action, on row ${repo.name}`)
101
+ }
102
+ ];
103
+
104
+ return (
105
+ <React.Fragment>
106
+ <ToggleGroup aria-label="Default uses kebab toggle">
107
+ <ToggleGroupItem
108
+ text="Default actions toggle"
109
+ buttonId="defaultToggle"
110
+ isSelected={exampleChoice === 'defaultToggle'}
111
+ onChange={onExampleTypeChange}
112
+ />
113
+ <ToggleGroupItem
114
+ text="Custom actions toggle"
115
+ buttonId="customToggle"
116
+ isSelected={exampleChoice === 'customToggle'}
117
+ onChange={onExampleTypeChange}
118
+ />
119
+ </ToggleGroup>
120
+ <TableComposable aria-label="Actions table">
121
+ <Thead>
122
+ <Tr>
123
+ <Th>{columnNames.name}</Th>
124
+ <Th>{columnNames.branches}</Th>
125
+ <Th>{columnNames.prs}</Th>
126
+ <Th>{columnNames.workspaces}</Th>
127
+ <Th>{columnNames.lastCommit}</Th>
128
+ </Tr>
129
+ </Thead>
130
+ <Tbody>
131
+ {repositories.map(repo => {
132
+ // Arbitrary logic to determine which rows get which actions in this example
133
+ let rowActions: IAction[] | null = defaultActions(repo);
134
+ if (repo.name === 'a') {
135
+ rowActions = null;
136
+ }
137
+ if (repo.name === '5') {
138
+ rowActions = lastRowActions(repo);
139
+ }
140
+ return (
141
+ <Tr key={repo.name}>
142
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
143
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
144
+ <Td dataLabel={columnNames.prs}>{repo.prs}</Td>
145
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
146
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
147
+ <Td>
148
+ {rowActions ? (
149
+ <ActionsColumn
150
+ items={rowActions}
151
+ isDisabled={repo.name === '4'} // Also arbitrary for the example
152
+ actionsToggle={exampleChoice === 'customToggle' ? customActionsToggle : undefined}
153
+ />
154
+ ) : null}
155
+ </Td>
156
+ </Tr>
157
+ );
158
+ })}
159
+ </Tbody>
160
+ </TableComposable>
161
+ </React.Fragment>
162
+ );
163
+ };
@@ -0,0 +1,89 @@
1
+ import React from 'react';
2
+ import { ToggleGroup, ToggleGroupItem, ToggleGroupItemProps } from '@patternfly/react-core';
3
+ import { TableComposable, Caption, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
4
+
5
+ interface Repository {
6
+ name: string;
7
+ branches: string | null;
8
+ prs: string | null;
9
+ workspaces: string;
10
+ lastCommit: string;
11
+ }
12
+
13
+ type ExampleType = 'default' | 'compact' | 'compactBorderless';
14
+
15
+ export const ComposableTableBasic: React.FunctionComponent = () => {
16
+ // In real usage, this data would come from some external source like an API via props.
17
+ const repositories: Repository[] = [
18
+ { name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
19
+ { name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
20
+ { name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
21
+ ];
22
+
23
+ const columnNames = {
24
+ name: 'Repositories',
25
+ branches: 'Branches',
26
+ prs: 'Pull requests',
27
+ workspaces: 'Workspaces',
28
+ lastCommit: 'Last commit'
29
+ };
30
+
31
+ // This state is just for the ToggleGroup in this example and isn't necessary for TableComposable usage.
32
+ const [exampleChoice, setExampleChoice] = React.useState<ExampleType>('default');
33
+ const onExampleTypeChange: ToggleGroupItemProps['onChange'] = (_isSelected, event) => {
34
+ const id = event.currentTarget.id;
35
+ setExampleChoice(id as ExampleType);
36
+ };
37
+
38
+ return (
39
+ <React.Fragment>
40
+ <ToggleGroup aria-label="Default with single selectable">
41
+ <ToggleGroupItem
42
+ text="Default"
43
+ buttonId="default"
44
+ isSelected={exampleChoice === 'default'}
45
+ onChange={onExampleTypeChange}
46
+ />
47
+ <ToggleGroupItem
48
+ text="Compact"
49
+ buttonId="compact"
50
+ isSelected={exampleChoice === 'compact'}
51
+ onChange={onExampleTypeChange}
52
+ />
53
+ <ToggleGroupItem
54
+ text="Compact borderless"
55
+ buttonId="compactBorderless"
56
+ isSelected={exampleChoice === 'compactBorderless'}
57
+ onChange={onExampleTypeChange}
58
+ />
59
+ </ToggleGroup>
60
+ <TableComposable
61
+ aria-label="Simple table"
62
+ variant={exampleChoice !== 'default' ? 'compact' : undefined}
63
+ borders={exampleChoice !== 'compactBorderless'}
64
+ >
65
+ <Caption>Simple table using composable components</Caption>
66
+ <Thead>
67
+ <Tr>
68
+ <Th>{columnNames.name}</Th>
69
+ <Th>{columnNames.branches}</Th>
70
+ <Th>{columnNames.prs}</Th>
71
+ <Th>{columnNames.workspaces}</Th>
72
+ <Th>{columnNames.lastCommit}</Th>
73
+ </Tr>
74
+ </Thead>
75
+ <Tbody>
76
+ {repositories.map(repo => (
77
+ <Tr key={repo.name}>
78
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
79
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
80
+ <Td dataLabel={columnNames.prs}>{repo.prs}</Td>
81
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
82
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
83
+ </Tr>
84
+ ))}
85
+ </Tbody>
86
+ </TableComposable>
87
+ </React.Fragment>
88
+ );
89
+ };
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
+
4
+ interface Repository {
5
+ name: string;
6
+ branches: string | null;
7
+ prs: string | null;
8
+ workspaces: string;
9
+ lastCommit: string;
10
+ }
11
+
12
+ export const ComposableTableCellWidth: React.FunctionComponent = () => {
13
+ // In real usage, this data would come from some external source like an API via props.
14
+ const repositories: Repository[] = [
15
+ { name: 'one', branches: 'two', prs: 'three', workspaces: 'four', lastCommit: 'five' },
16
+ { name: 'one - 2', branches: null, prs: null, workspaces: 'four - 2', lastCommit: 'five - 2' },
17
+ { name: 'one - 3', branches: 'two - 3', prs: 'three - 3', workspaces: 'four - 3', lastCommit: 'five - 3' }
18
+ ];
19
+
20
+ const columnNames = {
21
+ name: 'Repositories',
22
+ branches: 'Branches',
23
+ prs: 'Pull requests',
24
+ workspaces: 'Workspaces',
25
+ lastCommit: 'Last commit'
26
+ };
27
+
28
+ return (
29
+ <TableComposable aria-label="Cell widths">
30
+ <Thead>
31
+ <Tr>
32
+ <Th width={15}>{columnNames.name}</Th>
33
+ <Th width={15}>{columnNames.branches}</Th>
34
+ <Th width={40} visibility={['hiddenOnMd', 'visibleOnLg']}>
35
+ {columnNames.prs}
36
+ </Th>
37
+ <Th width={15}>{columnNames.workspaces}</Th>
38
+ <Th width={15}>{columnNames.lastCommit}</Th>
39
+ </Tr>
40
+ </Thead>
41
+ <Tbody>
42
+ {repositories.map(repo => (
43
+ <Tr key={repo.name}>
44
+ <Td dataLabel={columnNames.name}>{repo.name}</Td>
45
+ <Td dataLabel={columnNames.branches}>{repo.branches}</Td>
46
+ <Td dataLabel={columnNames.prs} visibility={['hiddenOnMd', 'visibleOnLg']}>
47
+ {repo.prs}
48
+ </Td>
49
+ <Td dataLabel={columnNames.workspaces}>{repo.workspaces}</Td>
50
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
51
+ </Tr>
52
+ ))}
53
+ </Tbody>
54
+ </TableComposable>
55
+ );
56
+ };
@@ -0,0 +1,103 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td, TdProps, ExpandableRowContent } from '@patternfly/react-table';
3
+
4
+ import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
5
+ import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
6
+ import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
7
+
8
+ interface Repository {
9
+ name: string;
10
+ branches: number;
11
+ prs: number;
12
+ workspaces: number;
13
+ lastCommit: string;
14
+ }
15
+
16
+ export const ComposableTableCompoundExpandable: React.FunctionComponent = () => {
17
+ // In real usage, this data would come from some external source like an API via props.
18
+ const repositories: Repository[] = [
19
+ { name: 'siemur/test-space', branches: 10, prs: 4, workspaces: 4, lastCommit: '20 minutes' },
20
+ { name: 'siemur/test-space-2', branches: 3, prs: 4, workspaces: 4, lastCommit: '20 minutes' }
21
+ ];
22
+
23
+ const columnNames = {
24
+ name: 'Repositories',
25
+ branches: 'Branches',
26
+ prs: 'Pull requests',
27
+ workspaces: 'Workspaces',
28
+ lastCommit: 'Last commit'
29
+ };
30
+ type ColumnKey = keyof typeof columnNames;
31
+
32
+ // In this example, expanded cells are tracked by the repo and property names from each row. This could be any pair of unique identifiers.
33
+ // This is to prevent state from being based on row and column order index in case we later add sorting and rearranging columns.
34
+ // Note that this behavior is very similar to selection state.
35
+ const [expandedCells, setExpandedCells] = React.useState<Record<string, ColumnKey>>({
36
+ 'siemur/test-space': 'branches' // Default to the first cell of the first row being expanded
37
+ });
38
+ const setCellExpanded = (repo: Repository, columnKey: ColumnKey, isExpanding = true) => {
39
+ const newExpandedCells = { ...expandedCells };
40
+ if (isExpanding) {
41
+ newExpandedCells[repo.name] = columnKey;
42
+ } else {
43
+ delete newExpandedCells[repo.name];
44
+ }
45
+ setExpandedCells(newExpandedCells);
46
+ };
47
+ const compoundExpandParams = (repo: Repository, columnKey: ColumnKey): TdProps['compoundExpand'] => ({
48
+ isExpanded: expandedCells[repo.name] === columnKey,
49
+ onToggle: () => setCellExpanded(repo, columnKey, expandedCells[repo.name] !== columnKey)
50
+ });
51
+
52
+ return (
53
+ <TableComposable aria-label="Compound expandable table">
54
+ <Thead>
55
+ <Tr>
56
+ <Th>{columnNames.name}</Th>
57
+ <Th>{columnNames.branches}</Th>
58
+ <Th>{columnNames.prs}</Th>
59
+ <Th>{columnNames.workspaces}</Th>
60
+ <Th>{columnNames.lastCommit}</Th>
61
+ <Th />
62
+ </Tr>
63
+ </Thead>
64
+ {repositories.map(repo => {
65
+ const expandedCellKey = expandedCells[repo.name];
66
+ const isRowExpanded = !!expandedCellKey;
67
+ return (
68
+ <Tbody key={repo.name} isExpanded={isRowExpanded}>
69
+ <Tr>
70
+ <Td dataLabel={columnNames.name} component="th">
71
+ <a href="#">{repo.name}</a>
72
+ </Td>
73
+ <Td dataLabel={columnNames.branches} compoundExpand={compoundExpandParams(repo, 'branches')}>
74
+ <CodeBranchIcon key="icon" /> {repo.branches}
75
+ </Td>
76
+ <Td dataLabel={columnNames.prs} compoundExpand={compoundExpandParams(repo, 'prs')}>
77
+ <CodeIcon key="icon" /> {repo.prs}
78
+ </Td>
79
+ <Td dataLabel={columnNames.workspaces} compoundExpand={compoundExpandParams(repo, 'workspaces')}>
80
+ <CubeIcon key="icon" /> {repo.workspaces}
81
+ </Td>
82
+ <Td dataLabel={columnNames.lastCommit}>{repo.lastCommit}</Td>
83
+ <Td>
84
+ <a href="#">Open in GitHub</a>
85
+ </Td>
86
+ </Tr>
87
+ {isRowExpanded ? (
88
+ <Tr isExpanded={isRowExpanded}>
89
+ <Td dataLabel={columnNames[expandedCellKey]} noPadding colSpan={6}>
90
+ <ExpandableRowContent>
91
+ <div className="pf-u-m-md">
92
+ Expanded content for {repo.name}: {expandedCellKey} goes here!
93
+ </div>
94
+ </ExpandableRowContent>
95
+ </Td>
96
+ </Tr>
97
+ ) : null}
98
+ </Tbody>
99
+ );
100
+ })}
101
+ </TableComposable>
102
+ );
103
+ };
@@ -0,0 +1,51 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
+
4
+ // This example has been simplified to focus on the text modifier props. In real usage,
5
+ // you may want to derive your rows from typed underlying data and minimal state. See other examples.
6
+
7
+ const columnNames = {
8
+ truncate: 'Truncate (width 20%)',
9
+ break: 'Break word',
10
+ wrap: 'Wrapping table header text. This th text will wrap instead of truncate.',
11
+ fit: 'Fit content',
12
+ nowrap: 'No wrap'
13
+ };
14
+
15
+ export const ComposableTableControllingText: React.FunctionComponent = () => (
16
+ <TableComposable aria-label="Controlling text">
17
+ <Thead>
18
+ <Tr>
19
+ <Th width={20}>{columnNames.truncate}</Th>
20
+ <Th>{columnNames.break}</Th>
21
+ <Th modifier="wrap">{columnNames.wrap}</Th>
22
+ <Th modifier="fitContent">{columnNames.fit}</Th>
23
+ <Th>{columnNames.nowrap}</Th>
24
+ </Tr>
25
+ </Thead>
26
+ <Tbody>
27
+ <Tr>
28
+ <Td dataLabel={columnNames.truncate} modifier="truncate">
29
+ This text will truncate instead of wrap.
30
+ </Td>
31
+ <Td dataLabel={columnNames.break} modifier="breakWord">
32
+ <a>http://thisisaverylongurlthatneedstobreakusethebreakwordmodifier.org</a>
33
+ </Td>
34
+ <Td dataLabel={columnNames.wrap}>
35
+ <p>
36
+ By default,
37
+ <code>thead</code> cells will truncate and
38
+ <code>tbody</code> cells will wrap. Use
39
+ <code>.pf-m-wrap</code> on a<code>th</code> to change its behavior.
40
+ </p>
41
+ </Td>
42
+ <Td dataLabel={columnNames.fit}>
43
+ This cell's content will adjust itself to the parent th width. This modifier only affects table layouts.
44
+ </Td>
45
+ <Td dataLabel={columnNames.nowrap} modifier="nowrap">
46
+ <a href="#">No wrap</a>
47
+ </Td>
48
+ </Tr>
49
+ </Tbody>
50
+ </TableComposable>
51
+ );
@@ -0,0 +1,170 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tbody, Tr, Th, Td, TbodyProps, TrProps } from '@patternfly/react-table';
3
+ import styles from '@patternfly/react-styles/css/components/Table/table';
4
+
5
+ export const ComposableTableDraggable: React.FunctionComponent = () => {
6
+ const [draggedItemId, setDraggedItemId] = React.useState<string | null>(null);
7
+ const [draggingToItemIndex, setDraggingToItemIndex] = React.useState<number | null>(null);
8
+ const [isDragging, setIsDragging] = React.useState(false);
9
+ const [itemOrder, setItemOrder] = React.useState(['row1', 'row2', 'row3']);
10
+ const [tempItemOrder, setTempItemOrder] = React.useState<string[]>([]);
11
+
12
+ const bodyRef = React.useRef<HTMLTableSectionElement>();
13
+
14
+ const onDragStart: TrProps['onDragStart'] = evt => {
15
+ evt.dataTransfer.effectAllowed = 'move';
16
+ evt.dataTransfer.setData('text/plain', evt.currentTarget.id);
17
+ const draggedItemId = evt.currentTarget.id;
18
+
19
+ evt.currentTarget.classList.add(styles.modifiers.ghostRow);
20
+ evt.currentTarget.setAttribute('aria-pressed', 'true');
21
+
22
+ setDraggedItemId(draggedItemId);
23
+ setIsDragging(true);
24
+ };
25
+
26
+ const moveItem = (arr: string[], i1: string, toIndex: number) => {
27
+ const fromIndex = arr.indexOf(i1);
28
+ if (fromIndex === toIndex) {
29
+ return arr;
30
+ }
31
+ const temp = arr.splice(fromIndex, 1);
32
+ arr.splice(toIndex, 0, temp[0]);
33
+
34
+ return arr;
35
+ };
36
+
37
+ const move = (itemOrder: string[]) => {
38
+ const ulNode = bodyRef.current;
39
+ const nodes = Array.from(ulNode.children);
40
+ if (nodes.map(node => node.id).every((id, i) => id === itemOrder[i])) {
41
+ return;
42
+ }
43
+ while (ulNode.firstChild) {
44
+ ulNode.removeChild(ulNode.lastChild);
45
+ }
46
+
47
+ itemOrder.forEach(id => {
48
+ ulNode.appendChild(nodes.find(n => n.id === id));
49
+ });
50
+ };
51
+
52
+ const onDragCancel = () => {
53
+ Array.from(bodyRef.current.children).forEach(el => {
54
+ el.classList.remove(styles.modifiers.ghostRow);
55
+ el.setAttribute('aria-pressed', 'false');
56
+ });
57
+ setDraggedItemId(null);
58
+ setDraggingToItemIndex(null);
59
+ setIsDragging(false);
60
+ };
61
+
62
+ const onDragLeave: TbodyProps['onDragLeave'] = evt => {
63
+ if (!isValidDrop(evt)) {
64
+ move(itemOrder);
65
+ setDraggingToItemIndex(null);
66
+ }
67
+ };
68
+
69
+ const isValidDrop = (evt: React.DragEvent<HTMLTableSectionElement | HTMLTableRowElement>) => {
70
+ const ulRect = bodyRef.current.getBoundingClientRect();
71
+ return (
72
+ evt.clientX > ulRect.x &&
73
+ evt.clientX < ulRect.x + ulRect.width &&
74
+ evt.clientY > ulRect.y &&
75
+ evt.clientY < ulRect.y + ulRect.height
76
+ );
77
+ };
78
+
79
+ const onDrop: TrProps['onDrop'] = evt => {
80
+ if (isValidDrop(evt)) {
81
+ setItemOrder(tempItemOrder);
82
+ } else {
83
+ onDragCancel();
84
+ }
85
+ };
86
+
87
+ const onDragOver: TbodyProps['onDragOver'] = evt => {
88
+ evt.preventDefault();
89
+
90
+ const curListItem = (evt.target as HTMLTableSectionElement).closest('tr');
91
+ if (!curListItem || !bodyRef.current.contains(curListItem) || curListItem.id === draggedItemId) {
92
+ return null;
93
+ } else {
94
+ const dragId = curListItem.id;
95
+ const newDraggingToItemIndex = Array.from(bodyRef.current.children).findIndex(item => item.id === dragId);
96
+ if (newDraggingToItemIndex !== draggingToItemIndex) {
97
+ const tempItemOrder = moveItem([...itemOrder], draggedItemId, newDraggingToItemIndex);
98
+ move(tempItemOrder);
99
+ setDraggingToItemIndex(newDraggingToItemIndex);
100
+ setTempItemOrder(tempItemOrder);
101
+ }
102
+ }
103
+ };
104
+
105
+ const onDragEnd: TrProps['onDragEnd'] = evt => {
106
+ const target = evt.target as HTMLTableRowElement;
107
+ target.classList.remove(styles.modifiers.ghostRow);
108
+ target.setAttribute('aria-pressed', 'false');
109
+ setDraggedItemId(null);
110
+ setDraggingToItemIndex(null);
111
+ setIsDragging(false);
112
+ };
113
+
114
+ const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];
115
+ const rows = [
116
+ {
117
+ id: 'row1',
118
+ repository: 'one',
119
+ branch: 'two',
120
+ pullRequest: 'three',
121
+ workspace: 'four',
122
+ lastCommit: 'five'
123
+ },
124
+ {
125
+ id: 'row2',
126
+ repository: 'one -2',
127
+ branch: null,
128
+ pullRequest: null,
129
+ workspace: 'four -2',
130
+ lastCommit: 'five -2'
131
+ },
132
+ {
133
+ id: 'row3',
134
+ repository: 'one - 3',
135
+ branch: 'two - 3',
136
+ pullRequest: 'three - 3',
137
+ workspace: 'four - 3',
138
+ lastCommit: 'five - 3'
139
+ }
140
+ ];
141
+
142
+ return (
143
+ <TableComposable aria-label="Draggable table" className={isDragging && styles.modifiers.dragOver}>
144
+ <Thead>
145
+ <Tr>
146
+ <Th />
147
+ {columns.map((column, columnIndex) => (
148
+ <Th key={columnIndex}>{column}</Th>
149
+ ))}
150
+ </Tr>
151
+ </Thead>
152
+ <Tbody ref={bodyRef} onDragOver={onDragOver} onDrop={onDragOver} onDragLeave={onDragLeave}>
153
+ {rows.map((row, rowIndex) => (
154
+ <Tr key={rowIndex} id={row.id} draggable onDrop={onDrop} onDragEnd={onDragEnd} onDragStart={onDragStart}>
155
+ <Td
156
+ draggableRow={{
157
+ id: `draggable-row-${row.id}`
158
+ }}
159
+ />
160
+ {Object.keys(row).map((key, keyIndex) => (
161
+ <Td key={`${rowIndex}_${keyIndex}`} dataLabel={columns[keyIndex]}>
162
+ {row[key]}
163
+ </Td>
164
+ ))}
165
+ </Tr>
166
+ ))}
167
+ </Tbody>
168
+ </TableComposable>
169
+ );
170
+ };
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { TableComposable, Thead, Tr, Th, Tbody, Td } from '@patternfly/react-table';
3
+ import {
4
+ Bullseye,
5
+ EmptyState,
6
+ EmptyStateVariant,
7
+ EmptyStateIcon,
8
+ Title,
9
+ EmptyStateBody,
10
+ Button
11
+ } from '@patternfly/react-core';
12
+ import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
13
+
14
+ // This example has been simplified to focus on the empty state. In real usage,
15
+ // you may want to derive your rows from typed underlying data and minimal state. See other examples.
16
+
17
+ export const ComposableTableEmptyState: React.FunctionComponent = () => (
18
+ <TableComposable aria-label="Empty state table">
19
+ <Thead>
20
+ <Tr>
21
+ <Th>Repositories</Th>
22
+ <Th>Branches</Th>
23
+ <Th>Pull requests</Th>
24
+ <Th>Workspaces</Th>
25
+ <Th>Last commit</Th>
26
+ </Tr>
27
+ </Thead>
28
+ <Tbody>
29
+ <Tr>
30
+ <Td colSpan={8}>
31
+ <Bullseye>
32
+ <EmptyState variant={EmptyStateVariant.small}>
33
+ <EmptyStateIcon icon={SearchIcon} />
34
+ <Title headingLevel="h2" size="lg">
35
+ No results found
36
+ </Title>
37
+ <EmptyStateBody>Clear all filters and try again.</EmptyStateBody>
38
+ <Button variant="link">Clear all filters</Button>
39
+ </EmptyState>
40
+ </Bullseye>
41
+ </Td>
42
+ </Tr>
43
+ </Tbody>
44
+ </TableComposable>
45
+ );