From 87d3bf683a098478c45302fdce3b1efdb05dbd15 Mon Sep 17 00:00:00 2001 From: hackape Date: Mon, 26 Feb 2018 18:46:37 +0800 Subject: [PATCH 01/12] copy HeadTable as FootTable, as a base to start --- src/FootTable.js | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/FootTable.js diff --git a/src/FootTable.js b/src/FootTable.js new file mode 100644 index 000000000..92acbc138 --- /dev/null +++ b/src/FootTable.js @@ -0,0 +1,61 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { measureScrollbar } from './utils'; +import BaseTable from './BaseTable'; + +export default function HeadTable(props, { table }) { + const { prefixCls, scroll, showHeader } = table.props; + const { columns, fixed, tableClassName, handleBodyScrollLeft, expander } = props; + const { saveRef } = table; + let { useFixedHeader } = table.props; + const headStyle = {}; + + if (scroll.y) { + useFixedHeader = true; + // Add negative margin bottom for scroll bar overflow bug + const scrollbarWidth = measureScrollbar(); + if (scrollbarWidth > 0 && !fixed) { + headStyle.marginBottom = `-${scrollbarWidth}px`; + headStyle.paddingBottom = '0px'; + } + } + + if (!useFixedHeader || !showHeader) { + return null; + } + + return ( +
+ +
+ ); +} + +HeadTable.propTypes = { + fixed: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.bool, + ]), + columns: PropTypes.array.isRequired, + tableClassName: PropTypes.string.isRequired, + handleBodyScrollLeft: PropTypes.func.isRequired, + expander: PropTypes.object.isRequired, +}; + +HeadTable.contextTypes = { + table: PropTypes.any, +}; From c774d846250240fbc00096c4c2c63e370714f98d Mon Sep 17 00:00:00 2001 From: hackape Date: Mon, 26 Feb 2018 18:51:45 +0800 Subject: [PATCH 02/12] rename and mod FootTable content accordingly --- src/FootTable.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/FootTable.js b/src/FootTable.js index 92acbc138..4501d586d 100644 --- a/src/FootTable.js +++ b/src/FootTable.js @@ -3,40 +3,40 @@ import PropTypes from 'prop-types'; import { measureScrollbar } from './utils'; import BaseTable from './BaseTable'; -export default function HeadTable(props, { table }) { - const { prefixCls, scroll, showHeader } = table.props; +export default function FootTable(props, { table }) { + const { prefixCls, scroll } = table.props; const { columns, fixed, tableClassName, handleBodyScrollLeft, expander } = props; const { saveRef } = table; let { useFixedHeader } = table.props; - const headStyle = {}; + const footStyle = {}; if (scroll.y) { useFixedHeader = true; // Add negative margin bottom for scroll bar overflow bug const scrollbarWidth = measureScrollbar(); if (scrollbarWidth > 0 && !fixed) { - headStyle.marginBottom = `-${scrollbarWidth}px`; - headStyle.paddingBottom = '0px'; + footStyle.marginBottom = `-${scrollbarWidth}px`; + footStyle.paddingBottom = '0px'; } } - if (!useFixedHeader || !showHeader) { + if (!useFixedHeader) { return null; } return (
Date: Thu, 22 Mar 2018 17:57:04 +0800 Subject: [PATCH 03/12] implement TableFooter --- src/TableFooter.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/TableFooter.js diff --git a/src/TableFooter.js b/src/TableFooter.js new file mode 100644 index 000000000..fce52b4d7 --- /dev/null +++ b/src/TableFooter.js @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import get from 'lodash/get'; + +export default function TableFooter(props, { table }) { + const { columnManager, components, } = table; + const { prefixCls, data, expandIconAsCell } = table.props; + const { columns, fixed } = props; + + const expandIconCol = { + key: 'expand-icon-placeholder', + render: () => null + } + + let leafColumns; + if (fixed === 'left') { + leafColumns = columnManager.leftLeafColumns(); + if (expandIconAsCell) { + leafColumns = [expandIconCol, ...leafColumns]; + } + } else if (fixed === 'right') { + leafColumns = columnManager.rightLeafColumns(); + } else { + leafColumns = columnManager.leafColumns(); + if (expandIconAsCell) { + leafColumns = [expandIconCol, ...leafColumns]; + } + } + + if (!columnManager.leafColumns().some(col => col.footer)) { + return null; + } + + const FooterWrapper = components.footer.wrapper; + const FooterRow = components.footer.row; + const FooterCell = components.footer.cell; + + return ( + + + {leafColumns.map(col => + {col.footer ? col.footer(data.map(item => item[col.dataIndex]), data) : null} + )} + + + ); +} + +TableFooter.propTypes = { + fixed: PropTypes.string, + columns: PropTypes.array.isRequired, +}; + +TableFooter.contextTypes = { + table: PropTypes.any, +}; From 2bab59fe596d2d8fdeb891d19fbddff20e63efe4 Mon Sep 17 00:00:00 2001 From: hackape Date: Mon, 26 Feb 2018 18:36:19 +0800 Subject: [PATCH 04/12] add `hasFoot` prop to BaseTable and insert TableFooter --- src/BaseTable.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/BaseTable.js b/src/BaseTable.js index 18d91610f..0d1be2418 100644 --- a/src/BaseTable.js +++ b/src/BaseTable.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'mini-store'; import ColGroup from './ColGroup'; import TableHeader from './TableHeader'; +import TableFooter from './TableFooter'; import TableRow from './TableRow'; import ExpandableRow from './ExpandableRow'; @@ -16,6 +17,7 @@ class BaseTable extends React.Component { tableClassName: PropTypes.string.isRequired, hasHead: PropTypes.bool.isRequired, hasBody: PropTypes.bool.isRequired, + hasFoot: PropTypes.bool.isRequired, store: PropTypes.object.isRequired, expander: PropTypes.object.isRequired, getRowKey: PropTypes.func, @@ -134,7 +136,7 @@ class BaseTable extends React.Component { const { table } = this.context; const { components } = table; const { prefixCls, scroll, data, getBodyWrapper } = table.props; - const { expander, tableClassName, hasHead, hasBody, fixed, columns } = this.props; + const { expander, tableClassName, hasHead, hasBody, hasFoot, fixed, columns } = this.props; const tableStyle = {}; if (!fixed && scroll.x) { @@ -165,6 +167,7 @@ class BaseTable extends React.Component { {hasHead && } + {hasFoot && } {body}
); From b57462bdbc8a9fd9c9832a8a963919103169fcff Mon Sep 17 00:00:00 2001 From: hackape Date: Thu, 22 Mar 2018 17:57:28 +0800 Subject: [PATCH 05/12] add `component.footer` default props --- src/Table.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Table.js b/src/Table.js index 8d9ecea1b..0aea788b2 100644 --- a/src/Table.js +++ b/src/Table.js @@ -49,6 +49,11 @@ export default class Table extends React.Component { row: PropTypes.any, cell: PropTypes.any, }), + footer: PropTypes.shape({ + wrapper: PropTypes.any, + row: PropTypes.any, + cell: PropTypes.any, + }), }), ...ExpandableTable.PropTypes, } @@ -126,6 +131,11 @@ export default class Table extends React.Component { row: 'tr', cell: 'td', }, + footer: { + wrapper: 'tfoot', + row: 'tr', + cell: 'td', + }, }, this.props.components), }, }; From c495e6d85f057acab0be29063e631910d5105e19 Mon Sep 17 00:00:00 2001 From: hackape Date: Thu, 22 Mar 2018 18:47:03 +0800 Subject: [PATCH 06/12] pass in hasFoot props, correct className --- src/BodyTable.js | 1 + src/FootTable.js | 2 +- src/HeadTable.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BodyTable.js b/src/BodyTable.js index 3648dafb5..bc3f806cc 100644 --- a/src/BodyTable.js +++ b/src/BodyTable.js @@ -51,6 +51,7 @@ export default function BodyTable(props, { table }) { tableClassName={tableClassName} hasHead={!useFixedHeader} hasBody + hasFoot={!useFixedHeader} fixed={fixed} columns={columns} expander={expander} diff --git a/src/FootTable.js b/src/FootTable.js index 4501d586d..c20549a1d 100644 --- a/src/FootTable.js +++ b/src/FootTable.js @@ -28,7 +28,7 @@ export default function FootTable(props, { table }) {
diff --git a/src/HeadTable.js b/src/HeadTable.js index 5b427f9e6..6c206aff5 100644 --- a/src/HeadTable.js +++ b/src/HeadTable.js @@ -36,6 +36,7 @@ export default function HeadTable(props, { table }) { tableClassName={tableClassName} hasHead hasBody={false} + hasFoot={false} fixed={fixed} columns={columns} expander={expander} From 6acecc9d657af7feb97f420474882c042fc23b0e Mon Sep 17 00:00:00 2001 From: hackape Date: Thu, 22 Mar 2018 18:47:56 +0800 Subject: [PATCH 07/12] apply same style as header to footer --- assets/index.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/index.less b/assets/index.less index 173d5f1eb..c8d39e65b 100644 --- a/assets/index.less +++ b/assets/index.less @@ -38,7 +38,8 @@ overflow: scroll; } - &-fixed-header &-scroll &-header { + &-fixed-header &-scroll &-header, + &-fixed-header &-scroll &-in-table-footer { overflow-x: scroll; padding-bottom: 20px; margin-bottom: -20px; From 074ead953b0cafd31c83f1164f119efb9545b5fb Mon Sep 17 00:00:00 2001 From: hackape Date: Thu, 22 Mar 2018 18:48:33 +0800 Subject: [PATCH 08/12] include FootTable.js to Table.js --- src/Table.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Table.js b/src/Table.js index 0aea788b2..6ccc4049f 100644 --- a/src/Table.js +++ b/src/Table.js @@ -9,6 +9,7 @@ import ColumnManager from './ColumnManager'; import classes from 'component-classes'; import HeadTable from './HeadTable'; import BodyTable from './BodyTable'; +import FootTable from './FootTable'; import ExpandableTable from './ExpandableTable'; export default class Table extends React.Component { @@ -400,7 +401,18 @@ export default class Table extends React.Component { /> ); - return [headTable, bodyTable]; + const footTable = ( + + ) + + return [headTable, bodyTable, footTable]; } renderTitle() { From ba413dcbce20834b2a207489ed9bc826dabe609b Mon Sep 17 00:00:00 2001 From: hackape Date: Thu, 22 Mar 2018 18:48:45 +0800 Subject: [PATCH 09/12] sync scroll effect --- src/Table.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Table.js b/src/Table.js index 6ccc4049f..6e4b8be38 100644 --- a/src/Table.js +++ b/src/Table.js @@ -271,6 +271,9 @@ export default class Table extends React.Component { if (this.bodyTable) { this.bodyTable.scrollLeft = 0; } + if (this.footTable) { + this.footTable.scrollLeft = 0; + } } hasScrollX() { @@ -285,12 +288,17 @@ export default class Table extends React.Component { } const target = e.target; const { scroll = {} } = this.props; - const { headTable, bodyTable } = this; + const { headTable, bodyTable, footTable } = this; if (target.scrollLeft !== this.lastScrollLeft && scroll.x) { - if (target === bodyTable && headTable) { - headTable.scrollLeft = target.scrollLeft; - } else if (target === headTable && bodyTable) { - bodyTable.scrollLeft = target.scrollLeft; + if (target === bodyTable) { + if (headTable) headTable.scrollLeft = target.scrollLeft; + if (footTable) footTable.scrollLeft = target.scrollLeft; + } else if (target === headTable) { + if (bodyTable) bodyTable.scrollLeft = target.scrollLeft; + if (footTable) footTable.scrollLeft = target.scrollLeft; + } else if (target === footTable) { + if (bodyTable) bodyTable.scrollLeft = target.scrollLeft; + if (headTable) headTable.scrollLeft = target.scrollLeft; } this.setScrollPositionClassName(); } From 3392123674a42b5ac30333dc9f70a02be351c9d1 Mon Sep 17 00:00:00 2001 From: hackape Date: Fri, 23 Mar 2018 11:02:23 +0800 Subject: [PATCH 10/12] `column.footer` accept both function and ReactNode --- src/Column.js | 1 + src/TableFooter.js | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Column.js b/src/Column.js index f891975b1..8b4d898ae 100644 --- a/src/Column.js +++ b/src/Column.js @@ -6,6 +6,7 @@ export default class Column extends Component { className: PropTypes.string, colSpan: PropTypes.number, title: PropTypes.node, + footer: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), dataIndex: PropTypes.string, width: PropTypes.oneOfType([ PropTypes.number, diff --git a/src/TableFooter.js b/src/TableFooter.js index fce52b4d7..096726f26 100644 --- a/src/TableFooter.js +++ b/src/TableFooter.js @@ -2,11 +2,20 @@ import React from 'react'; import PropTypes from 'prop-types'; import get from 'lodash/get'; +function getColumnFooter(col) { + if (typeof col.footer === 'function') return col.footer + return () => col.footer +} + export default function TableFooter(props, { table }) { const { columnManager, components, } = table; const { prefixCls, data, expandIconAsCell } = table.props; const { columns, fixed } = props; + if (!columnManager.leafColumns().some(col => col.footer)) { + return null; + } + const expandIconCol = { key: 'expand-icon-placeholder', render: () => null @@ -27,10 +36,6 @@ export default function TableFooter(props, { table }) { } } - if (!columnManager.leafColumns().some(col => col.footer)) { - return null; - } - const FooterWrapper = components.footer.wrapper; const FooterRow = components.footer.row; const FooterCell = components.footer.cell; @@ -39,7 +44,7 @@ export default function TableFooter(props, { table }) { {leafColumns.map(col => - {col.footer ? col.footer(data.map(item => item[col.dataIndex]), data) : null} + {col.footer === undefined ? null : getColumnFooter(col)(data)} )} From cb21f2a7f21f86211ee15475337428387be17c5f Mon Sep 17 00:00:00 2001 From: hackape Date: Fri, 23 Mar 2018 11:23:59 +0800 Subject: [PATCH 11/12] add column footer example --- examples/columnFooter.html | 0 examples/columnFooter.js | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 examples/columnFooter.html create mode 100644 examples/columnFooter.js diff --git a/examples/columnFooter.html b/examples/columnFooter.html new file mode 100644 index 000000000..e69de29bb diff --git a/examples/columnFooter.js b/examples/columnFooter.js new file mode 100644 index 000000000..537e7a266 --- /dev/null +++ b/examples/columnFooter.js @@ -0,0 +1,46 @@ +/* eslint-disable no-console,func-names,react/no-multi-comp */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import Table from 'rc-table'; +import 'rc-table/assets/index.less'; + +const columns = [ + { title: 'Name', dataIndex: 'name', width: 100, fixed: 'left', footer: 'Summary' }, + { title: 'Money', dataIndex: 'money', width: 100, render: (text) => '$' + text.toFixed(2), footer: (data) => 'Total: $' + data.reduce((acc, row) => acc + row.money, 0).toFixed(2) }, + { title: 'Address', dataIndex: 'address', width: 300 } +]; + +const data = [ + { + name: 'John Brown', + money: 300, + address: 'New York No. 1 Lake Park', + }, { + name: 'Jim Green', + money: 128, + address: 'London No. 1 Lake Park', + }, { + name: 'Joe Black', + money: 240, + address: 'Sidney No. 1 Lake Park', + }, { + name: 'Mick Sydney', + money: 300, + address: 'Sidney No. 1 Lake Park', + }, { + name: 'Miguel Manning', + money: 120, + address: 'Sidney No. 1 Lake Park', + }, { + name: 'John Appleseed', + money: 256, + address: '1 Infinite Loop; Cupertino, CA 95014', + } +]; + +ReactDOM.render( +
+

Demonstrate column footer

+ + +, document.getElementById('__react-content')); From e28b0eefcdc8c4a04500a465075dcd42c2c7dbba Mon Sep 17 00:00:00 2001 From: hackape Date: Fri, 23 Mar 2018 12:24:38 +0800 Subject: [PATCH 12/12] code style: fix lint problem --- examples/columnFooter.js | 40 +++++++++++++++++++++++++++++----------- src/Table.js | 2 +- src/TableFooter.js | 19 +++++++++++-------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/examples/columnFooter.js b/examples/columnFooter.js index 537e7a266..c23d5701b 100644 --- a/examples/columnFooter.js +++ b/examples/columnFooter.js @@ -5,9 +5,21 @@ import Table from 'rc-table'; import 'rc-table/assets/index.less'; const columns = [ - { title: 'Name', dataIndex: 'name', width: 100, fixed: 'left', footer: 'Summary' }, - { title: 'Money', dataIndex: 'money', width: 100, render: (text) => '$' + text.toFixed(2), footer: (data) => 'Total: $' + data.reduce((acc, row) => acc + row.money, 0).toFixed(2) }, - { title: 'Address', dataIndex: 'address', width: 300 } + { + title: 'Name', + dataIndex: 'name', + width: 100, + fixed: 'left', + footer: 'Summary', + }, + { + title: 'Money', + dataIndex: 'money', + width: 100, + render: text => `$${text.toFixed(2)}`, + footer: data => `Total: $${data.reduce((acc, row) => acc + row.money, 0).toFixed(2)}`, + }, + { title: 'Address', dataIndex: 'address', width: 300 }, ]; const data = [ @@ -15,32 +27,38 @@ const data = [ name: 'John Brown', money: 300, address: 'New York No. 1 Lake Park', - }, { + }, + { name: 'Jim Green', money: 128, address: 'London No. 1 Lake Park', - }, { + }, + { name: 'Joe Black', money: 240, address: 'Sidney No. 1 Lake Park', - }, { + }, + { name: 'Mick Sydney', money: 300, address: 'Sidney No. 1 Lake Park', - }, { + }, + { name: 'Miguel Manning', money: 120, address: 'Sidney No. 1 Lake Park', - }, { + }, + { name: 'John Appleseed', money: 256, address: '1 Infinite Loop; Cupertino, CA 95014', - } + }, ]; ReactDOM.render(

Demonstrate column footer

- -, document.getElementById('__react-content')); + , + document.getElementById('__react-content') +); diff --git a/src/Table.js b/src/Table.js index 6e4b8be38..3c5350e95 100644 --- a/src/Table.js +++ b/src/Table.js @@ -418,7 +418,7 @@ export default class Table extends React.Component { handleBodyScrollLeft={this.handleBodyScrollLeft} expander={this.expander} /> - ) + ); return [headTable, bodyTable, footTable]; } diff --git a/src/TableFooter.js b/src/TableFooter.js index 096726f26..65fb8c347 100644 --- a/src/TableFooter.js +++ b/src/TableFooter.js @@ -1,16 +1,15 @@ import React from 'react'; import PropTypes from 'prop-types'; -import get from 'lodash/get'; function getColumnFooter(col) { - if (typeof col.footer === 'function') return col.footer - return () => col.footer + if (typeof col.footer === 'function') return col.footer; + return () => col.footer; } export default function TableFooter(props, { table }) { - const { columnManager, components, } = table; + const { columnManager, components } = table; const { prefixCls, data, expandIconAsCell } = table.props; - const { columns, fixed } = props; + const { fixed } = props; if (!columnManager.leafColumns().some(col => col.footer)) { return null; @@ -18,8 +17,8 @@ export default function TableFooter(props, { table }) { const expandIconCol = { key: 'expand-icon-placeholder', - render: () => null - } + render: () => null, + }; let leafColumns; if (fixed === 'left') { @@ -44,7 +43,11 @@ export default function TableFooter(props, { table }) { {leafColumns.map(col => - {col.footer === undefined ? null : getColumnFooter(col)(data)} + + {col.footer === undefined ? null : getColumnFooter(col)(data)} + )}