Skip to content

Commit 0ff6972

Browse files
committed
feat(table): allow custom action definition
1 parent 5c3170d commit 0ff6972

File tree

6 files changed

+93
-36
lines changed

6 files changed

+93
-36
lines changed

demo/TableExamples.jsx

+10
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,16 @@ export function TableExamples() {
207207
],
208208
sortState
209209
)}
210+
actions={(doc, docIndex) => [
211+
{
212+
title: 'Add',
213+
content: <span>{doc.b + docIndex}?</span>,
214+
},
215+
{
216+
title: 'Subtract',
217+
content: <span>{doc.b - docIndex}?</span>,
218+
},
219+
]}
210220
/>
211221
</div>
212222
</div>

demo/demo.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ReactDOM.render(
1818
<StatefulTabs
1919
vertical={true}
2020
onlyRenderActiveTab={true}
21-
initialTab={1}
21+
initialTab={5}
2222
tabs={[
2323
{
2424
title: 'Dialog',

src/table/Table.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function Table({
3434
<div className="table-responsive">
3535
<table className={tableClasses}>
3636
{caption && <caption>{caption}</caption>}
37-
<TableHead {...{ actions, actionLabel, columnHeaderFormat }} columns={normalizedColumns} />
37+
<TableHead {...{ actionLabel, columnHeaderFormat, hasActions: Boolean(actions) }} columns={normalizedColumns} />
3838
<TableBody {...{ docs, rowClass, actions, onRowClick }} columns={normalizedColumns} />
3939
</table>
4040
</div>
@@ -55,7 +55,7 @@ Table.defaultProps = {
5555

5656
Table.propTypes = {
5757
actionLabel: PropTypes.string,
58-
actions: PropTypes.arrayOf(PropTypes.object),
58+
actions: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.object)]),
5959
bordered: PropTypes.bool,
6060
caption: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
6161
columnHeaderFormat: PropTypes.func,

src/table/TableActions.jsx

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
4+
import { safeClick, stopPropagation } from '../utils/event-handlers';
5+
import { isFunction } from '../utils/types';
6+
7+
export function TableActions({ doc, docIndex, actions }) {
8+
if (!actions) {
9+
return null;
10+
}
11+
12+
const normalizedActions = normalizeAction(actions, doc, docIndex);
13+
14+
return (
15+
<td className="text-center">
16+
{normalizedActions.map((action, actionIndex) => (
17+
<span key={actionIndex} className={actionIndex > 0 ? 'ml-2' : ''}>
18+
<TableAction doc={doc} docIndex={docIndex} action={action} />
19+
</span>
20+
))}
21+
</td>
22+
);
23+
}
24+
25+
TableActions.propTypes = {
26+
doc: PropTypes.object.isRequired,
27+
docIndex: PropTypes.number.isRequired,
28+
actions: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.object)]),
29+
};
30+
31+
function TableAction({ doc, docIndex, action }) {
32+
if (isFunction(action)) {
33+
return action(doc, docIndex) || null;
34+
}
35+
36+
if (action.onClick || action.link) {
37+
return (
38+
<a title={action.title} {...getActionProps(action, doc, docIndex)}>
39+
{action.content}
40+
</a>
41+
);
42+
}
43+
44+
return action.content;
45+
}
46+
47+
TableAction.propTypes = {
48+
doc: PropTypes.object.isRequired,
49+
docIndex: PropTypes.number.isRequired,
50+
action: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
51+
};
52+
53+
function getActionProps(action, doc, docIndex) {
54+
const props = {};
55+
56+
if (action.onClick) {
57+
props.href = '';
58+
props.onClick = safeClick(action.onClick, doc, docIndex);
59+
} else if (action.link) {
60+
props.onClick = stopPropagation;
61+
props.href = action.link(doc, docIndex);
62+
}
63+
64+
return props;
65+
}
66+
67+
function normalizeAction(actions, doc, docIndex) {
68+
if (isFunction(actions)) {
69+
return actions(doc, docIndex);
70+
}
71+
72+
return actions;
73+
}

src/table/TableBody.jsx

+4-30
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
33
import { getColumnClass } from './table-helpers';
4-
import { safeClick, stopPropagation } from '../utils/event-handlers';
4+
import { safeClick } from '../utils/event-handlers';
55
import { getValueByPath } from '../utils/getters-setters';
6+
import { TableActions } from './TableActions';
67

78
export function TableBody({ columns, docs, rowClass, actions, onRowClick }) {
89
return (
@@ -15,28 +16,15 @@ export function TableBody({ columns, docs, rowClass, actions, onRowClick }) {
1516
</td>
1617
))}
1718

18-
{actions && (
19-
<td className="text-center">
20-
{actions.map((action, actionIndex) => (
21-
<a
22-
key={actionIndex}
23-
title={action.title}
24-
{...getActionProps(action, doc, docIndex)}
25-
className={actionIndex > 0 ? 'ml-2' : ''}
26-
>
27-
{action.content}
28-
</a>
29-
))}
30-
</td>
31-
)}
19+
<TableActions doc={doc} docIndex={docIndex} actions={actions} />
3220
</tr>
3321
))}
3422
</tbody>
3523
);
3624
}
3725

3826
TableBody.propTypes = {
39-
actions: PropTypes.arrayOf(PropTypes.object),
27+
actions: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.object)]),
4028
columns: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
4129
docs: PropTypes.arrayOf(PropTypes.object),
4230
rowClass: PropTypes.func,
@@ -52,17 +40,3 @@ function getColumnValue(doc, column, docIndex) {
5240

5341
return column.format(rawValue, doc, docIndex);
5442
}
55-
56-
function getActionProps(action, doc, docIndex) {
57-
const props = {};
58-
59-
if (action.onClick) {
60-
props.href = '';
61-
props.onClick = safeClick(action.onClick, doc, docIndex);
62-
} else if (action.link) {
63-
props.onClick = stopPropagation;
64-
props.href = action.link(doc, docIndex);
65-
}
66-
67-
return props;
68-
}

src/table/TableHead.jsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import PropTypes from 'prop-types';
33
import { getColumnClass } from './table-helpers';
44

5-
export function TableHead({ columns, actions, actionLabel, columnHeaderFormat }) {
5+
export function TableHead({ columns, hasActions, actionLabel, columnHeaderFormat }) {
66
return (
77
<thead>
88
<tr>
@@ -11,15 +11,15 @@ export function TableHead({ columns, actions, actionLabel, columnHeaderFormat })
1111
{columnHeaderFormat(column.label, column.attribute)}
1212
</th>
1313
))}
14-
{actions && <th className="text-center">{actionLabel}</th>}
14+
{hasActions && <th className="text-center">{actionLabel}</th>}
1515
</tr>
1616
</thead>
1717
);
1818
}
1919

2020
TableHead.propTypes = {
2121
actionLabel: PropTypes.string,
22-
actions: PropTypes.arrayOf(PropTypes.object),
22+
hasActions: PropTypes.bool,
2323
columns: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])),
2424
columnHeaderFormat: PropTypes.func.isRequired,
2525
};

0 commit comments

Comments
 (0)