From 67c37e95f9187f496fd4a50c6cf4248e1d9666c3 Mon Sep 17 00:00:00 2001 From: "ChunMing, Chen" Date: Sat, 2 Sep 2017 19:15:34 +0800 Subject: [PATCH] fix #18 * allow user to customize class for header cell * add corresponding story * allow user to customize inline-style for header cell * add corresponding story * [test] unit test for headerStyle * [test] unit test for headerClasses * update Document --- docs/columns.md | 27 ++++++ .../header-columns/column-class-table.js | 62 ++++++++++++ .../header-columns/column-style-table.js | 78 +++++++++++++++ .../stories/index.js | 6 +- .../react-bootstrap-table2/src/header-cell.js | 17 +++- .../test/header-cell.test.js | 96 +++++++++++++++++++ 6 files changed, 281 insertions(+), 5 deletions(-) create mode 100644 packages/react-bootstrap-table2-example/examples/header-columns/column-class-table.js create mode 100644 packages/react-bootstrap-table2-example/examples/header-columns/column-style-table.js diff --git a/docs/columns.md b/docs/columns.md index 281221a..38594d5 100644 --- a/docs/columns.md +++ b/docs/columns.md @@ -16,6 +16,8 @@ Available properties in a column object: * [headerTitle](#headerTitle) * [headerEvents](#headerEvents) * [headerAlign](#headerAlign) +* [headerClasses](#headerClasses) +* [headerStyle](#headerStyle) Following is a most simplest and basic usage: @@ -93,6 +95,20 @@ In addition, `classes` also accept a callback function which have more power to * `row` * `colIndex` +## column.headerClasses - [String | Function] +It's availabe to have customized class on table header column: + +```js +{ + // omit... + headerClasses: 'id-custom-cell' +} +``` +In addition, similar to [`column.classes`](#classes), `headerClasses` also accept a callback function which have more power to custom the css class on header column. This callback function take two arguments and a string is expect to return: + +* `column` +* `colIndex` + ## column.style - [Object | Function] It's availabe to have custom class on table column: @@ -104,6 +120,17 @@ It's availabe to have custom class on table column: ``` `style` like [`column.classes`](#classes), it accept a callback function too and have same arguments: `cell`, `row` and `colIndex`. +## column.headerStyle - [Object | Function] +It's availabe to have customized inline-style on table header column: + +```js +{ + // omit... + headerStyle: { backgroundColor: 'green' } +} +``` +`headerStyle` like [`column.headerClasses`](#headerClasses), it accept a callback function as well and have same arguments: `column` and `colIndex`. + ## column.title - [Bool | Function] `react-bootstrap-table2` is disable [`HTML title`](https://www.w3schools.com/tags/tag_title.asp) as default. You can assign `title` as `true` to enable the HTML title on table column. In addition, you can custom the title via a callback function: diff --git a/packages/react-bootstrap-table2-example/examples/header-columns/column-class-table.js b/packages/react-bootstrap-table2-example/examples/header-columns/column-class-table.js new file mode 100644 index 0000000..31f7e8a --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/header-columns/column-class-table.js @@ -0,0 +1,62 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import { BootstrapTable } from 'react-bootstrap-table2'; + +const products = []; + +function addProducts(quantity) { + const startId = products.length; + for (let i = 0; i < quantity; i += 1) { + const id = startId + i; + products.push({ + id, + name: `Item name ${id}`, + price: 2100 + i + }); + } +} + +addProducts(5); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + headerClasses: 'demo-row-odd' +}, { + dataField: 'price', + text: 'Product Price', + headerClasses: (column, colIndex) => { + if (colIndex % 2 === 0) return 'demo-row-even'; + return 'demo-row-odd'; + } +}]; + +export default () => ( +
+ +
{`
+const columns = [{
+  dataField: 'id',
+  text: 'Product ID'
+}, {
+  dataField: 'name',
+  text: 'Product Name',
+  headerClasses: 'demo-row-odd'
+}, {
+  dataField: 'price',
+  text: 'Product Price',
+  headerClasses: (column, colIndex) => {
+    if (colIndex % 2 === 0) return 'demo-row-even';
+    return 'demo-row-odd';
+  }
+}];
+
+
+    `}
+    
+
+); diff --git a/packages/react-bootstrap-table2-example/examples/header-columns/column-style-table.js b/packages/react-bootstrap-table2-example/examples/header-columns/column-style-table.js new file mode 100644 index 0000000..c02921e --- /dev/null +++ b/packages/react-bootstrap-table2-example/examples/header-columns/column-style-table.js @@ -0,0 +1,78 @@ +/* eslint no-unused-vars: 0 */ +import React from 'react'; + +import { BootstrapTable } from 'react-bootstrap-table2'; + +const products = []; + +function addProducts(quantity) { + const startId = products.length; + for (let i = 0; i < quantity; i += 1) { + const id = startId + i; + products.push({ + id, + name: `Item name ${id}`, + price: 2100 + i + }); + } +} + +addProducts(5); + +const columns = [{ + dataField: 'id', + text: 'Product ID' +}, { + dataField: 'name', + text: 'Product Name', + headerStyle: { + backgroundColor: '#fea' + } +}, { + dataField: 'price', + text: 'Product Price', + headerStyle: (column, colIndex) => { + if (colIndex % 2 === 0) { + return { + backgroundColor: '#bbe' + }; + } + return { + backgroundColor: '#fea' + }; + } +}]; + +export default () => ( +
+ +
{`
+const columns = [{
+  dataField: 'id',
+  text: 'Product ID'
+}, {
+  dataField: 'name',
+  text: 'Product Name',
+  headerStyle: {
+    backgroundColor: '#fea'
+  }
+}, {
+  dataField: 'price',
+  text: 'Product Price',
+  headerStyle: (column, colIndex) => {
+    if (colIndex % 2 === 0) {
+      return {
+        backgroundColor: '#bbe'
+      };
+    }
+    return {
+      backgroundColor: '#fea'
+    };
+  }
+}];
+
+
+    `}
+    
+
+); diff --git a/packages/react-bootstrap-table2-example/stories/index.js b/packages/react-bootstrap-table2-example/stories/index.js index 6d3a202..9857f3d 100644 --- a/packages/react-bootstrap-table2-example/stories/index.js +++ b/packages/react-bootstrap-table2-example/stories/index.js @@ -26,6 +26,8 @@ import HeaderColumnFormatTable from 'examples/header-columns/column-format-table import HeaderColumnAlignTable from 'examples/header-columns/column-align-table'; import HeaderColumnTitleTable from 'examples/header-columns/column-title-table'; import HeaderColumnEventTable from 'examples/header-columns/column-event-table'; +import HeaderColumnClassTable from 'examples/header-columns/column-class-table'; +import HeaderColumnStyleTable from 'examples/header-columns/column-style-table'; // css style import 'bootstrap/dist/css/bootstrap.min.css'; @@ -59,4 +61,6 @@ storiesOf('Work on Header Columns', module) .add('Column Formatter', () => ) .add('Column Align', () => ) .add('Column Title', () => ) - .add('Column Event', () => ); + .add('Column Event', () => ) + .add('Customize Column Class', () => ) + .add('Customize Column Style', () => ); diff --git a/packages/react-bootstrap-table2/src/header-cell.js b/packages/react-bootstrap-table2/src/header-cell.js index 036366b..062e4f6 100644 --- a/packages/react-bootstrap-table2/src/header-cell.js +++ b/packages/react-bootstrap-table2/src/header-cell.js @@ -11,23 +11,32 @@ const HeaderCell = ({ column, index }) => { headerTitle, headerAlign, headerFormatter, - headerEvents + headerEvents, + headerClasses, + headerStyle } = column; const attrs = { ...headerEvents }; - const headerStyle = {}; const children = headerFormatter ? headerFormatter(column, index) : text; + const cellClasses = _.isFunction(headerClasses) ? headerClasses(column, index) : headerClasses; + + let cellStyle = {}; + + if (headerStyle) { + cellStyle = _.isFunction(headerStyle) ? headerStyle(column, index) : headerStyle; + } if (headerTitle) { attrs.title = _.isFunction(headerTitle) ? headerTitle(column, index) : text; } if (headerAlign) { - headerStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign; + cellStyle.textAlign = _.isFunction(headerAlign) ? headerAlign(column, index) : headerAlign; } - attrs.style = headerStyle; + attrs.style = cellStyle; + attrs.className = cellClasses; if (hidden) { attrs.style.display = 'none'; diff --git a/packages/react-bootstrap-table2/test/header-cell.test.js b/packages/react-bootstrap-table2/test/header-cell.test.js index 019f35b..0dd027a 100644 --- a/packages/react-bootstrap-table2/test/header-cell.test.js +++ b/packages/react-bootstrap-table2/test/header-cell.test.js @@ -191,4 +191,100 @@ describe('HeaderCell', () => { expect(column.headerEvents.onClick.callCount).toBe(1); }); }); + + describe('when column.headerStyle prop is defined', () => { + let column; + + beforeEach(() => { + column = { + dataField: 'id', + text: 'ID' + }; + }); + + describe('when headerStyle is an object', () => { + beforeEach(() => { + column.headerStyle = { backgroundColor: 'red' }; + wrapper = shallow(); + }); + + it('should render successfully', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('th').prop('style')).toEqual(column.headerStyle); + }); + }); + + describe('when headerStyle is a function', () => { + const returnStyle = { backgroundColor: 'red' }; + let styleCallBack; + + beforeEach(() => { + styleCallBack = sinon.stub() + .withArgs(column, index) + .returns(returnStyle); + column.headerStyle = styleCallBack; + wrapper = shallow(); + }); + + afterEach(() => { styleCallBack.reset(); }); + + it('should render successfully', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.find('th').prop('style')).toEqual(returnStyle); + }); + + it('should call custom style function correctly', () => { + expect(styleCallBack.callCount).toBe(1); + expect(styleCallBack.calledWith(column, index)).toBe(true); + }); + }); + }); + + describe('when column.headerClasses prop is defined', () => { + let column; + + beforeEach(() => { + column = { + dataField: 'id', + text: 'ID' + }; + }); + + describe('when headerClasses is an object', () => { + beforeEach(() => { + column.headerClasses = 'td-test-class'; + wrapper = shallow(); + }); + + it('should render successfully', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.hasClass(column.headerClasses)).toBe(true); + }); + }); + + describe('when headerClasses is a function', () => { + const returnClasses = 'td-test-class'; + let classesCallBack; + + beforeEach(() => { + classesCallBack = sinon.stub() + .withArgs(column, index) + .returns(returnClasses); + column.headerClasses = classesCallBack; + wrapper = shallow(); + }); + + afterEach(() => { classesCallBack.reset(); }); + + it('should render successfully', () => { + expect(wrapper.length).toBe(1); + expect(wrapper.hasClass(returnClasses)).toBe(true); + }); + + it('should call custom classes function correctly', () => { + expect(classesCallBack.callCount).toBe(1); + expect(classesCallBack.calledWith(column, index)).toBe(true); + }); + }); + }); });