@patternfly/react-table 4.44.12 → 4.44.13

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 (67) hide show
  1. package/CHANGELOG.md +8 -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/package.json +6 -6
  23. package/src/components/Table/Table.tsx +2 -1
  24. package/src/components/Table/TableTypes.tsx +2 -1
  25. package/src/components/Table/examples/LegacyTableActions.tsx +218 -0
  26. package/src/components/Table/examples/LegacyTableBasic.tsx +90 -0
  27. package/src/components/Table/examples/LegacyTableCellWidth.tsx +66 -0
  28. package/src/components/Table/examples/LegacyTableCompoundExpandable.tsx +175 -0
  29. package/src/components/Table/examples/LegacyTableControllingText.tsx +51 -0
  30. package/src/components/Table/examples/LegacyTableEmptyState.tsx +48 -0
  31. package/src/components/Table/examples/LegacyTableExpandable.tsx +172 -0
  32. package/src/components/Table/examples/LegacyTableFavoritable.tsx +157 -0
  33. package/src/components/Table/examples/LegacyTableHoverable.tsx +125 -0
  34. package/src/components/Table/examples/LegacyTableMisc.tsx +56 -0
  35. package/src/components/Table/examples/LegacyTableSelectable.tsx +124 -0
  36. package/src/components/Table/examples/LegacyTableSelectableRadio.tsx +54 -0
  37. package/src/components/Table/examples/LegacyTableSortable.tsx +120 -0
  38. package/src/components/Table/examples/LegacyTableSortableCustom.tsx +189 -0
  39. package/src/components/Table/examples/LegacyTableTextModifiers.tsx +31 -0
  40. package/src/components/Table/examples/LegacyTableTree.tsx +213 -0
  41. package/src/components/Table/examples/Table.md +83 -1848
  42. package/src/components/TableComposable/examples/ComposableTable.md +31 -2805
  43. package/src/components/TableComposable/examples/ComposableTableActions.tsx +163 -0
  44. package/src/components/TableComposable/examples/ComposableTableBasic.tsx +89 -0
  45. package/src/components/TableComposable/examples/ComposableTableCellWidth.tsx +56 -0
  46. package/src/components/TableComposable/examples/ComposableTableCompoundExpandable.tsx +103 -0
  47. package/src/components/TableComposable/examples/ComposableTableControllingText.tsx +51 -0
  48. package/src/components/TableComposable/examples/ComposableTableDraggable.tsx +170 -0
  49. package/src/components/TableComposable/examples/ComposableTableEmptyState.tsx +45 -0
  50. package/src/components/TableComposable/examples/ComposableTableExpandable.tsx +195 -0
  51. package/src/components/TableComposable/examples/ComposableTableFavoritable.tsx +118 -0
  52. package/src/components/TableComposable/examples/ComposableTableHoverable.tsx +67 -0
  53. package/src/components/TableComposable/examples/ComposableTableMisc.tsx +92 -0
  54. package/src/components/TableComposable/examples/ComposableTableMultipleStickyColumns.tsx +153 -0
  55. package/src/components/TableComposable/examples/ComposableTableNestedExpandable.tsx +127 -0
  56. package/src/components/TableComposable/examples/ComposableTableNestedHeaders.tsx +202 -0
  57. package/src/components/TableComposable/examples/ComposableTableSelectable.tsx +125 -0
  58. package/src/components/TableComposable/examples/ComposableTableSelectableRadio.tsx +68 -0
  59. package/src/components/TableComposable/examples/ComposableTableSortable.tsx +107 -0
  60. package/src/components/TableComposable/examples/ComposableTableSortableCustom.tsx +175 -0
  61. package/src/components/TableComposable/examples/ComposableTableStickyColumn.tsx +144 -0
  62. package/src/components/TableComposable/examples/ComposableTableStickyColumnsAndHeader.tsx +167 -0
  63. package/src/components/TableComposable/examples/ComposableTableTextModifiers.tsx +33 -0
  64. package/src/components/TableComposable/examples/ComposableTableTree.tsx +201 -0
  65. package/src/demos/Table.md +7 -6
  66. package/src/components/Table/examples/DemoSortableTable.js +0 -65
  67. package/src/components/TableComposable/examples/DemoSortableTable.js +0 -65
@@ -30,8 +30,6 @@ import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amou
30
30
  import { css } from '@patternfly/react-styles';
31
31
  import styles from '@patternfly/react-styles/css/components/Table/table';
32
32
 
33
- import DemoSortableTable from './DemoSortableTable';
34
-
35
33
  ### Table Columns
36
34
 
37
35
  Array items for columns provided to the `Table`'s `cells` prop, can be simple strings or objects.
@@ -118,73 +116,7 @@ interface IRowCell {
118
116
 
119
117
  ### Basic
120
118
 
121
- ```js
122
- import React from 'react';
123
- import { Table, TableHeader, TableBody } from '@patternfly/react-table';
124
- import { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
125
-
126
- class SimpleTable extends React.Component {
127
- constructor(props) {
128
- super(props);
129
- this.state = {
130
- choice: 'default'
131
- };
132
- this.handleItemClick = this.handleItemClick.bind(this);
133
- }
134
-
135
- handleItemClick(isSelected, event) {
136
- this.setState({
137
- choice: event.currentTarget.id
138
- });
139
- }
140
-
141
- render() {
142
- // need to make a comment to change
143
- const { choice } = this.state;
144
-
145
- const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];
146
- const rows = [
147
- ['Repository one', 'Branch one', 'PR one', 'Workspace one', 'Commit one'],
148
- ['Repository two', 'Branch two', 'PR two', 'Workspace two', 'Commit two'],
149
- ['Repository three', 'Branch three', 'PR three', 'Workspace three', 'Commit three']
150
- ];
151
-
152
- return (
153
- <React.Fragment>
154
- <ToggleGroup aria-label="Default with single selectable">
155
- <ToggleGroupItem
156
- text="Default"
157
- buttonId="default"
158
- isSelected={choice === 'default'}
159
- onChange={this.handleItemClick}
160
- />
161
- <ToggleGroupItem
162
- text="Compact"
163
- buttonId="compact"
164
- isSelected={choice === 'compact'}
165
- onChange={this.handleItemClick}
166
- />
167
- <ToggleGroupItem
168
- text="Compact without borders"
169
- buttonId="compactBorderless"
170
- isSelected={choice === 'compactBorderless'}
171
- onChange={this.handleItemClick}
172
- />
173
- </ToggleGroup>
174
- <Table
175
- aria-label="Simple Table"
176
- variant={choice !== 'default' ? 'compact' : null}
177
- borders={choice !== 'compactBorderless'}
178
- cells={columns}
179
- rows={rows}
180
- >
181
- <TableHeader />
182
- <TableBody />
183
- </Table>
184
- </React.Fragment>
185
- );
186
- }
187
- }
119
+ ```ts file="LegacyTableBasic.tsx"
188
120
  ```
189
121
 
190
122
  ### Custom row wrapper
@@ -213,60 +145,7 @@ interface RowWrapperProps {
213
145
  }
214
146
  ```
215
147
 
216
- ```js
217
- import React from 'react';
218
- import { Table, TableHeader, TableBody } from '@patternfly/react-table';
219
- import { css } from '@patternfly/react-styles';
220
-
221
- class RowWrapperTable extends React.Component {
222
- constructor(props) {
223
- super(props);
224
- this.state = {
225
- columns: [{ title: 'Repositories' }, 'Branches', { title: 'Pull requests' }, 'Workspaces'],
226
- rows: [
227
- {
228
- cells: ['Repositories one', 'Branches one', 'Pull requests one', 'Workspaces one']
229
- },
230
- {
231
- cells: ['Repositories two', 'Branches two', 'Pull requests two', 'Workspaces two']
232
- },
233
- {
234
- cells: ['Repositories three', 'Branches three', 'Pull requests three', 'Workspaces three']
235
- }
236
- ]
237
- };
238
- this.customRowWrapper = ({ trRef, className, rowProps, row, ...props }) => {
239
- const isOddRow = (rowProps.rowIndex + 1) % 2;
240
- const customStyle = {
241
- borderLeft: '3px solid var(--pf-global--primary-color--100)'
242
- };
243
- return (
244
- <tr
245
- {...props}
246
- ref={trRef}
247
- className={css(className, isOddRow ? 'odd-row-class' : 'even-row-class', 'custom-static-class')}
248
- style={isOddRow ? customStyle : {}}
249
- />
250
- );
251
- };
252
- }
253
-
254
- render() {
255
- const { columns, rows } = this.state;
256
-
257
- return (
258
- <Table
259
- caption="Table with custom row wrapper that styles odd rows"
260
- cells={columns}
261
- rows={rows}
262
- rowWrapper={this.customRowWrapper}
263
- >
264
- <TableHeader />
265
- <TableBody />
266
- </Table>
267
- );
268
- }
269
- }
148
+ ```ts file="LegacyTableMisc.tsx"
270
149
  ```
271
150
 
272
151
  ### Sortable & wrapping column headers
@@ -279,1388 +158,108 @@ To implement sortable columns:
279
158
  3. Pass an `onSort` callback to the `Table` component
280
159
  `` `onSort` - (event: React.MouseEvent, columnIndex: number, sortByDirection: SortByDirection, extraData: IExtraColumnData) => void; ``
281
160
 
282
- Note: If you want to add a tooltip/popover to a sortable header, in the `transforms` array the `info` transform has to precede the `sortable` transform.
283
-
284
- The built in display for sorting is not fully responsive, as the column headers will be displayed per row when the screen size is small. The example below showcases how sorting may have a custom control display that can be used for small screen sizes.
285
-
286
- ```js
287
- import React from 'react';
288
- import {
289
- Table,
290
- TableHeader,
291
- TableBody,
292
- sortable,
293
- SortByDirection,
294
- wrappable,
295
- cellWidth,
296
- info
297
- } from '@patternfly/react-table';
298
-
299
- class SortableTable extends React.Component {
300
- constructor(props) {
301
- super(props);
302
- this.state = {
303
- columns: [
304
- { title: 'Repositories', transforms: [sortable] },
305
- {
306
- title: 'Branches',
307
- transforms: [
308
- info({
309
- tooltip: 'More information about branches'
310
- }),
311
- sortable
312
- ]
313
- },
314
- { title: 'Pull requests', transforms: [sortable] },
315
- {
316
- title: 'Workspaces - Also this long header will wrap since we have applied the wrappable transform',
317
- transforms: [sortable, wrappable, cellWidth(20)]
318
- },
319
- {
320
- title: 'Last commit',
321
- transforms: [
322
- info({
323
- tooltip: 'More information about commits'
324
- })
325
- ]
326
- }
327
- ],
328
- rows: [
329
- ['one', 'two', 'a', 'four', 'five'],
330
- ['a', 'two', 'k', 'four', 'five'],
331
- ['p', 'two', 'b', 'four', 'five']
332
- ],
333
- sortBy: {
334
- defaultDirection: 'asc' // starting sort direction when first sorting a column. Defaults to 'asc'
335
- }
336
- };
337
- this.onSort = this.onSort.bind(this);
338
- }
339
-
340
- onSort(_event, index, direction) {
341
- const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0));
342
- this.setState({
343
- sortBy: {
344
- index,
345
- direction
346
- },
347
- rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
348
- });
349
- }
350
-
351
- render() {
352
- const { columns, rows, sortBy } = this.state;
353
-
354
- return (
355
- <Table aria-label="Sortable Table" sortBy={sortBy} onSort={this.onSort} cells={columns} rows={rows}>
356
- <TableHeader />
357
- <TableBody />
358
- </Table>
359
- );
360
- }
361
- }
362
- ```
363
-
364
- ### Sortable - custom control
365
-
366
- Sorting a table may also be controlled with a toolbar. This toolbar item may also be hidden at large screen sizes and only displayed when the screen size is small to support responsive tables.
367
-
368
- ```js
369
- import React from 'react';
370
- import { Table, TableHeader, TableBody, sortable, SortByDirection, info } from '@patternfly/react-table';
371
- import {
372
- Toolbar,
373
- ToolbarItem,
374
- ToolbarContent,
375
- OptionsMenu,
376
- OptionsMenuItemGroup,
377
- OptionsMenuItem,
378
- OptionsMenuSeparator,
379
- OptionsMenuToggle
380
- } from '@patternfly/react-core';
381
- import SortAmountDownIcon from '@patternfly/react-icons/dist/esm/icons/sort-amount-down-icon';
382
-
383
- class SortableTable extends React.Component {
384
- constructor(props) {
385
- super(props);
386
- this.state = {
387
- columns: [
388
- { title: 'Repositories', transforms: [sortable] },
389
- {
390
- title: 'Branches',
391
- transforms: [
392
- info({
393
- tooltip: 'More information about branches'
394
- }),
395
- sortable
396
- ]
397
- },
398
- { title: 'Pull requests', transforms: [sortable] },
399
- {
400
- title: 'Workspaces',
401
- transforms: [sortable]
402
- },
403
- {
404
- title: 'Last commit',
405
- transforms: [
406
- info({
407
- tooltip: 'More information about commits'
408
- }),
409
- sortable
410
- ]
411
- }
412
- ],
413
- rows: [
414
- ['one', 'two', 'a', 'four', 'five'],
415
- ['a', 'five', 'k', 'two', 'three'],
416
- ['p', 'seven', 'b', 'one', 'six']
417
- ],
418
- sortBy: {},
419
- isSortDropdownOpen: false
420
- };
421
-
422
- this.onSort = this.onSort.bind(this);
423
- this.onToggle = this.onToggle.bind(this);
424
- }
425
-
426
- onSort(_event, index, direction) {
427
- const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0));
428
- this.setState({
429
- sortBy: {
430
- index,
431
- direction
432
- },
433
- rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
434
- });
435
- }
436
-
437
- onToggle(isSortDropdownOpen) {
438
- this.setState({
439
- isSortDropdownOpen
440
- });
441
- }
442
-
443
- render() {
444
- const { columns, rows, sortBy, isSortDropdownOpen } = this.state;
445
-
446
- return (
447
- <React.Fragment>
448
- <Toolbar id="toolbar">
449
- <ToolbarContent>
450
- <ToolbarItem>
451
- <OptionsMenu
452
- id="options-menu-multiple-options-example"
453
- menuItems={[
454
- <OptionsMenuItemGroup key="first group" aria-label="Sort column">
455
- {columns.map((column, columnIndex) => (
456
- <OptionsMenuItem
457
- key={column.title}
458
- isSelected={sortBy.index === columnIndex}
459
- onSelect={evt => this.onSort(evt, columnIndex, sortBy.direction ? sortBy.direction : 'asc')}
460
- >
461
- {column.title}
462
- </OptionsMenuItem>
463
- ))}
464
- </OptionsMenuItemGroup>,
465
- <OptionsMenuSeparator key="separator" />,
466
- <OptionsMenuItemGroup key="second group" aria-label="Sort direction">
467
- <OptionsMenuItem
468
- onSelect={evt => this.onSort(evt, sortBy.index ? sortBy.index : 0, 'asc')}
469
- isSelected={sortBy.direction === 'asc'}
470
- id="ascending"
471
- key="ascending"
472
- >
473
- Ascending
474
- </OptionsMenuItem>
475
- <OptionsMenuItem
476
- onSelect={evt => this.onSort(evt, sortBy.index ? sortBy.index : 0, 'desc')}
477
- isSelected={sortBy.direction === 'desc'}
478
- id="descending"
479
- key="descending"
480
- >
481
- Descending
482
- </OptionsMenuItem>
483
- </OptionsMenuItemGroup>
484
- ]}
485
- isOpen={isSortDropdownOpen}
486
- toggle={
487
- <OptionsMenuToggle
488
- hideCaret
489
- onToggle={() => this.onToggle(!isSortDropdownOpen)}
490
- toggleTemplate={<SortAmountDownIcon />}
491
- />
492
- }
493
- isPlain
494
- isGrouped
495
- />
496
- </ToolbarItem>
497
- </ToolbarContent>
498
- </Toolbar>
499
- <Table aria-label="Sortable Table" sortBy={sortBy} onSort={this.onSort} cells={columns} rows={rows}>
500
- <TableHeader />
501
- <TableBody />
502
- </Table>
503
- </React.Fragment>
504
- );
505
- }
506
- }
507
- ```
508
-
509
- ### Selectable with checkbox
510
-
511
- To enable row selection, set the `onSelect` callback prop on the Table.
512
-
513
- To control whether a row is selected or not, the Table looks for `selected: true | falsy` on the row definition.
514
-
515
- To disable selection for a row, set `disableSelection: true` on the row definition.
516
-
517
- To include a 'select all' checkbox in the header row, pass `true` to the`canSelectAll` prop on the Table.
518
-
519
- Note: this example also demonstrates the use of the `headerCol` transformation being applied to the first
520
- column via the `cellTransforms` in the column definition. `headerCol` transforms the column so that instead
521
- of using `td` elements, the cells in that column use `th` elements.
522
-
523
- ```js
524
- import React from 'react';
525
- import { Table, TableHeader, TableBody, headerCol } from '@patternfly/react-table';
526
- import { Checkbox } from '@patternfly/react-core';
527
-
528
- class SelectableTable extends React.Component {
529
- constructor(props) {
530
- super(props);
531
- this.state = {
532
- columns: [
533
- { title: 'Repositories', cellTransforms: [headerCol()] },
534
- 'Branches',
535
- { title: 'Pull requests' },
536
- 'Workspaces',
537
- 'Last commit'
538
- ],
539
- rows: [
540
- {
541
- cells: ['one', 'two', 'a', 'four', 'five']
542
- },
543
- {
544
- cells: ['a', 'two', 'k', 'four', 'five'],
545
- disableSelection: true
546
- },
547
- {
548
- cells: ['p', 'two', 'b', 'four', 'five']
549
- }
550
- ],
551
- canSelectAll: true
552
- };
553
- this.onSelect = this.onSelect.bind(this);
554
- this.toggleSelect = this.toggleSelect.bind(this);
555
- }
556
-
557
- onSelect(event, isSelected, rowId) {
558
- let rows;
559
- if (rowId === -1) {
560
- rows = this.state.rows.map(oneRow => {
561
- if (!oneRow.disableSelection) {
562
- oneRow.selected = isSelected;
563
- }
564
- return oneRow;
565
- });
566
- } else {
567
- rows = [...this.state.rows];
568
- rows[rowId].selected = isSelected;
569
- }
570
- this.setState({
571
- rows
572
- });
573
- }
574
-
575
- toggleSelect(checked) {
576
- this.setState({
577
- canSelectAll: checked
578
- });
579
- }
580
-
581
- render() {
582
- const { columns, rows, canSelectAll } = this.state;
583
-
584
- return (
585
- <div>
586
- <Checkbox
587
- label="Can select all"
588
- className="pf-u-mb-lg"
589
- isChecked={canSelectAll}
590
- onChange={this.toggleSelect}
591
- aria-label="toggle select all checkbox"
592
- id="toggle-select-all"
593
- name="toggle-select-all"
594
- />
595
- <Table
596
- onSelect={this.onSelect}
597
- canSelectAll={canSelectAll}
598
- aria-label="Selectable Table"
599
- cells={columns}
600
- rows={rows}
601
- >
602
- <TableHeader />
603
- <TableBody />
604
- </Table>
605
- </div>
606
- );
607
- }
608
- }
609
- ```
610
-
611
- ### Selectable radio input
612
-
613
- To enable row radio selection, set the `onSelect` callback prop on the Table, and set `RowSelectVariant.radio` as the
614
- `selectVariant` prop on the Table.
615
-
616
- To disable selection for a row, set `disableSelection: true` on the row definition.
617
-
618
- ```js
619
- import React from 'react';
620
- import { Table, TableHeader, TableBody, RowSelectVariant, headerCol } from '@patternfly/react-table';
621
-
622
- class SelectableTable extends React.Component {
623
- constructor(props) {
624
- super(props);
625
- this.state = {
626
- columns: [
627
- { title: 'Repositories', cellTransforms: [headerCol()] },
628
- 'Branches',
629
- { title: 'Pull requests' },
630
- 'Workspaces',
631
- 'Last commit'
632
- ],
633
- rows: [
634
- {
635
- cells: ['one', 'two', 'a', 'four', 'five']
636
- },
637
- {
638
- cells: ['a', 'two', 'k', 'four', 'five'],
639
- disableSelection: true
640
- },
641
- {
642
- cells: ['p', 'two', 'b', 'four', 'five']
643
- }
644
- ]
645
- };
646
- this.onSelect = this.onSelect.bind(this);
647
- }
648
-
649
- onSelect(event, isSelected, rowId) {
650
- let rows = this.state.rows.map((oneRow, index) => {
651
- oneRow.selected = rowId === index;
652
- return oneRow;
653
- });
654
- this.setState({
655
- rows
656
- });
657
- }
658
-
659
- render() {
660
- const { columns, rows } = this.state;
661
-
662
- return (
663
- <Table
664
- onSelect={this.onSelect}
665
- selectVariant={RowSelectVariant.radio}
666
- aria-label="Selectable Table"
667
- cells={columns}
668
- rows={rows}
669
- >
670
- <TableHeader />
671
- <TableBody />
672
- </Table>
673
- );
674
- }
675
- }
676
- ```
677
-
678
- ### Hoverable rows, selectable rows, and header cell tooltips/popovers
679
-
680
- This selectable rows feature is intended for use when a table is used to present a list of objects in a Primary-detail view.
681
-
682
- ```js
683
- import React from 'react';
684
- import { Table, TableHeader, TableBody, textCenter } from '@patternfly/react-table';
685
- import styles from '@patternfly/react-styles/css/components/Table/table';
686
-
687
- class RowClickTable extends React.Component {
688
- constructor(props) {
689
- super(props);
690
- this.state = {
691
- columns: [
692
- {
693
- title: 'Repositories',
694
- transforms: [
695
- info({
696
- tooltip: 'More information about repositories',
697
- className: 'repositories-info-tip',
698
- tooltipProps: {
699
- isContentLeftAligned: true
700
- }
701
- })
702
- ]
703
- },
704
- 'Branches',
705
- {
706
- title: 'Pull requests',
707
- transforms: [
708
- info({
709
- popover: (
710
- <div>
711
- More <strong>information</strong> on pull requests
712
- </div>
713
- ),
714
- ariaLabel: 'More information on pull requests',
715
- popoverProps: {
716
- headerContent: 'Pull requests',
717
- footerContent: <a href="">Click here for even more info</a>
718
- }
719
- })
720
- ]
721
- },
722
- 'Workspaces',
723
- {
724
- title: 'Last commit',
725
- transforms: [textCenter],
726
- cellTransforms: [textCenter]
727
- }
728
- ],
729
- rows: [
730
- {
731
- cells: ['Repository one', 'Branch one', 'PR one', 'Workspace one', 'Commit one'],
732
- isHoverable: true,
733
- isRowSelected: false
734
- },
735
- {
736
- cells: [
737
- {
738
- title: <div>one - 2</div>,
739
- props: { title: 'hover title', colSpan: 3 }
740
- },
741
- 'four - 2',
742
- 'five - 2'
743
- ],
744
- isHoverable: true,
745
- isRowSelected: false
746
- },
747
- {
748
- cells: [
749
- 'one - 3',
750
- 'two - 3',
751
- 'three - 3',
752
- 'four - 3',
753
- {
754
- title: 'five - 3 (not centered)',
755
- props: { textCenter: false }
756
- }
757
- ],
758
- isHoverable: true,
759
- isRowSelected: false
760
- }
761
- ]
762
- };
763
-
764
- this.rowClickHandler = (event, row, rowProps) => {
765
- this.setState(prevState => {
766
- const updatedRows = [...prevState.rows];
767
- updatedRows[rowProps.rowIndex].isRowSelected = !prevState.rows[rowProps.rowIndex].isRowSelected;
768
- return {
769
- rows: updatedRows
770
- };
771
- });
772
- };
773
- }
774
-
775
- render() {
776
- const { columns, rows } = this.state;
777
-
778
- return (
779
- <Table caption="Row click handler table" cells={columns} rows={rows}>
780
- <TableHeader className={styles.modifiers.nowrap} />
781
- <TableBody onRowClick={this.rowClickHandler} />
782
- </Table>
783
- );
784
- }
785
- }
786
- ```
787
-
788
- ### Actions and first cell in body rows as th
789
-
790
- To use actions you can either specify an array of actions and pass that into the `Table`'s `actions` prop, or for more control you can use the `actionResolver` callback prop to add actions conditionally.
791
-
792
- ```js
793
- import React from 'react';
794
- import { Table, TableHeader, TableBody, headerCol } from '@patternfly/react-table';
795
- import {
796
- ButtonVariant,
797
- Checkbox,
798
- DropdownToggle,
799
- ToggleGroup,
800
- ToggleGroupItem,
801
- Toolbar,
802
- ToolbarContent,
803
- ToolbarItem
804
- } from '@patternfly/react-core';
805
-
806
- class ActionsTable extends React.Component {
807
- constructor(props) {
808
- super(props);
809
- this.state = {
810
- propToUse: 'actions',
811
- useCustomToggle: false,
812
- useExtraAction: false,
813
- columns: [
814
- { title: 'Repositories', cellTransforms: [headerCol()] },
815
- 'Branches',
816
- { title: 'Pull requests' },
817
- 'Workspaces',
818
- 'Last commit'
819
- ],
820
- rows: [
821
- {
822
- cells: ['a', 'two', 1, 'four', 'five']
823
- },
824
- {
825
- cells: ['disable actions', 'two', 3, 'four', 'five'],
826
- disableActions: true
827
- },
828
- {
829
- cells: ['green actions', 'two', 4, 'four', 'five'],
830
- type: 'green'
831
- },
832
- {
833
- cells: ['extra action props', 'two', 5, 'four', 'five'],
834
- actionProps: {
835
- 'data-specific-attr': 'some-value'
836
- }
837
- },
838
- {
839
- cells: ['blue actions', 'two', 6, 'four', 'five'],
840
- type: 'blue'
841
- }
842
- ]
843
- };
844
- this.handleItemClick = this.handleItemClick.bind(this);
845
- this.toggleCustomToggle = this.toggleCustomToggle.bind(this);
846
- this.toggleExtraAction = this.toggleExtraAction.bind(this);
847
- }
848
-
849
- /**
850
- * Use actions or actionResolver, not both
851
- */
852
- actions() {
853
- return [
854
- {
855
- title: 'Some action',
856
- onClick: (event, rowId, rowData, extra) => console.log('clicked on Some action, on row: ', rowId)
857
- },
858
- {
859
- title: <a href="https://www.patternfly.org">Link action</a>
860
- },
861
- {
862
- isSeparator: true
863
- },
864
- {
865
- title: 'Third action',
866
- onClick: (event, rowId, rowData, extra) => console.log('clicked on Third action, on row: ', rowId)
867
- },
868
- ...(this.state.useExtraAction
869
- ? [
870
- {
871
- title: 'Start',
872
- variant: ButtonVariant.secondary,
873
- onClick: (event, rowId, rowData, extra) => console.log('clicked on extra action on row: ', rowId),
874
- isOutsideDropdown: true
875
- }
876
- ]
877
- : [])
878
- ];
879
- }
880
-
881
- /**
882
- * Use actions or actionResolver, not both
883
- */
884
- actionResolver(rowData, { rowIndex }) {
885
- if (rowIndex === 1) {
886
- return null;
887
- }
888
-
889
- const thirdAction = rowData.type
890
- ? [
891
- {
892
- isSeparator: true
893
- },
894
- {
895
- title: `${rowData.type} action`,
896
- onClick: (event, rowId, rowData, extra) =>
897
- console.log(`clicked on ${rowData.type} action, on row ${rowId} of type ${rowData.type}`)
898
- }
899
- ]
900
- : [];
901
-
902
- return [
903
- {
904
- title: 'actionResolver action',
905
- onClick: (event, rowId, rowData, extra) =>
906
- console.log(`clicked on Some action, on row ${rowId} of type ${rowData.type}`)
907
- },
908
- {
909
- title: <div>Another action</div>,
910
- onClick: (event, rowId, rowData, extra) =>
911
- console.log(`clicked on Another action, on row ${rowId} of type ${rowData.type}`)
912
- },
913
- ...thirdAction
914
- ];
915
- }
916
-
917
- /**
918
- * Use actions or actionResolver, not both
919
- */
920
- actionResolverWithActions(rowData, { rowIndex }) {
921
- if (rowIndex === 1) {
922
- return null;
923
- }
924
-
925
- const thirdAction = rowData.type
926
- ? [
927
- {
928
- isSeparator: true
929
- },
930
- {
931
- title: `${rowData.type} action`,
932
- onClick: (event, rowId, rowData, extra) =>
933
- console.log(`clicked on ${rowData.type} action, on row ${rowId} of type ${rowData.type}`)
934
- }
935
- ]
936
- : [];
937
-
938
- return [
939
- {
940
- title: 'Start',
941
- variant: ButtonVariant.secondary,
942
- onClick: (event, rowId, rowData, extra) => console.log('clicked on extra action on row: ', rowId),
943
- isOutsideDropdown: true
944
- },
945
- {
946
- title: 'actionResolver action',
947
- onClick: (event, rowId, rowData, extra) =>
948
- console.log(`clicked on Some action, on row ${rowId} of type ${rowData.type}`)
949
- },
950
- {
951
- title: <div>Another action</div>,
952
- onClick: (event, rowId, rowData, extra) =>
953
- console.log(`clicked on Another action, on row ${rowId} of type ${rowData.type}`)
954
- },
955
- ...thirdAction
956
- ];
957
- }
958
-
959
- areActionsDisabled(rowData, { rowIndex }) {
960
- return rowIndex === 3;
961
- }
962
-
963
- handleItemClick(isSelected, event) {
964
- const action = event.currentTarget.id;
965
- this.setState({
966
- propToUse: action
967
- });
968
- }
969
-
970
- toggleCustomToggle(checked) {
971
- this.setState({
972
- useCustomToggle: checked
973
- });
974
- }
975
-
976
- toggleExtraAction(checked) {
977
- this.setState({
978
- useExtraAction: checked
979
- });
980
- }
981
-
982
- render() {
983
- const { columns, rows, propToUse, useCustomToggle, useExtraAction } = this.state;
984
-
985
- const customActionsToggle = props => (
986
- <DropdownToggle onToggle={props.onToggle} isDisabled={props.isDisabled}>
987
- Actions
988
- </DropdownToggle>
989
- );
990
-
991
- return (
992
- <React.Fragment>
993
- <Toolbar>
994
- <ToolbarContent>
995
- <ToolbarItem>
996
- <ToggleGroup aria-label="actions or actionResolver">
997
- <ToggleGroupItem
998
- text="Use actions prop"
999
- buttonId="actions"
1000
- isSelected={propToUse === 'actions'}
1001
- onChange={this.handleItemClick}
1002
- />
1003
- <ToggleGroupItem
1004
- text="Use actionResolver prop"
1005
- buttonId="actionResolver"
1006
- isSelected={propToUse === 'actionResolver'}
1007
- onChange={this.handleItemClick}
1008
- />
1009
- </ToggleGroup>
1010
- </ToolbarItem>
1011
- <ToolbarItem>
1012
- <Checkbox
1013
- label="Use custom actions toggle"
1014
- isChecked={useCustomToggle}
1015
- onChange={this.toggleCustomToggle}
1016
- aria-label="toggle use of custom actions toggle"
1017
- id="toggle-custom-actions-toggle"
1018
- name="toggle-custom-actions-toggle"
1019
- />
1020
- </ToolbarItem>
1021
- <ToolbarItem>
1022
- <Checkbox
1023
- label="Add extra actions"
1024
- isChecked={useExtraAction}
1025
- onChange={this.toggleExtraAction}
1026
- aria-label="toggle extra actions"
1027
- id="toggle-extra-action"
1028
- name="toggle-extra-action"
1029
- />
1030
- </ToolbarItem>
1031
- </ToolbarContent>
1032
- </Toolbar>
1033
- <Table
1034
- aria-label="Actions table"
1035
- cells={columns}
1036
- rows={rows}
1037
- actions={propToUse === 'actions' ? this.actions() : null}
1038
- {...(propToUse === 'actionResolver' && {
1039
- actionResolver: useExtraAction ? this.actionResolverWithActions : this.actionResolver
1040
- })}
1041
- areActionsDisabled={this.areActionsDisabled}
1042
- dropdownPosition="left"
1043
- dropdownDirection="bottom"
1044
- actionsToggle={useCustomToggle ? customActionsToggle : undefined}
1045
- >
1046
- <TableHeader />
1047
- <TableBody />
1048
- </Table>
1049
- </React.Fragment>
1050
- );
1051
- }
1052
- }
1053
- ```
1054
-
1055
- ### Expandable
1056
-
1057
- To make an exapandable row, define a child row with the `parent` field set to its parent's row index.
1058
- The parent row can have an `isOpen` field for managing the expanded state of the parent row.
1059
-
1060
- Also, pass an `onCollapse` event handler via the prop on the Table
1061
-
1062
- ```js
1063
- import React from 'react';
1064
- import { Table, TableHeader, TableBody, TableVariant, expandable } from '@patternfly/react-table';
1065
- import { Checkbox } from '@patternfly/react-core';
1066
-
1067
- class CompactExpandableTable extends React.Component {
1068
- constructor(props) {
1069
- super(props);
1070
- this.state = {
1071
- isCompact: true,
1072
- columns: [
1073
- {
1074
- title: 'ID',
1075
- cellFormatters: [expandable]
1076
- },
1077
- 'Branches',
1078
- { title: 'Pull requests' },
1079
- { title: '' /* deliberately empty */, dataLabel: 'Label for mobile view' }
1080
- ],
1081
- rows: [
1082
- {
1083
- cells: ['one', 'two', 'three', 'four']
1084
- },
1085
- {
1086
- isOpen: true,
1087
- cells: ['parent - 1', 'two', 'three', 'four']
1088
- },
1089
- {
1090
- parent: 1,
1091
- cells: ['single cell']
1092
- },
1093
- {
1094
- isOpen: true,
1095
- cells: ['parent - 2', 'two', 'three', 'four']
1096
- },
1097
- {
1098
- parent: 3,
1099
- fullWidth: true,
1100
- cells: ['single cell - fullWidth']
1101
- },
1102
- {
1103
- isOpen: true,
1104
- cells: ['parent - 3', 'two', 'three', 'four']
1105
- },
1106
- {
1107
- parent: 5,
1108
- noPadding: true,
1109
- cells: ['single cell - noPadding']
1110
- },
1111
- {
1112
- isOpen: true,
1113
- cells: ['parent - 4', 'two', 'three', 'four']
1114
- },
1115
- {
1116
- parent: 7,
1117
- noPadding: true,
1118
- fullWidth: true,
1119
- cells: ['single cell - fullWidth & noPadding']
1120
- },
1121
- {
1122
- isOpen: true,
1123
- cells: ['parent - 5', 'two', 'three', 'four']
1124
- },
1125
- {
1126
- parent: 9,
1127
- cells: [
1128
- {
1129
- title: "spans 'Header cell' and 'Branches'",
1130
- props: {
1131
- colSpan: 2
1132
- }
1133
- },
1134
- {
1135
- title: "spans 'Pull requests' and the empty column",
1136
- props: {
1137
- colSpan: 2
1138
- }
1139
- }
1140
- ]
1141
- },
1142
- {
1143
- isOpen: true,
1144
- cells: ['parent - 6', 'two', 'three', 'four']
1145
- },
1146
- {
1147
- parent: 11,
1148
- fullWidth: true,
1149
- cells: [
1150
- {
1151
- title: "fullWidth, spans the collapsible column and 'Header cell'",
1152
- props: {
1153
- colSpan: 2
1154
- }
1155
- },
1156
- {
1157
- title: "fullWidth, spans 'Branches' and 'Pull requests'",
1158
- props: {
1159
- colSpan: 2
1160
- }
1161
- },
1162
- 'fullWidth, spans the empty column'
1163
- ]
1164
- }
1165
- ]
1166
- };
1167
- this.onCollapse = this.onCollapse.bind(this);
1168
- this.toggleCompact = this.toggleCompact.bind(this);
1169
- }
1170
-
1171
- onCollapse(event, rowKey, isOpen) {
1172
- const { rows } = this.state;
1173
- /**
1174
- * Please do not use rowKey as row index for more complex tables.
1175
- * Rather use some kind of identifier like ID passed with each row.
1176
- */
1177
- rows[rowKey].isOpen = isOpen;
1178
- this.setState({
1179
- rows
1180
- });
1181
- }
1182
-
1183
- toggleCompact(checked) {
1184
- this.setState({
1185
- isCompact: checked
1186
- });
1187
- }
1188
-
1189
- render() {
1190
- const { columns, rows, isCompact } = this.state;
1191
-
1192
- return (
1193
- <React.Fragment>
1194
- <Checkbox
1195
- label="Compact"
1196
- isChecked={isCompact}
1197
- onChange={this.toggleCompact}
1198
- aria-label="toggle compact variation"
1199
- id="toggle-compact"
1200
- name="toggle-compact"
1201
- />
1202
- <Table
1203
- aria-label="Expandable table"
1204
- variant={isCompact ? TableVariant.compact : null}
1205
- onCollapse={this.onCollapse}
1206
- rows={rows}
1207
- cells={columns}
1208
- >
1209
- <TableHeader />
1210
- <TableBody />
1211
- </Table>
1212
- </React.Fragment>
1213
- );
1214
- }
1215
- }
1216
- ```
1217
-
1218
- ### Compound expandable
1219
-
1220
- To build a compound expandable table:
1221
-
1222
- 1. Pass the `compoundExpand` transformation via the `cellTransforms` field in the column definition for each column that will have an expanded section.
1223
- 2. For each expandable parent row, the cells in the expandable columns should:
1224
- 1. have a managed `isOpen` prop passed to the cell definition
1225
- 2. have an `ariaControls` value which matches the `id` of it’s child row
1226
- 3. For each expandable child row, the row definition needs:
1227
- 1. A `parent` field set to its parent’s row index
1228
- 2. A `compoundParent` field set to the cell index which will control the expanding/collapsing of this row
1229
- 4. An `onExpand` event handler prop should be passed to the Table.
1230
-
1231
- ```js
1232
- import React from 'react';
1233
- import { Table, TableHeader, TableBody, compoundExpand } from '@patternfly/react-table';
1234
-
1235
- import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
1236
- import CodeIcon from '@patternfly/react-icons/dist/esm/icons/code-icon';
1237
- import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
1238
-
1239
- // https://github.com/patternfly/patternfly-react/blob/main/packages/react-table/src/components/Table/composable-table-examples/DemoSortableTable.js
1240
- import DemoSortableTable from './DemoSortableTable';
1241
-
1242
- class CompoundExpandableTable extends React.Component {
1243
- constructor(props) {
1244
- super(props);
1245
- this.state = {
1246
- columns: [
1247
- 'Repositories',
1248
- {
1249
- title: 'Branches',
1250
- cellTransforms: [compoundExpand]
1251
- },
1252
- {
1253
- title: 'Pull requests',
1254
- cellTransforms: [compoundExpand]
1255
- },
1256
- {
1257
- title: 'Workspaces',
1258
- cellTransforms: [compoundExpand]
1259
- },
1260
- 'Last Commit',
1261
- {
1262
- title: '',
1263
- dataLabel: 'Action'
1264
- }
1265
- ],
1266
- rows: [
1267
- {
1268
- isOpen: true,
1269
- cells: [
1270
- { title: <a href="#">siemur/test-space</a>, props: { component: 'th' } },
1271
- {
1272
- title: (
1273
- <React.Fragment>
1274
- <CodeBranchIcon key="icon" /> 10
1275
- </React.Fragment>
1276
- ),
1277
- props: { isOpen: true, ariaControls: 'compound-expansion-table-1' }
1278
- },
1279
- {
1280
- title: (
1281
- <React.Fragment>
1282
- <CodeIcon key="icon" /> 4
1283
- </React.Fragment>
1284
- ),
1285
- props: { isOpen: false, ariaControls: 'compound-expansion-table-2' }
1286
- },
1287
- {
1288
- title: (
1289
- <React.Fragment>
1290
- <CubeIcon key="icon" /> 4
1291
- </React.Fragment>
1292
- ),
1293
- props: { isOpen: false, ariaControls: 'compound-expansion-table-3' }
1294
- },
1295
- '20 minutes',
1296
- { title: <a href="#">Open in Github</a> }
1297
- ]
1298
- },
1299
- {
1300
- parent: 0,
1301
- compoundParent: 1,
1302
- cells: [
1303
- {
1304
- title: (
1305
- <DemoSortableTable
1306
- firstColumnRows={['parent-0', 'compound-1', 'three', 'four', 'five']}
1307
- id="compound-expansion-table-1"
1308
- />
1309
- ),
1310
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1311
- }
1312
- ]
1313
- },
1314
- {
1315
- parent: 0,
1316
- compoundParent: 2,
1317
- cells: [
1318
- {
1319
- title: (
1320
- <DemoSortableTable
1321
- firstColumnRows={['parent-0', 'compound-2', 'three', 'four', 'five']}
1322
- id="compound-expansion-table-2"
1323
- />
1324
- ),
1325
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1326
- }
1327
- ]
1328
- },
1329
- {
1330
- parent: 0,
1331
- compoundParent: 3,
1332
- cells: [
1333
- {
1334
- title: (
1335
- <DemoSortableTable
1336
- firstColumnRows={['parent-0', 'compound-3', 'three', 'four', 'five']}
1337
- id="compound-expansion-table-3"
1338
- />
1339
- ),
1340
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1341
- }
1342
- ]
1343
- },
1344
- {
1345
- isOpen: false,
1346
- cells: [
1347
- { title: <a href="#">siemur/test-space</a>, props: { component: 'th' } },
1348
- {
1349
- title: (
1350
- <React.Fragment>
1351
- <CodeBranchIcon key="icon" /> 3
1352
- </React.Fragment>
1353
- ),
1354
- props: { isOpen: false, ariaControls: 'compound-expansion-table-4' }
1355
- },
1356
- {
1357
- title: (
1358
- <React.Fragment>
1359
- <CodeIcon key="icon" /> 4
1360
- </React.Fragment>
1361
- ),
1362
- props: { isOpen: false, ariaControls: 'compound-expansion-table-5' }
1363
- },
1364
- {
1365
- title: (
1366
- <React.Fragment>
1367
- <CubeIcon key="icon" /> 2
1368
- </React.Fragment>
1369
- ),
1370
- props: { isOpen: false, ariaControls: 'compound-expansion-table-6' }
1371
- },
1372
- '20 minutes',
1373
- { title: <a href="#">Open in Github</a> }
1374
- ]
1375
- },
1376
- {
1377
- parent: 4,
1378
- compoundParent: 1,
1379
- cells: [
1380
- {
1381
- title: (
1382
- <DemoSortableTable
1383
- firstColumnRows={['parent-4', 'compound-1', 'three', 'four', 'five']}
1384
- id="compound-expansion-table-4"
1385
- />
1386
- ),
1387
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1388
- }
1389
- ]
1390
- },
1391
- {
1392
- parent: 4,
1393
- compoundParent: 2,
1394
- cells: [
1395
- {
1396
- title: (
1397
- <DemoSortableTable
1398
- firstColumnRows={['parent-4', 'compound-2', 'three', 'four', 'five']}
1399
- id="compound-expansion-table-5"
1400
- />
1401
- ),
1402
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1403
- }
1404
- ]
1405
- },
1406
- {
1407
- parent: 4,
1408
- compoundParent: 3,
1409
- cells: [
1410
- {
1411
- title: (
1412
- <DemoSortableTable
1413
- firstColumnRows={['parent-4', 'compound-3', 'three', 'four', 'five']}
1414
- id="compound-expansion-table-6"
1415
- />
1416
- ),
1417
- props: { colSpan: 6, className: 'pf-m-no-padding' }
1418
- }
1419
- ]
1420
- }
1421
- ]
1422
- };
1423
- this.onExpand = this.onExpand.bind(this);
1424
- }
1425
-
1426
- onExpand(event, rowIndex, colIndex, isOpen, rowData, extraData) {
1427
- const { rows } = this.state;
1428
- if (!isOpen) {
1429
- // set all other expanded cells false in this row if we are expanding
1430
- rows[rowIndex].cells.forEach(cell => {
1431
- if (cell.props) cell.props.isOpen = false;
1432
- });
1433
- rows[rowIndex].cells[colIndex].props.isOpen = true;
1434
- rows[rowIndex].isOpen = true;
1435
- } else {
1436
- rows[rowIndex].cells[colIndex].props.isOpen = false;
1437
- rows[rowIndex].isOpen = rows[rowIndex].cells.some(cell => cell.props && cell.props.isOpen);
1438
- }
1439
- this.setState({
1440
- rows
1441
- });
1442
- }
161
+ Note: If you want to add a tooltip/popover to a sortable header, in the `transforms` array the `info` transform has to precede the `sortable` transform.
1443
162
 
1444
- render() {
1445
- const { columns, rows } = this.state;
163
+ The built in display for sorting is not fully responsive, as the column headers will be displayed per row when the screen size is small. The example below showcases how sorting may have a custom control display that can be used for small screen sizes.
1446
164
 
1447
- return (
1448
- <Table aria-label="Compound expandable table" onExpand={this.onExpand} rows={rows} cells={columns}>
1449
- <TableHeader />
1450
- <TableBody />
1451
- </Table>
1452
- );
1453
- }
1454
- }
165
+ ```ts file="LegacyTableSortable.tsx"
1455
166
  ```
1456
167
 
1457
- ### With width and breakpoint visibility modifiers
168
+ ### Sortable - custom control
1458
169
 
1459
- ```js
1460
- import React from 'react';
1461
- import { Table, TableHeader, TableBody, cellWidth, classNames, Visibility } from '@patternfly/react-table';
170
+ Sorting a table may also be controlled with a toolbar. This toolbar item may also be hidden at large screen sizes and only displayed when the screen size is small to support responsive tables.
1462
171
 
1463
- class WidthTable extends React.Component {
1464
- constructor(props) {
1465
- super(props);
1466
- this.state = {
1467
- columns: [
1468
- { title: 'Header cell', transforms: [cellWidth(10)] },
1469
- {
1470
- title: 'Branches (visible only on md)',
1471
- columnTransforms: [
1472
- classNames(Visibility.hidden, Visibility.visibleOnMd, Visibility.hiddenOnLg, Visibility.visibleOn2Xl)
1473
- ]
1474
- },
1475
- {
1476
- title: 'Pull requests (hidden only on md)',
1477
- columnTransforms: [classNames(Visibility.hiddenOnMd, Visibility.visibleOnLg)]
1478
- },
1479
- {
1480
- title: 'Workspaces (hidden on xs)',
1481
- columnTransforms: [classNames(Visibility.hidden, Visibility.visibleOnSm)]
1482
- },
1483
- {
1484
- title: 'Last commit',
1485
- transforms: [cellWidth(30)]
1486
- }
1487
- ],
1488
- rows: [
1489
- [
1490
- 'one - 1',
1491
- 'two - 1 (visible only on md)',
1492
- 'three - 1 (hidden only on md)',
1493
- 'four - 1 (hidden on xs)',
1494
- 'five - 1'
1495
- ],
1496
- [
1497
- 'one - 2',
1498
- 'two - 2 (visible only on md)',
1499
- 'three - 2 (hidden only on md)',
1500
- 'four - 2 (hidden on xs)',
1501
- 'five - 2'
1502
- ]
1503
- ]
1504
- };
1505
- }
172
+ ```ts file="LegacyTableSortableCustom.tsx"
173
+ ```
1506
174
 
1507
- render() {
1508
- const { columns, rows } = this.state;
175
+ ### Selectable with checkbox
1509
176
 
1510
- return (
1511
- <Table aria-label="Table with width and breakpoint visibility modifiers" cells={columns} rows={rows}>
1512
- <TableHeader />
1513
- <TableBody />
1514
- </Table>
1515
- );
1516
- }
1517
- }
177
+ To enable row selection, set the `onSelect` callback prop on the Table.
178
+
179
+ To control whether a row is selected or not, the Table looks for `selected: true | falsy` on the row definition.
180
+
181
+ To disable selection for a row, set `disableSelection: true` on the row definition.
182
+
183
+ To include a 'select all' checkbox in the header row, pass `true` to the`canSelectAll` prop on the Table.
184
+
185
+ Note: this example also demonstrates the use of the `headerCol` transformation being applied to the first
186
+ column via the `cellTransforms` in the column definition. `headerCol` transforms the column so that instead
187
+ of using `td` elements, the cells in that column use `th` elements.
188
+
189
+ **Note:** This example has a `shift + select` feature where holding shift while
190
+ checking checkboxes will check intermediate rows' checkboxes.
191
+
192
+ ```ts file="LegacyTableSelectable.tsx"
1518
193
  ```
1519
194
 
1520
- ### Controlling text
195
+ ### Selectable radio input
1521
196
 
1522
- ```js
1523
- import React from 'react';
1524
- import {
1525
- Table,
1526
- TableHeader,
1527
- TableBody,
1528
- wrappable,
1529
- truncate,
1530
- nowrap,
1531
- breakWord,
1532
- cellWidth,
1533
- fitContent
1534
- } from '@patternfly/react-table';
197
+ To enable row radio selection, set the `onSelect` callback prop on the Table, and set
198
+ `RowSelectVariant.radio` or `"radio"` as the `selectVariant` prop on the Table.
1535
199
 
1536
- class ControllingText extends React.Component {
1537
- constructor(props) {
1538
- super(props);
1539
- this.state = {
1540
- columns: [
1541
- { title: 'Truncate (width 20%)', transforms: [cellWidth(20)], cellTransforms: [truncate] },
1542
- { title: 'Break word', cellTransforms: [breakWord] },
1543
- { title: 'Wrapping table header text. This th text will wrap instead of truncate.', transforms: [wrappable] },
1544
- { title: 'Fit content', transforms: [fitContent] },
1545
- { title: '', cellTransforms: [nowrap] }
1546
- ],
1547
- rows: [
1548
- [
1549
- 'This text will truncate instead of wrap.',
1550
- { title: <a href="#">http://thisisaverylongurlthatneedstobreakusethebreakwordmodifier.org</a> },
1551
- {
1552
- title: (
1553
- <p>
1554
- By default,
1555
- <code>thead</code> cells will truncate and
1556
- <code>tbody</code> cells will wrap. Use
1557
- <code>.pf-m-wrap</code> on a<code>th</code> to change its behavior.
1558
- </p>
1559
- )
1560
- },
1561
- "This cell's content will adjust itself to the parent th width. This modifier only affects table layouts.",
1562
- { title: <a href="#">No wrap</a> }
1563
- ]
1564
- ]
1565
- };
1566
- }
200
+ To disable selection for a row, set `disableSelection: true` on the row definition.
1567
201
 
1568
- render() {
1569
- const { columns, rows } = this.state;
202
+ ```ts file="LegacyTableSelectableRadio.tsx"
203
+ ```
1570
204
 
1571
- return (
1572
- <Table aria-label="Controlling text" cells={columns} rows={rows}>
1573
- <TableHeader />
1574
- <TableBody />
1575
- </Table>
1576
- );
1577
- }
1578
- }
205
+ ### Hoverable rows, selectable rows, and header cell tooltips/popovers
206
+
207
+ This selectable rows feature is intended for use when a table is used to present a list of objects in a Primary-detail view.
208
+
209
+ ```ts file="LegacyTableHoverable.tsx"
1579
210
  ```
1580
211
 
1581
- ### Modifiers with table text
212
+ ### Actions and first cell in body rows as th
1582
213
 
1583
- ```js
1584
- import React from 'react';
1585
- import { Table, TableHeader, TableBody, TableText, cellWidth } from '@patternfly/react-table';
214
+ To use actions you can either specify an array of actions and pass that into the `Table`'s `actions` prop, or for more control you can use the `actionResolver` callback prop to add actions conditionally.
1586
215
 
1587
- class ModifiersWithTableText extends React.Component {
1588
- constructor(props) {
1589
- super(props);
1590
- this.state = {
1591
- columns: [
1592
- { title: 'Truncating text', transforms: [cellWidth(30)] },
1593
- { title: 'Wrapping table header text. This th text will wrap instead of truncate.' }
1594
- ],
1595
- rows: [
1596
- [
1597
- { title: <TableText wrapModifier="truncate">This text will truncate instead of wrap.</TableText> },
1598
- {
1599
- title: (
1600
- <TableText wrapModifier="nowrap">
1601
- <a href="#">This is a link that needs to be on one line and fully readable.</a>
1602
- </TableText>
1603
- )
1604
- }
1605
- ]
1606
- ]
1607
- };
1608
- }
216
+ ```ts file="LegacyTableActions.tsx"
217
+ ```
1609
218
 
1610
- render() {
1611
- const { columns, rows } = this.state;
219
+ ### Expandable
1612
220
 
1613
- return (
1614
- <Table aria-label="Controlling text" cells={columns} rows={rows}>
1615
- <TableHeader />
1616
- <TableBody />
1617
- </Table>
1618
- );
1619
- }
1620
- }
221
+ To make an exapandable row, define a child row with the `parent` field set to its parent's row index.
222
+ The parent row can have an `isOpen` field for managing the expanded state of the parent row.
223
+
224
+ Also, pass an `onCollapse` event handler via the prop on the Table
225
+
226
+ ```ts file="LegacyTableExpandable.tsx"
1621
227
  ```
1622
228
 
1623
- ### Empty state
229
+ ### Compound expandable
1624
230
 
1625
- ```js
1626
- import React from 'react';
1627
- import { Table, TableHeader, TableBody } from '@patternfly/react-table';
1628
- import { Button, EmptyState, EmptyStateBody, Bullseye, Title, EmptyStateIcon } from '@patternfly/react-core';
1629
- import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
231
+ To build a compound expandable table:
1630
232
 
1631
- EmptyStateTable = () => {
1632
- const columns = ['Repositories', 'Branches', 'Pull requests', 'Workspaces', 'Last commit'];
1633
- const rows = [
1634
- {
1635
- heightAuto: true,
1636
- cells: [
1637
- {
1638
- props: { colSpan: 8 },
1639
- title: (
1640
- <Bullseye>
1641
- <EmptyState variant={EmptyStateVariant.small}>
1642
- <EmptyStateIcon icon={SearchIcon} />
1643
- <Title headingLevel="h2" size="lg">
1644
- No results found
1645
- </Title>
1646
- <EmptyStateBody>Clear all filters and try again.</EmptyStateBody>
1647
- <Button variant="link">Clear all filters</Button>
1648
- </EmptyState>
1649
- </Bullseye>
1650
- )
1651
- }
1652
- ]
1653
- }
1654
- ];
1655
- return (
1656
- <React.Fragment>
1657
- <Table caption="Empty State Table Example" cells={columns} rows={rows}>
1658
- <TableHeader />
1659
- <TableBody />
1660
- </Table>
1661
- </React.Fragment>
1662
- );
1663
- };
233
+ 1. Pass the `compoundExpand` transformation via the `cellTransforms` field in the column definition for each column that will have an expanded section.
234
+ 2. For each expandable parent row, the cells in the expandable columns should:
235
+ 1. have a managed `isOpen` prop passed to the cell definition
236
+ 2. have an `ariaControls` value which matches the `id` of it’s child row
237
+ 3. For each expandable child row, the row definition needs:
238
+ 1. A `parent` field set to its parent’s row index
239
+ 2. A `compoundParent` field set to the cell index which will control the expanding/collapsing of this row
240
+ 4. An `onExpand` event handler prop should be passed to the Table.
241
+
242
+ ```ts file="LegacyTableCompoundExpandable.tsx"
243
+ ```
244
+
245
+ ### With width and breakpoint visibility modifiers
246
+
247
+ ```ts file="LegacyTableCellWidth.tsx"
248
+ ```
249
+
250
+ ### Controlling text
251
+
252
+ ```ts file="LegacyTableControllingText.tsx"
253
+ ```
254
+
255
+ ### Modifiers with table text
256
+
257
+ ```ts file="LegacyTableTextModifiers.tsx"
258
+ ```
259
+
260
+ ### Empty state
261
+
262
+ ```ts file="LegacyTableEmptyState.tsx"
1664
263
  ```
1665
264
 
1666
265
  ### Editable rows
@@ -2152,7 +751,7 @@ class EditableRowsTable extends React.Component {
2152
751
  }
2153
752
  ```
2154
753
 
2155
- ### Favoritable
754
+ ### Favoritable (implemented with sortable and selectable)
2156
755
 
2157
756
  To enable favoriting of a row, set the `onFavorite` callback prop on the Table.
2158
757
 
@@ -2162,154 +761,7 @@ When you also pass a sort callback through the `onSort` prop, favorites sorting
2162
761
 
2163
762
  If you want to exclude favorites from sorting, set `canSortFavorites={false}` on the Table.
2164
763
 
2165
- ```js
2166
- import React from 'react';
2167
- import { Table, TableHeader, TableBody, sortable, SortByDirection } from '@patternfly/react-table';
2168
- import { Checkbox } from '@patternfly/react-core';
2169
-
2170
- class FavoritesTable extends React.Component {
2171
- constructor(props) {
2172
- super(props);
2173
- this.state = {
2174
- columns: [
2175
- { title: 'Repositories', transforms: [sortable] },
2176
- 'Branches',
2177
- 'Pull requests',
2178
- 'Workspaces',
2179
- 'Last commit'
2180
- ],
2181
- rows: [
2182
- {
2183
- favorited: true,
2184
- // The favorites button has defaults that can be overriden
2185
- favoritesProps: {
2186
- 'aria-label': 'Favorited', // Defaults to 'Starred' / 'Not starred'
2187
- id: 'favorites-button-a', // Defaults to `favorites-button-${rowIndex}`
2188
- 'aria-labelledby': 'favorites-button-a repository-1' // Defaults to `favorites-button-${rowIndex}`
2189
- },
2190
- cells: ['c', 'two', 'a', 'four', 'five']
2191
- },
2192
- {
2193
- cells: ['a', 'two', 'k', 'four', 'five'],
2194
- disableSelection: true
2195
- },
2196
- {
2197
- favorited: true,
2198
- cells: ['b', 'two', 'b', 'four', 'five']
2199
- }
2200
- ],
2201
- sortBy: {},
2202
- canSortFavorites: true
2203
- };
2204
- this.onSelect = this.onSelect.bind(this);
2205
- this.onFavorite = this.onFavorite.bind(this);
2206
- this.onSort = this.onSort.bind(this);
2207
- this.toggleFavsSort = this.toggleFavsSort.bind(this);
2208
- }
2209
-
2210
- onSelect(event, isSelected, rowId) {
2211
- let rows;
2212
- if (rowId === -1) {
2213
- // header row
2214
- rows = this.state.rows.map(oneRow => {
2215
- oneRow.selected = isSelected;
2216
- return oneRow;
2217
- });
2218
- } else {
2219
- // body row
2220
- rows = [...this.state.rows];
2221
- rows[rowId].selected = isSelected;
2222
- }
2223
- this.setState({
2224
- rows
2225
- });
2226
- }
2227
-
2228
- onFavorite(event, isFavorited, rowId) {
2229
- this.setState({
2230
- rows: this.state.rows.map((row, index) => {
2231
- if (index === rowId) {
2232
- row.favorited = isFavorited;
2233
- row.favoritesProps = {
2234
- ...row.favoritesProps,
2235
- // Example of how to override the default aria-label of Starred / Not starred
2236
- 'aria-label': isFavorited ? 'Favorited' : 'Not favorited'
2237
- };
2238
- }
2239
- return row;
2240
- })
2241
- });
2242
- }
2243
-
2244
- onSort(_event, index, direction) {
2245
- // index 0 === select column
2246
- // index 1 === favorites column
2247
- // index 2 === first user defined column
2248
- let sortedRows;
2249
- if (index === 1) {
2250
- // favorites column
2251
- sortedRows = this.state.rows.sort((a, b) => {
2252
- if (a.favorited && !b.favorited) {
2253
- return -1;
2254
- } else if (!a.favorited && b.favorited) {
2255
- return 1;
2256
- }
2257
- return 0;
2258
- });
2259
- } else {
2260
- const userIndex = index - 2; // subtract for select and favorites column
2261
- sortedRows = this.state.rows.sort((a, b) =>
2262
- a.cells[userIndex] < b.cells[userIndex] ? -1 : a.cells[userIndex] > b.cells[userIndex] ? 1 : 0
2263
- );
2264
- }
2265
- this.setState({
2266
- sortBy: {
2267
- index,
2268
- direction
2269
- },
2270
- rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse()
2271
- });
2272
- }
2273
-
2274
- toggleFavsSort(checked) {
2275
- this.setState({
2276
- canSortFavorites: checked
2277
- });
2278
- }
2279
-
2280
- render() {
2281
- const { columns, rows, sortBy, canSortFavorites } = this.state;
2282
-
2283
- return (
2284
- <div>
2285
- <Checkbox
2286
- label="Can sort favorites"
2287
- isChecked={canSortFavorites}
2288
- onChange={this.toggleFavsSort}
2289
- aria-label="toggle select all checkbox"
2290
- id="toggle-select-all"
2291
- name="toggle-select-all"
2292
- />
2293
- <Table
2294
- // using this prop enables the favorites column
2295
- onFavorite={this.onFavorite}
2296
- // if the onSort prop is detected, favorites can be sorted
2297
- // if you want to exclude favorites from sorting you can use this prop with a value of `false`
2298
- canSortFavorites={canSortFavorites}
2299
- onSelect={this.onSelect}
2300
- onSort={this.onSort}
2301
- sortBy={sortBy}
2302
- aria-label="Favoritable Table"
2303
- cells={columns}
2304
- rows={rows}
2305
- >
2306
- <TableHeader />
2307
- <TableBody />
2308
- </Table>
2309
- </div>
2310
- );
2311
- }
2312
- }
764
+ ```ts file="LegacyTableFavoritable.tsx"
2313
765
  ```
2314
766
 
2315
767
  ### Tree table
@@ -2338,222 +790,5 @@ Note: If this table is going to be tested using axe-core, the tests will flag th
2338
790
  aria-posinset, and aria-setsize as violations. This is an intentional choice at this time so that
2339
791
  the voice over technologies will recognize the flat table structure as a tree.
2340
792
 
2341
- ```js isBeta
2342
- import React from 'react';
2343
- import { Table, TableHeader, TableBody, headerCol, treeRow } from '@patternfly/react-table';
2344
- import LeafIcon from '@patternfly/react-icons/dist/esm/icons/leaf-icon';
2345
- import FolderIcon from '@patternfly/react-icons/dist/esm/icons/folder-icon';
2346
- import FolderOpenIcon from '@patternfly/react-icons/dist/esm/icons/folder-open-icon';
2347
-
2348
- class TreeTable extends React.Component {
2349
- constructor(props) {
2350
- super(props);
2351
- this.state = {
2352
- data: [
2353
- {
2354
- repositories: 'Repositories one',
2355
- branches: 'Branch one',
2356
- pullRequests: 'Pull request one',
2357
- workspaces: 'Workplace one',
2358
- children: [
2359
- {
2360
- repositories: 'Repositories two',
2361
- branches: 'Branch two',
2362
- pullRequests: 'Pull request two',
2363
- workspaces: 'Workplace two',
2364
- children: [
2365
- {
2366
- repositories: 'Repositories three',
2367
- branches: 'Branch three',
2368
- pullRequests: 'Pull request three',
2369
- workspaces: 'Workplace three'
2370
- },
2371
- {
2372
- repositories: 'Repositories four',
2373
- branches: 'Branch four',
2374
- pullRequests: 'Pull request four',
2375
- workspaces: 'Workplace four'
2376
- }
2377
- ]
2378
- },
2379
- {
2380
- repositories: 'Repositories five',
2381
- branches: 'Branch five',
2382
- pullRequests: 'Pull request five',
2383
- workspaces: 'Workplace five'
2384
- },
2385
- {
2386
- repositories: 'Repositories six',
2387
- branches: 'Branch six',
2388
- pullRequests: 'Pull request six',
2389
- workspaces: 'Workplace six'
2390
- }
2391
- ]
2392
- },
2393
- {
2394
- repositories: 'Repositories seven',
2395
- branches: 'Branch seven',
2396
- pullRequests: 'Pull request seven',
2397
- workspaces: 'Workplace seven',
2398
- children: [
2399
- {
2400
- repositories: 'Repositories eight',
2401
- branches: 'Branch eight',
2402
- pullRequests: 'Pull request eight',
2403
- workspaces: 'Workplace eight'
2404
- }
2405
- ]
2406
- },
2407
- {
2408
- repositories: 'Repositories nine',
2409
- branches: 'Branch nine',
2410
- pullRequests: 'Pull request nine',
2411
- workspaces: 'Workplace nine'
2412
- }
2413
- ],
2414
- expandedRows: ['Repositories one', 'Repositories six'],
2415
- expandedDetailsRows: [],
2416
- checkedRows: []
2417
- };
2418
-
2419
- /**
2420
- Recursive function which flattens the data into an array flattened IRow objects
2421
- to be passed to the `rows` prop of the Table
2422
- params:
2423
- - rowData - array of data
2424
- - level - number representing how deeply nested the current row is
2425
- - posinset - position of the row relative to this row's siblings
2426
- - isHidden - defaults to false, true if this row's parent is expanded
2427
- */
2428
- this.buildRows = ([x, ...xs], level, posinset, isHidden = false) => {
2429
- if (x) {
2430
- const isExpanded = this.state.expandedRows.includes(x.repositories);
2431
- const isDetailsExpanded = this.state.expandedDetailsRows.includes(x.repositories);
2432
- const isChecked = this.mapChecked(x);
2433
- let icon = <LeafIcon />;
2434
- if (x.children) {
2435
- icon = isExpanded ? <FolderOpenIcon aria-hidden /> : <FolderIcon aria-hidden />;
2436
- }
2437
-
2438
- return [
2439
- {
2440
- cells: [x.repositories, x.branches, x.pullRequests, x.workspaces],
2441
- props: {
2442
- isExpanded,
2443
- isDetailsExpanded,
2444
- isHidden,
2445
- 'aria-level': level,
2446
- 'aria-posinset': posinset,
2447
- 'aria-setsize': x.children ? x.children.length : 0,
2448
- isChecked,
2449
- icon
2450
- }
2451
- },
2452
- ...(x.children && x.children.length ? this.buildRows(x.children, level + 1, 1, !isExpanded || isHidden) : []),
2453
- ...this.buildRows(xs, level, posinset + 1, isHidden)
2454
- ];
2455
- }
2456
- return [];
2457
- };
2458
-
2459
- this.onToggleRowDetails = (event, rowIndex, title) => {
2460
- this.setState(prevState => {
2461
- const { expandedDetailsRows } = prevState;
2462
- const openedIndex = expandedDetailsRows.indexOf(title);
2463
- const newExpandedDetailsRows =
2464
- openedIndex === -1 ? [...expandedDetailsRows, title] : expandedDetailsRows.filter(o => o !== title);
2465
- return {
2466
- expandedDetailsRows: newExpandedDetailsRows
2467
- };
2468
- });
2469
- };
2470
-
2471
- this.onCollapse = (event, rowIndex, title) => {
2472
- this.setState(prevState => {
2473
- const { expandedRows } = prevState;
2474
- const openedIndex = expandedRows.indexOf(title);
2475
- const newExpandedRows = openedIndex === -1 ? [...expandedRows, title] : expandedRows.filter(o => o !== title);
2476
- return {
2477
- expandedRows: newExpandedRows
2478
- };
2479
- });
2480
- };
2481
-
2482
- this.onCheck = (event, checked, rowIndex, checkedTitle) => {
2483
- this.setState(prevState => {
2484
- let flattenedData = this.getFlattenedTitles(prevState.data, checkedTitle);
2485
- const prevChecked = prevState.checkedRows;
2486
- return {
2487
- checkedRows: checked
2488
- ? prevChecked.concat(flattenedData.filter(title => !prevChecked.includes(title)))
2489
- : prevChecked.filter(title => !flattenedData.includes(title))
2490
- };
2491
- });
2492
- };
2493
-
2494
- // // helper methods for determining the checkbox's checked state for each row ///
2495
-
2496
- /** Recursive function which flattens the data into an array of row titles
2497
- * whose checkboxes' checked states are being updated.
2498
- * Titles are only added to the array if they are the root checked title node,
2499
- * or if they are a descendent of the root checked title node */
2500
- this.getFlattenedTitles = (data, checkedTitle, parentChecked) => {
2501
- let flattenedData = [];
2502
- data.forEach(item => {
2503
- if (item.repositories === checkedTitle || parentChecked) {
2504
- flattenedData.push(item.repositories);
2505
- }
2506
- if (item.children) {
2507
- flattenedData = flattenedData.concat(
2508
- this.getFlattenedTitles(item.children, checkedTitle, item.repositories === checkedTitle || parentChecked)
2509
- );
2510
- }
2511
- return flattenedData;
2512
- });
2513
- return flattenedData;
2514
- };
2515
-
2516
- this.areAllDescendantsChecked = row =>
2517
- row.children
2518
- ? row.children.every(child => this.areAllDescendantsChecked(child))
2519
- : this.state.checkedRows.indexOf(row.repositories) !== -1;
2520
-
2521
- this.areSomeDescendantsChecked = row =>
2522
- row.children
2523
- ? row.children.some(child => this.areSomeDescendantsChecked(child))
2524
- : this.state.checkedRows.indexOf(row.repositories) !== -1;
2525
-
2526
- this.mapChecked = row => {
2527
- if (this.areAllDescendantsChecked(row)) {
2528
- return true;
2529
- }
2530
- if (this.areSomeDescendantsChecked(row)) {
2531
- return null;
2532
- }
2533
- return false;
2534
- };
2535
- }
2536
-
2537
- render() {
2538
- return (
2539
- <Table
2540
- isTreeTable
2541
- aria-label="Tree table"
2542
- cells={[
2543
- {
2544
- title: 'Repositories',
2545
- cellTransforms: [treeRow(this.onCollapse, this.onCheck, this.onToggleRowDetails)]
2546
- },
2547
- 'Branches',
2548
- { title: 'Pull requests' },
2549
- 'Workspaces'
2550
- ]}
2551
- rows={this.buildRows(this.state.data, 1, 1)}
2552
- >
2553
- <TableHeader />
2554
- <TableBody />
2555
- </Table>
2556
- );
2557
- }
2558
- }
793
+ ```ts isBeta file="LegacyTableTree.tsx"
2559
794
  ```