diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 9396727c2..b00d103dd 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9d702d3ed..4ed7bf71e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -7,4 +7,4 @@ **After your pull request is merged**, you can safely delete your branch. -### [<- Back](https://github.com/mbrn/material-table/) \ No newline at end of file +### [<- Back](https://github.com/mbrn/material-table/) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f65a8c755..08d562293 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,21 +6,21 @@ labels: "bug" # Guidelines - - #### Please include a demo of the issue/behavior/question you have +- #### Please include a demo of the issue/behavior/question you have - - #### Please try to be as detailed as possible +- #### Please try to be as detailed as possible - - #### You may fork one of the following starter templates if you would like: - - - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) - - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) +- #### You may fork one of the following starter templates if you would like: + - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) + - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -33,15 +33,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 2facc803b..a656192ae 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -6,15 +6,14 @@ labels: "feature" # Guidelines - - #### Please include a demo of the issue/behavior/question you have +- #### Please include a demo of the issue/behavior/question you have - - #### Please try to be as detailed as possible +- #### Please try to be as detailed as possible - - #### You may fork one of the following starter templates if you would like: - - - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) - - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) +- #### You may fork one of the following starter templates if you would like: + - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) + - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] diff --git a/.github/ISSUE_TEMPLATE/help.md b/.github/ISSUE_TEMPLATE/help.md index 34090de0d..43dc00898 100644 --- a/.github/ISSUE_TEMPLATE/help.md +++ b/.github/ISSUE_TEMPLATE/help.md @@ -6,11 +6,11 @@ labels: "question" # Guidelines - - #### Please include a demo of the issue/behavior/question you have +- #### Please include a demo of the issue/behavior/question you have - - #### Please try to be as detailed as possible +- #### Please try to be as detailed as possible - - #### You may fork one of the following starter templates if you would like: +- #### You may fork one of the following starter templates if you would like: - - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) - - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) + - #### [CodeSandbox](https://codesandbox.io/s/material-table-starter-template-xnfpo) + - #### [StackBlitz](https://stackblitz.com/edit/material-table-starter-template) diff --git a/.github/actions/setup-node b/.github/actions/setup-node new file mode 100644 index 000000000..3ec96f707 --- /dev/null +++ b/.github/actions/setup-node @@ -0,0 +1,3 @@ +strategy: + matrix: + node-version: [8.16.2, 10.17.0] \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fdcb27b09..45cb683b8 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,21 +1,26 @@ ## Related Issue + Relate the Github issue with this PR using `#` ## Description + Simple words to describe the overall goals of the pull request's commits. ## Related PRs + List related PRs against other branches: -branch | PR ------- | ------ -other_pr_production | [link]() -other_pr_master | [link]() +| branch | PR | +| ------------------- | -------- | +| other_pr_production | [link]() | +| other_pr_master | [link]() | ## Impacted Areas in Application + List general components of the application that this PR will affect: -* +\* ## Additional Notes -This is optional, feel free to follow your hearth and write here :) \ No newline at end of file + +This is optional, feel free to follow your hearth and write here :) diff --git a/.github/stale.yml b/.github/stale.yml index 01ac0b7ee..c274dd9df 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -12,6 +12,6 @@ staleLabel: wontfix markComment: > This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. You can reopen it if it required. + for your contributions. You can reopen it if it required. # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 000000000..c023e2918 --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,19 @@ +name: Prettier CLI +# This action works with pull requests and pushes +on: + pull_request: + +jobs: + prettier: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: Prettify code + uses: creyD/prettier_action@v2.2 + with: + prettier_options: --write **/*.{js,tsx,ts,md} diff --git a/.travis.yml b/.travis.yml index 36eef50fe..d0dafb70b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: node_js version: 1.0 sudo: false node_js: - - 10 + - 10 install: - npm install script: diff --git a/README.md b/README.md index 1d31a7f22..89b70f30f 100644 --- a/README.md +++ b/README.md @@ -1,240 +1,245 @@ -

- material-table

-

- -

material-table

- -
- -A simple and powerful Datatable for React based on [Material-UI Table](https://material-ui.com/api/table/) with some additional features. - -[![Build Status](https://travis-ci.org/mbrn/material-table.svg?branch=master)](https://travis-ci.org/mbrn/material-table) -[![Financial Contributors on Open Collective](https://opencollective.com/material-table/all/badge.svg?label=financial+contributors)](https://opencollective.com/material-table) [![npm package](https://img.shields.io/npm/v/material-table/latest.svg)](https://www.npmjs.com/package/material-table) -[![NPM Downloads](https://img.shields.io/npm/dm/material-table.svg?style=flat)](https://npmcharts.com/compare/material-table?minimal=true) -[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/mbrn/material-table.svg)](http://isitmaintained.com/project/mbrn/material-table "Average time to resolve an issue") -[![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/mbrn/material-table) -[![Follow on Twitter](https://img.shields.io/twitter/follow/baranmehmet.svg?label=follow+baranmehmet)](https://twitter.com/baranmehmet) -[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/material-table/Lobby) - -
- -## Roadmap - - - [More on our roadmap can be found here](https://github.com/mbrn/material-table/blob/master/.github/ROADMAP.md) - -## Key features - -- [Actions](https://material-table.com/#/docs/features/actions) -- [Component overriding](https://material-table.com/#/docs/features/component-overriding) -- [Custom column rendering](https://material-table.com/#/docs/features/custom-column-rendering) -- [Detail Panel](https://material-table.com/#/docs/features/detail-panel) -- [Editable](https://material-table.com/#/docs/features/editable) -- [Export](https://material-table.com/#/docs/features/export) -- [Filtering](https://material-table.com/#/docs/features/filtering) -- [Grouping](https://material-table.com/#/docs/features/grouping) -- [Localization](https://material-table.com/#/docs/features/localization) -- [Remote Data](https://material-table.com/#/docs/features/remote-data) -- [Search](https://material-table.com/#/docs/features/search) -- [Selection](https://material-table.com/#/docs/features/selection) -- [Sorting](https://material-table.com/#/docs/features/sorting) -- [Styling](https://material-table.com/#/docs/features/styling) -- [Tree Data](https://material-table.com/#/docs/features/tree-data) -- and more - -## Demo and documentation - -You can access all code examples and documentation on our site [**material-table.com**](https://material-table.com/). - -## Support material-table - -To support material-table visit [SUPPORT](https://www.patreon.com/mbrn) page. - -## Issue Prioritizing - -Issues would be prioritized according reactions count. `is:issue is:open sort:reactions-+1-desc` filter would be use. - -[List issues according to reaction score](https://github.com/mbrn/material-table/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) - -## Prerequisites - -The minimum `React` version material-table supports is `^16.8.5` since material-table `v1.36.1`. This is due to utilising [`react-beautiful-dnd`](https://github.com/atlassian/react-beautiful-dnd) for drag & drop functionality which uses hooks. - -If you use an older version of react we suggest to upgrade your dependencies or use material-table `1.36.0`. - -## Installation - -#### 1.Install package - -To install material-table with `npm`: - - npm install material-table @material-ui/core --save - -To install material-table with `yarn`: - - yarn add material-table @material-ui/core - -#### 2.Add material icons - -There are two ways to use icons in material-table either import the material icons font via html OR import material icons and use the material-table `icons` prop. - -##### HTML - -```html - -``` - -OR - -##### Import Material icons - -Icons can be imported to be used in material-table offering more flexibility for customising the look and feel of material table over using a font library. - -To install @material-ui/icons with `npm`: - - npm install @material-ui/icons --save - -To install @material-ui/icons with `yarn`: - - yarn add @material-ui/icons - -If your environment doesn't support tree-shaking, the **recommended** way to import the icons is the following: - -```jsx -import AddBox from "@material-ui/icons/AddBox"; -import ArrowDownward from "@material-ui/icons/ArrowDownward"; -``` - -If your environment support tree-shaking you can also import the icons this way: - -```jsx -import { AddBox, ArrowDownward } from "@material-ui/icons"; -``` - -Note: Importing named exports in this way will result in the code for _every icon_ being included in your project, so is not recommended unless you configure [tree-shaking](https://webpack.js.org/guides/tree-shaking/). It may also impact Hot Module Reload performance. Source: [@material-ui/icons](https://github.com/mui-org/material-ui/blob/master/packages/material-ui-icons/README.md#imports) - -Example - -```jsx -import { forwardRef } from 'react'; - -import AddBox from '@material-ui/icons/AddBox'; -import ArrowDownward from '@material-ui/icons/ArrowDownward'; -import Check from '@material-ui/icons/Check'; -import ChevronLeft from '@material-ui/icons/ChevronLeft'; -import ChevronRight from '@material-ui/icons/ChevronRight'; -import Clear from '@material-ui/icons/Clear'; -import DeleteOutline from '@material-ui/icons/DeleteOutline'; -import Edit from '@material-ui/icons/Edit'; -import FilterList from '@material-ui/icons/FilterList'; -import FirstPage from '@material-ui/icons/FirstPage'; -import LastPage from '@material-ui/icons/LastPage'; -import Remove from '@material-ui/icons/Remove'; -import SaveAlt from '@material-ui/icons/SaveAlt'; -import Search from '@material-ui/icons/Search'; -import ViewColumn from '@material-ui/icons/ViewColumn'; - -const tableIcons = { - Add: forwardRef((props, ref) => ), - Check: forwardRef((props, ref) => ), - Clear: forwardRef((props, ref) => ), - Delete: forwardRef((props, ref) => ), - DetailPanel: forwardRef((props, ref) => ), - Edit: forwardRef((props, ref) => ), - Export: forwardRef((props, ref) => ), - Filter: forwardRef((props, ref) => ), - FirstPage: forwardRef((props, ref) => ), - LastPage: forwardRef((props, ref) => ), - NextPage: forwardRef((props, ref) => ), - PreviousPage: forwardRef((props, ref) => ), - ResetSearch: forwardRef((props, ref) => ), - Search: forwardRef((props, ref) => ), - SortArrow: forwardRef((props, ref) => ), - ThirdStateCheck: forwardRef((props, ref) => ), - ViewColumn: forwardRef((props, ref) => ) - }; - - -``` - -## Usage - -Here is a basic example of using material-table within a react application. - -```jsx -import React, { Component } from "react"; -import ReactDOM from "react-dom"; -import MaterialTable from "material-table"; - -class App extends Component { - render() { - return ( -
- -
- ); - } -} - -ReactDOM.render(, document.getElementById("react-div")); -``` - -## Contributing - -We'd love to have your helping hand on `material-table`! See [CONTRIBUTING.md](https://github.com/mbrn/material-table/blob/master/.github/CONTRIBUTING.md) for more information on what we're looking for and how to get started. - -If you have any sort of doubt, idea or just want to talk about the project, feel free to join [our chat on Gitter](https://gitter.im/material-table/Lobby) :) - -## Contributors - -### Code Contributors - -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. - - -### Financial Contributors - -Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/material-table/contribute)] - -#### Individuals - - - -#### Organizations - -Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/material-table/contribute)] - - - - - - - - - - - - -## License - -This project is licensed under the terms of the [MIT license](/LICENSE). +

+ material-table

+

+ +

material-table

+ +
+ +A simple and powerful Datatable for React based on [Material-UI Table](https://material-ui.com/api/table/) with some additional features. + +[![Build Status](https://travis-ci.org/mbrn/material-table.svg?branch=master)](https://travis-ci.org/mbrn/material-table) +[![Financial Contributors on Open Collective](https://opencollective.com/material-table/all/badge.svg?label=financial+contributors)](https://opencollective.com/material-table) [![npm package](https://img.shields.io/npm/v/material-table/latest.svg)](https://www.npmjs.com/package/material-table) +[![NPM Downloads](https://img.shields.io/npm/dm/material-table.svg?style=flat)](https://npmcharts.com/compare/material-table?minimal=true) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/mbrn/material-table.svg)](http://isitmaintained.com/project/mbrn/material-table "Average time to resolve an issue") +[![xscode](https://img.shields.io/badge/Available%20on-xs%3Acode-blue?style=?style=plastic&logo=appveyor&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAZQTFRF////////VXz1bAAAAAJ0Uk5T/wDltzBKAAAAlUlEQVR42uzXSwqAMAwE0Mn9L+3Ggtgkk35QwcnSJo9S+yGwM9DCooCbgn4YrJ4CIPUcQF7/XSBbx2TEz4sAZ2q1RAECBAiYBlCtvwN+KiYAlG7UDGj59MViT9hOwEqAhYCtAsUZvL6I6W8c2wcbd+LIWSCHSTeSAAECngN4xxIDSK9f4B9t377Wd7H5Nt7/Xz8eAgwAvesLRjYYPuUAAAAASUVORK5CYII=)](https://xscode.com/mbrn/material-table) +[![Follow on Twitter](https://img.shields.io/twitter/follow/baranmehmet.svg?label=follow+baranmehmet)](https://twitter.com/baranmehmet) +[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/material-table/Lobby) + +
+ +## Roadmap + +- [More on our roadmap can be found here](https://github.com/mbrn/material-table/blob/master/.github/ROADMAP.md) + +## Key features + +- [Actions](https://material-table.com/#/docs/features/actions) +- [Component overriding](https://material-table.com/#/docs/features/component-overriding) +- [Custom column rendering](https://material-table.com/#/docs/features/custom-column-rendering) +- [Detail Panel](https://material-table.com/#/docs/features/detail-panel) +- [Editable](https://material-table.com/#/docs/features/editable) +- [Export](https://material-table.com/#/docs/features/export) +- [Filtering](https://material-table.com/#/docs/features/filtering) +- [Grouping](https://material-table.com/#/docs/features/grouping) +- [Localization](https://material-table.com/#/docs/features/localization) +- [Remote Data](https://material-table.com/#/docs/features/remote-data) +- [Search](https://material-table.com/#/docs/features/search) +- [Selection](https://material-table.com/#/docs/features/selection) +- [Sorting](https://material-table.com/#/docs/features/sorting) +- [Styling](https://material-table.com/#/docs/features/styling) +- [Tree Data](https://material-table.com/#/docs/features/tree-data) +- and more + +## Demo and documentation + +You can access all code examples and documentation on our site [**material-table.com**](https://material-table.com/). + +## Support material-table + +To support material-table visit [SUPPORT](https://www.patreon.com/mbrn) page. + +## Issue Prioritizing + +Issues would be prioritized according reactions count. `is:issue is:open sort:reactions-+1-desc` filter would be use. + +[List issues according to reaction score](https://github.com/mbrn/material-table/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) + +## Prerequisites + +The minimum `React` version material-table supports is `^16.8.5` since material-table `v1.36.1`. This is due to utilising [`react-beautiful-dnd`](https://github.com/atlassian/react-beautiful-dnd) for drag & drop functionality which uses hooks. + +If you use an older version of react we suggest to upgrade your dependencies or use material-table `1.36.0`. + +## Installation + +#### 1.Install package + +To install material-table with `npm`: + + npm install material-table @material-ui/core --save + +To install material-table with `yarn`: + + yarn add material-table @material-ui/core + +#### 2.Add material icons + +There are two ways to use icons in material-table either import the material icons font via html OR import material icons and use the material-table `icons` prop. + +##### HTML + +```html + +``` + +OR + +##### Import Material icons + +Icons can be imported to be used in material-table offering more flexibility for customising the look and feel of material table over using a font library. + +To install @material-ui/icons with `npm`: + + npm install @material-ui/icons --save + +To install @material-ui/icons with `yarn`: + + yarn add @material-ui/icons + +If your environment doesn't support tree-shaking, the **recommended** way to import the icons is the following: + +```jsx +import AddBox from "@material-ui/icons/AddBox"; +import ArrowDownward from "@material-ui/icons/ArrowDownward"; +``` + +If your environment support tree-shaking you can also import the icons this way: + +```jsx +import { AddBox, ArrowDownward } from "@material-ui/icons"; +``` + +Note: Importing named exports in this way will result in the code for _every icon_ being included in your project, so is not recommended unless you configure [tree-shaking](https://webpack.js.org/guides/tree-shaking/). It may also impact Hot Module Reload performance. Source: [@material-ui/icons](https://github.com/mui-org/material-ui/blob/master/packages/material-ui-icons/README.md#imports) + +Example + +```jsx +import { forwardRef } from 'react'; + +import AddBox from '@material-ui/icons/AddBox'; +import ArrowDownward from '@material-ui/icons/ArrowDownward'; +import Check from '@material-ui/icons/Check'; +import ChevronLeft from '@material-ui/icons/ChevronLeft'; +import ChevronRight from '@material-ui/icons/ChevronRight'; +import Clear from '@material-ui/icons/Clear'; +import DeleteOutline from '@material-ui/icons/DeleteOutline'; +import Edit from '@material-ui/icons/Edit'; +import FilterList from '@material-ui/icons/FilterList'; +import FirstPage from '@material-ui/icons/FirstPage'; +import LastPage from '@material-ui/icons/LastPage'; +import Remove from '@material-ui/icons/Remove'; +import SaveAlt from '@material-ui/icons/SaveAlt'; +import Search from '@material-ui/icons/Search'; +import ViewColumn from '@material-ui/icons/ViewColumn'; + +const tableIcons = { + Add: forwardRef((props, ref) => ), + Check: forwardRef((props, ref) => ), + Clear: forwardRef((props, ref) => ), + Delete: forwardRef((props, ref) => ), + DetailPanel: forwardRef((props, ref) => ), + Edit: forwardRef((props, ref) => ), + Export: forwardRef((props, ref) => ), + Filter: forwardRef((props, ref) => ), + FirstPage: forwardRef((props, ref) => ), + LastPage: forwardRef((props, ref) => ), + NextPage: forwardRef((props, ref) => ), + PreviousPage: forwardRef((props, ref) => ), + ResetSearch: forwardRef((props, ref) => ), + Search: forwardRef((props, ref) => ), + SortArrow: forwardRef((props, ref) => ), + ThirdStateCheck: forwardRef((props, ref) => ), + ViewColumn: forwardRef((props, ref) => ) + }; + + +``` + +## Usage + +Here is a basic example of using material-table within a react application. + +```jsx +import React, { Component } from "react"; +import ReactDOM from "react-dom"; +import MaterialTable from "material-table"; + +class App extends Component { + render() { + return ( +
+ +
+ ); + } +} + +ReactDOM.render(, document.getElementById("react-div")); +``` + +## Contributing + +We'd love to have your helping hand on `material-table`! See [CONTRIBUTING.md](https://github.com/mbrn/material-table/blob/master/.github/CONTRIBUTING.md) for more information on what we're looking for and how to get started. + +If you have any sort of doubt, idea or just want to talk about the project, feel free to join [our chat on Gitter](https://gitter.im/material-table/Lobby) :) + +## Contributors + +### Code Contributors + +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. + + +### Financial Contributors + +Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/material-table/contribute)] + +#### Individuals + + + +#### Organizations + +Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/material-table/contribute)] + + + + + + + + + + + + +## License + +This project is licensed under the terms of the [MIT license](/LICENSE). diff --git a/configs/.babelrc b/configs/.babelrc index 4a6fc3bc9..3b9ffbc88 100644 --- a/configs/.babelrc +++ b/configs/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["@babel/preset-env", "@babel/react"], + "presets": ["@babel/preset-env", "@babel/react"], "plugins": [ "@babel/plugin-transform-runtime", "@babel/plugin-proposal-class-properties", diff --git a/configs/.eslintrc b/configs/.eslintrc index 00f877dde..3c81312d9 100644 --- a/configs/.eslintrc +++ b/configs/.eslintrc @@ -1,13 +1,10 @@ { - "extends": [ - "standard", - "eslint:recommended", - "plugin:react/recommended" - ], + "extends": ["standard", "eslint:recommended", "plugin:react/recommended"], "rules": { "one-var": "off", - "semi": ["error", "always", { "omitLastInOneLineBlock": true }], - "space-before-function-paren": ["error", "never"] + "semi": ["error", "always", { + "omitLastInOneLineBlock": true + }] }, "parser": "babel-eslint" } \ No newline at end of file diff --git a/demo/demo.js b/demo/demo.js index d6d53e46d..ed026f3b8 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,32 +1,32 @@ -import { Grid, MuiThemeProvider, Button } from '@material-ui/core'; -import { createMuiTheme } from '@material-ui/core/styles'; -import React, { Component } from 'react'; -import ReactDOM from 'react-dom'; -import MaterialTable from '../src'; +import { Grid, MuiThemeProvider, Button } from "@material-ui/core"; +import { createMuiTheme } from "@material-ui/core/styles"; +import React, { Component } from "react"; +import ReactDOM from "react-dom"; +import MaterialTable from "../src"; import Typography from "@material-ui/core/Typography"; -let direction = 'ltr'; +let direction = "ltr"; // direction = 'rtl'; const theme = createMuiTheme({ direction: direction, palette: { - type: 'light' - } + type: "light", + }, }); const bigData = []; for (let i = 0; i < 1; i++) { const d = { id: i + 1, - name: 'Name' + i, - surname: 'Surname' + Math.round(i / 10), + name: "Name" + i, + surname: "Surname" + Math.round(i / 10), isMarried: i % 2 ? true : false, birthDate: new Date(1987, 1, 1), birthCity: 0, - sex: i % 2 ? 'Male' : 'Female', - type: 'adult', + sex: i % 2 ? "Male" : "Female", + type: "adult", insertDateTime: new Date(2018, 1, 1, 12, 23, 44), - time: new Date(1900, 1, 1, 14, 23, 35) + time: new Date(1900, 1, 1, 14, 23, 35), }; bigData.push(d); } @@ -37,65 +37,451 @@ class App extends Component { colRenderCount = 0; state = { - text: 'text', + text: "text", selecteds: 0, data: [ - { id: 1, name: 'A1', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 0, sex: 'Male', type: 'adult', insertDateTime: '1994-11-23T08:15:30-05:00', time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 2, name: 'A2', surname: 'B', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'adult', insertDateTime: '1994-11-05T13:15:30Z', time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 3, name: 'A3', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 4, name: 'A4', surname: 'Dede Dede Dede Dede Dede Dede Dede Dede', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 3 }, - { id: 5, name: 'A5', surname: 'C', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 6, name: 'A6', surname: 'C', isMarried: true, birthDate: new Date(1989, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 5 }, - { id: 11, name: 'A1', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 0, sex: 'Male', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 21, name: 'A2', surname: 'B', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 31, name: 'A3', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 41, name: 'A4', surname: 'Dede', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 3 }, - { id: 51, name: 'A5', surname: 'C', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 61, name: 'A6', surname: 'C', isMarried: true, birthDate: new Date(1989, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 5 }, - { id: 12, name: 'A1', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 0, sex: 'Male', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 22, name: 'A2', surname: 'B', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 32, name: 'A3', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 42, name: 'A4', surname: 'Dede', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 3 }, - { id: 52, name: 'A5', surname: 'C', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 62, name: 'A6', surname: 'C', isMarried: true, birthDate: new Date(1989, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 5 }, - { id: 13, name: 'A1', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 0, sex: 'Male', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 23, name: 'A2', surname: 'B', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 33, name: 'A3', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 43, name: 'A4', surname: 'Dede', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 3 }, - { id: 53, name: 'A5', surname: 'C', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 63, name: 'A6', surname: 'C', isMarried: true, birthDate: new Date(1989, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 5 }, - { id: 14, name: 'A1', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 0, sex: 'Male', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 24, name: 'A2', surname: 'B', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'adult', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 34, name: 'A3', surname: 'B', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 1 }, - { id: 44, name: 'A4', surname: 'Dede', isMarried: true, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 3 }, - { id: 54, name: 'A5', surname: 'C', isMarried: false, birthDate: new Date(1987, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35) }, - { id: 64, name: 'A6', surname: 'C', isMarried: true, birthDate: new Date(1989, 1, 1), birthCity: 34, sex: 'Female', type: 'child', insertDateTime: new Date(2018, 1, 1, 12, 23, 44), time: new Date(1900, 1, 1, 14, 23, 35), parentId: 5 } + { + id: 1, + name: "A1", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 0, + sex: "Male", + type: "adult", + insertDateTime: "1994-11-23T08:15:30-05:00", + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 2, + name: "A2", + surname: "B", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "adult", + insertDateTime: "1994-11-05T13:15:30Z", + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 3, + name: "A3", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 4, + name: "A4", + surname: "Dede Dede Dede Dede Dede Dede Dede Dede", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 3, + }, + { + id: 5, + name: "A5", + surname: "C", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 6, + name: "A6", + surname: "C", + isMarried: true, + birthDate: new Date(1989, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 5, + }, + { + id: 11, + name: "A1", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 0, + sex: "Male", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 21, + name: "A2", + surname: "B", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 31, + name: "A3", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 41, + name: "A4", + surname: "Dede", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 3, + }, + { + id: 51, + name: "A5", + surname: "C", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 61, + name: "A6", + surname: "C", + isMarried: true, + birthDate: new Date(1989, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 5, + }, + { + id: 12, + name: "A1", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 0, + sex: "Male", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 22, + name: "A2", + surname: "B", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 32, + name: "A3", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 42, + name: "A4", + surname: "Dede", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 3, + }, + { + id: 52, + name: "A5", + surname: "C", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 62, + name: "A6", + surname: "C", + isMarried: true, + birthDate: new Date(1989, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 5, + }, + { + id: 13, + name: "A1", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 0, + sex: "Male", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 23, + name: "A2", + surname: "B", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 33, + name: "A3", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 43, + name: "A4", + surname: "Dede", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 3, + }, + { + id: 53, + name: "A5", + surname: "C", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 63, + name: "A6", + surname: "C", + isMarried: true, + birthDate: new Date(1989, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 5, + }, + { + id: 14, + name: "A1", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 0, + sex: "Male", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 24, + name: "A2", + surname: "B", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "adult", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 34, + name: "A3", + surname: "B", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 1, + }, + { + id: 44, + name: "A4", + surname: "Dede", + isMarried: true, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 3, + }, + { + id: 54, + name: "A5", + surname: "C", + isMarried: false, + birthDate: new Date(1987, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + }, + { + id: 64, + name: "A6", + surname: "C", + isMarried: true, + birthDate: new Date(1989, 1, 1), + birthCity: 34, + sex: "Female", + type: "child", + insertDateTime: new Date(2018, 1, 1, 12, 23, 44), + time: new Date(1900, 1, 1, 14, 23, 35), + parentId: 5, + }, ], columns: [ - { title: 'Adı', field: 'name', filterPlaceholder: 'Adı filter', tooltip: 'This is tooltip text', editPlaceholder: 'This is placeholder' }, - { width: 200, title: 'Soyadı', field: 'surname', initialEditValue: 'test', tooltip: 'This is tooltip text' }, - { title: 'Evli', field: 'isMarried' }, - { title: 'Cinsiyet', field: 'sex', disableClick: true, editable: 'onAdd' }, - { title: 'Tipi', field: 'type', removable: false, editable: 'never' }, - { title: 'Doğum Yılı', field: 'birthDate', type: 'date' }, - { title: 'Doğum Yeri', field: 'birthCity', lookup: { 34: 'İstanbul', 0: 'Şanlıurfa' } }, - { title: 'Kayıt Tarihi', field: 'insertDateTime', type: 'datetime' }, - { title: 'Zaman', field: 'time', type: 'time' }, - { title: 'Adı', field: 'name', filterPlaceholder: 'Adı filter', tooltip: 'This is tooltip text' }, + { + title: "Adı", + field: "name", + filterPlaceholder: "Adı filter", + tooltip: "This is tooltip text", + editPlaceholder: "This is placeholder", + }, + { + width: 200, + title: "Soyadı", + field: "surname", + initialEditValue: "test", + tooltip: "This is tooltip text", + }, + { title: "Evli", field: "isMarried" }, + { + title: "Cinsiyet", + field: "sex", + disableClick: true, + editable: "onAdd", + }, + { title: "Tipi", field: "type", removable: false, editable: "never" }, + { title: "Doğum Yılı", field: "birthDate", type: "date" }, + { + title: "Doğum Yeri", + field: "birthCity", + lookup: { 34: "İstanbul", 0: "Şanlıurfa" }, + }, + { title: "Kayıt Tarihi", field: "insertDateTime", type: "datetime" }, + { title: "Zaman", field: "time", type: "time" }, + { + title: "Adı", + field: "name", + filterPlaceholder: "Adı filter", + tooltip: "This is tooltip text", + }, ], remoteColumns: [ - { title: 'Avatar', field: 'avatar', render: rowData => , tooltip: 'delakjdslkjdaskljklsdaj' }, - { title: 'Id', field: 'id' }, - { title: 'First Name', field: 'first_name', defaultFilter: 'De' }, - { title: 'Last Name', field: 'last_name' }, - ] - } + { + title: "Avatar", + field: "avatar", + render: (rowData) => ( + + ), + tooltip: "delakjdslkjdaskljklsdaj", + }, + { title: "Id", field: "id" }, + { title: "First Name", field: "first_name", defaultFilter: "De" }, + { title: "Last Name", field: "last_name" }, + ], + }; render() { return ( <> -
+
{this.state.selectedRows && this.state.selectedRows.length} @@ -104,21 +490,21 @@ class App extends Component { columns={this.state.columns} data={this.state.data} title="Demo Title" - onFilterChange={(appliedFilter)=>{ - console.log("selected Filters : " ,appliedFilter); + onFilterChange={(appliedFilter) => { + console.log("selected Filters : ", appliedFilter); }} options={{ selection: true, - selectionProps: rowData => { - rowData.tableData.disabled = rowData.name === 'A1'; - + selectionProps: (rowData) => { + rowData.tableData.disabled = rowData.name === "A1"; + return { - disabled: rowData.name === 'A1' - } - } + disabled: rowData.name === "A1", + }; + }, }} editable={{ - onRowAdd: newData => + onRowAdd: (newData) => new Promise((resolve, reject) => { setTimeout(() => { { @@ -141,7 +527,7 @@ class App extends Component { resolve(); }, 1000); }), - onRowDelete: oldData => + onRowDelete: (oldData) => new Promise((resolve, reject) => { setTimeout(() => { { @@ -152,76 +538,103 @@ class App extends Component { } resolve(); }, 1000); - }) + }), }} localization={{ body: { - emptyDataSourceMessage: 'No records to display', + emptyDataSourceMessage: "No records to display", filterRow: { - filterTooltip: 'Filter', - filterPlaceHolder: "Filtaaer" - } - } + filterTooltip: "Filter", + filterPlaceHolder: "Filtaaer", + }, + }, }} onSearchChange={(e) => console.log("search changed: " + e)} - onColumnDragged={(oldPos, newPos) => console.log("Dropped column from " + oldPos + " to position " + newPos)} - // parentChildData={(row, rows) => rows.find(a => a.id === row.parentId)} + onColumnDragged={(oldPos, newPos) => + console.log( + "Dropped column from " + oldPos + " to position " + newPos + ) + } + // parentChildData={(row, rows) => rows.find(a => a.id === row.parentId)} /> {this.state.text} - Remote Data Preview + + Remote Data Preview + } columns={[ { - title: 'Avatar', - field: 'avatar', - render: rowData => ( + title: "Avatar", + field: "avatar", + render: (rowData) => ( ), }, - { title: 'Id', field: 'id', filterPlaceholder: 'placeholder', + { + title: "Id", + field: "id", filterOnItemSelect: true, - lookup: {1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12'}}, - { title: 'First Name', field: 'first_name' }, - { title: 'Last Name', field: 'last_name' }, + filterPlaceholder: "placeholder", + lookup: { + 1: "1", + 2: "2", + 3: "3", + 4: "4", + 5: "5", + 6: "6", + 7: "7", + 8: "8", + 9: "9", + 10: "10", + 11: "11", + 12: "12", + }, + }, + { title: "First Name", field: "first_name" }, + { title: "Last Name", field: "last_name" }, ]} options={{ filtering: true, grouping: true, - groupTitle: group => group.data.length, - searchFieldVariant: 'outlined', + groupTitle: (group) => group.data.length, + searchFieldVariant: "outlined", }} localization={{ toolbar: { searchPlaceholder: "Outlined Search Field", - } + }, }} - data={query => new Promise((resolve, reject) => { - let url = 'https://reqres.in/api/users?' - url += 'per_page=' + query.pageSize - url += '&page=' + (query.page + 1) - console.log(query); - fetch(url) - .then(response => response.json()) - .then(result => { - resolve({ - data: result.data, - page: result.page - 1, - totalCount: result.total, - }) - }) - })} + data={(query) => + new Promise((resolve, reject) => { + let url = "https://reqres.in/api/users?"; + url += "per_page=" + query.pageSize; + url += "&page=" + (query.page + 1); + console.log(query); + fetch(url) + .then((response) => response.json()) + .then((result) => { + resolve({ + data: result.data, + page: result.page - 1, + totalCount: result.total, + }); + }); + }) + } /> -
@@ -229,9 +642,6 @@ class App extends Component { } } -ReactDOM.render( - , - document.getElementById('app') -); +ReactDOM.render(, document.getElementById("app")); module.hot.accept(); diff --git a/demo/index.html b/demo/index.html index c2b6f3601..b73401a27 100644 --- a/demo/index.html +++ b/demo/index.html @@ -2,11 +2,17 @@ The Minimal React Webpack Babel Setup - - + +
- \ No newline at end of file + diff --git a/demo/webpack.config.js b/demo/webpack.config.js index a7ebe6997..716d01ead 100644 --- a/demo/webpack.config.js +++ b/demo/webpack.config.js @@ -1,30 +1,28 @@ -const webpack = require('webpack'); +const webpack = require("webpack"); module.exports = { - entry: ['babel-polyfill', './demo/demo.js'], + entry: ["babel-polyfill", "./demo/demo.js"], module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, - use: ['babel-loader'] - } - ] + use: ["babel-loader"], + }, + ], }, resolve: { - extensions: ['*', '.js', '.jsx'] + extensions: ["*", ".js", ".jsx"], }, output: { - path: __dirname + '/dist', - publicPath: '/', - filename: 'bundle.js' + path: __dirname + "/dist", + publicPath: "/", + filename: "bundle.js", }, - plugins: [ - new webpack.HotModuleReplacementPlugin() - ], + plugins: [new webpack.HotModuleReplacementPlugin()], devServer: { - contentBase: './demo', + contentBase: "./demo", hot: true, - disableHostCheck: true - } + disableHostCheck: true, + }, }; diff --git a/package.json b/package.json index 3c39ec0b4..8671d63b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "material-table", - "version": "1.62.0", + "version": "1.63.1", "description": "Datatable for React based on https://material-ui.com/api/table/ with additional features", "main": "dist/index.js", "types": "types/index.d.ts", @@ -17,11 +17,12 @@ "lint": "npm run eslint && npm run tsc", "eslint": "eslint src/** -c ./configs/.eslintrc", "tsc": "tsc --noEmit --lib es6,dom --skipLibCheck types/index.d.ts", - "lint:fix": "eslint src/** --fix" + "lint:fix": "eslint src/** --fix", + "prettify": "prettier --write **/*.js" }, "husky": { "hooks": { - "pre-commit": "npm run lint" + "pre-commit": "npm run lint && pretty-quick --staged" } }, "repository": { @@ -63,6 +64,8 @@ "eslint-plugin-react": "7.11.1", "eslint-plugin-standard": "4.0.0", "husky": "^1.2.0", + "prettier": "^2.0.5", + "pretty-quick": "^2.0.1", "react": "^16.8.6", "react-dom": "^16.8.6", "react-hot-loader": "^4.3.12", @@ -79,6 +82,8 @@ "debounce": "^1.2.0", "fast-deep-equal": "2.0.1", "filefy": "0.1.10", + "jspdf": "1.5.3", + "jspdf-autotable": "3.5.3", "prop-types": "^15.6.2", "react-beautiful-dnd": "^13.0.0", "react-double-scrollbar": "0.0.15" diff --git a/src/components/index.js b/src/components/index.js index be3d83803..6ade5fe5b 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,17 +1,17 @@ -import MTableAction from './m-table-action'; -import MTableActions from './m-table-actions'; -import MTableBody from './m-table-body'; -import MTableBodyRow from './m-table-body-row'; -import MTableGroupbar from './m-table-groupbar'; -import MTableGroupRow from './m-table-group-row'; -import MTableCell from './m-table-cell'; -import MTableEditRow from './m-table-edit-row'; -import MTableEditField from './m-table-edit-field'; -import MTableFilterRow from './m-table-filter-row'; -import MTableHeader from './m-table-header'; -import MTablePagination from './m-table-pagination'; -import MTableSteppedPagination from './m-table-stepped-pagination'; -import MTableToolbar from './m-table-toolbar'; +import MTableAction from "./m-table-action"; +import MTableActions from "./m-table-actions"; +import MTableBody from "./m-table-body"; +import MTableBodyRow from "./m-table-body-row"; +import MTableGroupbar from "./m-table-groupbar"; +import MTableGroupRow from "./m-table-group-row"; +import MTableCell from "./m-table-cell"; +import MTableEditRow from "./m-table-edit-row"; +import MTableEditField from "./m-table-edit-field"; +import MTableFilterRow from "./m-table-filter-row"; +import MTableHeader from "./m-table-header"; +import MTablePagination from "./m-table-pagination"; +import MTableSteppedPagination from "./m-table-stepped-pagination"; +import MTableToolbar from "./m-table-toolbar"; export { MTableAction, @@ -28,4 +28,4 @@ export { MTablePagination, MTableSteppedPagination, MTableToolbar, -}; \ No newline at end of file +}; diff --git a/src/components/m-table-action.js b/src/components/m-table-action.js index 6ad32808f..975b2b29e 100644 --- a/src/components/m-table-action.js +++ b/src/components/m-table-action.js @@ -1,16 +1,16 @@ /* eslint-disable no-unused-vars */ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import Icon from '@material-ui/core/Icon'; -import IconButton from '@material-ui/core/IconButton'; -import Tooltip from '@material-ui/core/Tooltip'; +import * as React from "react"; +import PropTypes from "prop-types"; +import Icon from "@material-ui/core/Icon"; +import IconButton from "@material-ui/core/IconButton"; +import Tooltip from "@material-ui/core/Tooltip"; /* eslint-enable no-unused-vars */ class MTableAction extends React.Component { render() { let action = this.props.action; - - if (typeof action === 'function') { + + if (typeof action === "function") { action = action(this.props.data); if (!action) { return null; @@ -23,45 +23,50 @@ class MTableAction extends React.Component { return null; } } - + if (action.hidden) { return null; } const disabled = action.disabled || this.props.disabled; - const handleOnClick = event => { + const handleOnClick = (event) => { if (action.onClick) { action.onClick(event, this.props.data); event.stopPropagation(); } }; - const icon = typeof action.icon === "string" ? ( + const icon = + typeof action.icon === "string" ? ( {action.icon} - ) : typeof action.icon === "function" ? ( + ) : typeof action.icon === "function" ? ( action.icon({ ...action.iconProps, disabled: disabled }) - ) : ( + ) : ( - ); + ); const button = ( - - {icon} - + + {icon} + ); if (action.tooltip) { // fix for issue #1049 // https://github.com/mbrn/material-table/issues/1049 - return disabled - ? {button} - : {button}; + return disabled ? ( + + {button} + + ) : ( + {button} + ); } else { return button; } @@ -70,14 +75,17 @@ class MTableAction extends React.Component { MTableAction.defaultProps = { action: {}, - data: {} + data: {}, }; MTableAction.propTypes = { action: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, - data: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]), + data: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.arrayOf(PropTypes.object), + ]), disabled: PropTypes.bool, - size: PropTypes.string + size: PropTypes.string, }; export default MTableAction; diff --git a/src/components/m-table-actions.js b/src/components/m-table-actions.js index d9e075804..a14ff3af8 100644 --- a/src/components/m-table-actions.js +++ b/src/components/m-table-actions.js @@ -1,13 +1,20 @@ /* eslint-disable no-unused-vars */ -import * as React from 'react'; -import PropTypes from 'prop-types'; +import * as React from "react"; +import PropTypes from "prop-types"; /* eslint-enable no-unused-vars */ class MTableActions extends React.Component { - render() { if (this.props.actions) { - return this.props.actions.map((action, index) => ); + return this.props.actions.map((action, index) => ( + + )); } return null; @@ -16,13 +23,16 @@ class MTableActions extends React.Component { MTableActions.defaultProps = { actions: [], - data: {} + data: {}, }; MTableActions.propTypes = { components: PropTypes.object.isRequired, actions: PropTypes.array.isRequired, - data: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]), + data: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.arrayOf(PropTypes.object), + ]), disabled: PropTypes.bool, size: PropTypes.string, }; diff --git a/src/components/m-table-body-row.js b/src/components/m-table-body-row.js index f78051d82..cf9723a7f 100644 --- a/src/components/m-table-body-row.js +++ b/src/components/m-table-body-row.js @@ -1,20 +1,23 @@ /* eslint-disable no-unused-vars */ -import Checkbox from '@material-ui/core/Checkbox'; -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import IconButton from '@material-ui/core/IconButton'; -import Icon from '@material-ui/core/Icon'; -import Tooltip from '@material-ui/core/Tooltip'; -import PropTypes from 'prop-types'; -import * as React from 'react'; -import * as CommonValues from '../utils/common-values'; +import Checkbox from "@material-ui/core/Checkbox"; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import IconButton from "@material-ui/core/IconButton"; +import Icon from "@material-ui/core/Icon"; +import Tooltip from "@material-ui/core/Tooltip"; +import PropTypes from "prop-types"; +import * as React from "react"; +import * as CommonValues from "../utils/common-values"; /* eslint-enable no-unused-vars */ - export default class MTableBodyRow extends React.Component { renderColumns() { const size = CommonValues.elementSize(this.props); - const mapArr = this.props.columns.filter(columnDef => !columnDef.hidden && !(columnDef.tableData.groupOrder > -1)) + const mapArr = this.props.columns + .filter( + (columnDef) => + !columnDef.hidden && !(columnDef.tableData.groupOrder > -1) + ) .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) .map((columnDef, index) => { const value = this.props.getFieldValue(this.props.data, columnDef); @@ -22,9 +25,17 @@ export default class MTableBodyRow extends React.Component { ); @@ -37,37 +48,66 @@ export default class MTableBodyRow extends React.Component { const actions = CommonValues.rowActions(this.props); const width = actions.length * CommonValues.baseIconSize(this.props); return ( - -
- + +
+
); } renderSelectionColumn() { let checkboxProps = this.props.options.selectionProps || {}; - if (typeof checkboxProps === 'function') { + if (typeof checkboxProps === "function") { checkboxProps = checkboxProps(this.props.data); } const size = CommonValues.elementSize(this.props); - const selectionWidth = CommonValues.selectionMaxWidth(this.props, this.props.treeDataMaxLevel); + const selectionWidth = CommonValues.selectionMaxWidth( + this.props, + this.props.treeDataMaxLevel + ); - const styles = size === 'medium' ? { - marginLeft: this.props.level * 9 - } : { - padding: "4px", - marginLeft: 5 + this.props.level * 9 - }; + const styles = + size === "medium" + ? { + marginLeft: this.props.level * 9, + } + : { + padding: "4px", + marginLeft: 5 + this.props.level * 9, + }; return ( - + e.stopPropagation()} value={this.props.data.tableData.id.toString()} - onChange={(event) => this.props.onRowSelected(event, this.props.path, this.props.data)} + onChange={(event) => + this.props.onRowSelected(event, this.props.path, this.props.data) + } style={styles} {...checkboxProps} /> @@ -75,22 +115,44 @@ export default class MTableBodyRow extends React.Component { ); } - rotateIconStyle = isOpen => ({ - transform: isOpen ? 'rotate(90deg)' : 'none' + rotateIconStyle = (isOpen) => ({ + transform: isOpen ? "rotate(90deg)" : "none", }); renderDetailPanelColumn() { const size = CommonValues.elementSize(this.props); - const CustomIcon = ({ icon, iconProps, }) => typeof icon === "string" ? {icon} : React.createElement(icon, { ...iconProps }); + const CustomIcon = ({ icon, iconProps }) => + typeof icon === "string" ? ( + {icon} + ) : ( + React.createElement(icon, { ...iconProps }) + ); - if (typeof this.props.detailPanel == 'function') { + if (typeof this.props.detailPanel == "function") { return ( - + { - this.props.onToggleDetailPanel(this.props.path, this.props.detailPanel); + this.props.onToggleDetailPanel( + this.props.path, + this.props.detailPanel + ); event.stopPropagation(); }} > @@ -98,33 +160,43 @@ export default class MTableBodyRow extends React.Component { ); - } - else { + } else { return ( -
+
{this.props.detailPanel.map((panel, index) => { - if (typeof panel === "function") { panel = panel(this.props.data); } - const isOpen = (this.props.data.tableData.showDetailPanel || '').toString() === panel.render.toString(); + const isOpen = + (this.props.data.tableData.showDetailPanel || "").toString() === + panel.render.toString(); let iconButton = ; let animation = true; if (isOpen) { if (panel.openIcon) { - iconButton = ; + iconButton = ( + + ); animation = false; - } - else if (panel.icon) { + } else if (panel.icon) { iconButton = ( ); } - } - else if (panel.icon) { + } else if (panel.icon) { iconButton = ( ); @@ -135,18 +207,32 @@ export default class MTableBodyRow extends React.Component { { - this.props.onToggleDetailPanel(this.props.path, panel.render); + this.props.onToggleDetailPanel( + this.props.path, + panel.render + ); event.stopPropagation(); }} > {iconButton} - ); + + ); if (panel.tooltip) { - iconButton = {iconButton}; + iconButton = ( + + {iconButton} + + ); } return iconButton; @@ -159,15 +245,23 @@ export default class MTableBodyRow extends React.Component { renderTreeDataColumn() { const size = CommonValues.elementSize(this.props); - if (this.props.data.tableData.childRows && this.props.data.tableData.childRows.length > 0) { + if ( + this.props.data.tableData.childRows && + this.props.data.tableData.childRows.length > 0 + ) { return ( - + { this.props.onTreeExpandChanged(this.props.path, this.props.data); @@ -178,32 +272,30 @@ export default class MTableBodyRow extends React.Component { ); - } - else { - return(); + } else { + return ; } } getStyle(index, level) { let style = { - transition: 'all ease 300ms', + transition: "all ease 300ms", }; if (typeof this.props.options.rowStyle === "function") { style = { ...style, - ...this.props.options.rowStyle(this.props.data, index, level) + ...this.props.options.rowStyle(this.props.data, index, level), }; - } - else if (this.props.options.rowStyle) { + } else if (this.props.options.rowStyle) { style = { ...style, - ...this.props.options.rowStyle + ...this.props.options.rowStyle, }; } if (this.props.onRowClick) { - style.cursor = 'pointer'; + style.cursor = "pointer"; } if (this.props.hasAnyEditingRow) { @@ -219,7 +311,12 @@ export default class MTableBodyRow extends React.Component { if (this.props.options.selection) { renderColumns.splice(0, 0, this.renderSelectionColumn()); } - if (this.props.actions && this.props.actions.filter(a => a.position === "row" || typeof a === "function").length > 0) { + if ( + this.props.actions && + this.props.actions.filter( + (a) => a.position === "row" || typeof a === "function" + ).length > 0 + ) { if (this.props.options.actionsColumnIndex === -1) { renderColumns.push(this.renderActions()); } else if (this.props.options.actionsColumnIndex >= 0) { @@ -227,13 +324,17 @@ export default class MTableBodyRow extends React.Component { if (this.props.options.selection) { endPos = 1; } - renderColumns.splice(this.props.options.actionsColumnIndex + endPos, 0, this.renderActions()); + renderColumns.splice( + this.props.options.actionsColumnIndex + endPos, + 0, + this.renderActions() + ); } } // Then we add detail panel icon if (this.props.detailPanel) { - if (this.props.options.detailPanelColumnAlignment === 'right') { + if (this.props.options.detailPanelColumnAlignment === "right") { renderColumns.push(this.renderDetailPanelColumn()); } else { renderColumns.splice(0, 0, this.renderDetailPanelColumn()); @@ -246,9 +347,17 @@ export default class MTableBodyRow extends React.Component { } this.props.columns - .filter(columnDef => columnDef.tableData.groupOrder > -1) - .forEach(columnDef => { - renderColumns.splice(0, 0, ); + .filter((columnDef) => columnDef.tableData.groupOrder > -1) + .forEach((columnDef) => { + renderColumns.splice( + 0, + 0, + + ); }); const { @@ -270,7 +379,8 @@ export default class MTableBodyRow extends React.Component { treeDataMaxLevel, localization, actions, - ...rowProps } = this.props; + ...rowProps + } = this.props; return ( <> @@ -280,8 +390,8 @@ export default class MTableBodyRow extends React.Component { hover={onRowClick ? true : false} style={this.getStyle(this.props.index, this.props.level)} onClick={(event) => { - onRowClick && onRowClick(event, this.props.data, - (panelIndex) => { + onRowClick && + onRowClick(event, this.props.data, (panelIndex) => { let panel = detailPanel; if (Array.isArray(panel)) { panel = panel[panelIndex || 0]; @@ -297,21 +407,29 @@ export default class MTableBodyRow extends React.Component { > {renderColumns} - {this.props.data.tableData && this.props.data.tableData.showDetailPanel && - - - {this.props.data.tableData.showDetailPanel(this.props.data)} - - - } - {this.props.data.tableData.childRows && this.props.data.tableData.isTreeExpanded && + {this.props.data.tableData && + this.props.data.tableData.showDetailPanel && ( + + + {this.props.data.tableData.showDetailPanel(this.props.data)} + + + )} + {this.props.data.tableData.childRows && + this.props.data.tableData.isTreeExpanded && this.props.data.tableData.childRows.map((data, index) => { if (data.tableData.editing) { return ( { return !columnDef.hidden })} + columns={this.props.columns.filter((columnDef) => { + return !columnDef.hidden; + })} components={this.props.components} data={data} icons={this.props.icons} @@ -342,8 +460,7 @@ export default class MTableBodyRow extends React.Component { /> ); } - }) - } + })} ); } @@ -354,7 +471,7 @@ MTableBodyRow.defaultProps = { index: 0, data: {}, options: {}, - path: [] + path: [], }; MTableBodyRow.propTypes = { @@ -362,7 +479,10 @@ MTableBodyRow.propTypes = { icons: PropTypes.any.isRequired, index: PropTypes.number.isRequired, data: PropTypes.object.isRequired, - detailPanel: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func]))]), + detailPanel: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func])), + ]), hasAnyEditingRow: PropTypes.bool, options: PropTypes.object.isRequired, onRowSelected: PropTypes.func, diff --git a/src/components/m-table-body.js b/src/components/m-table-body.js index 6434aa13e..5b7a0c523 100644 --- a/src/components/m-table-body.js +++ b/src/components/m-table-body.js @@ -1,21 +1,32 @@ /* eslint-disable no-unused-vars */ -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import PropTypes from 'prop-types'; -import * as React from 'react'; +import TableBody from "@material-ui/core/TableBody"; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import PropTypes from "prop-types"; +import * as React from "react"; /* eslint-enable no-unused-vars */ class MTableBody extends React.Component { renderEmpty(emptyRowCount, renderData) { - const rowHeight = this.props.options.padding === 'default' ? 49 : 36; - const localization = { ...MTableBody.defaultProps.localization, ...this.props.localization }; - if (this.props.options.showEmptyDataSourceMessage && renderData.length === 0) { + const rowHeight = this.props.options.padding === "default" ? 49 : 36; + const localization = { + ...MTableBody.defaultProps.localization, + ...this.props.localization, + }; + if ( + this.props.options.showEmptyDataSourceMessage && + renderData.length === 0 + ) { let addColumn = 0; if (this.props.options.selection) { addColumn++; } - if (this.props.actions && this.props.actions.filter(a => a.position === "row" || typeof a === "function").length > 0) { + if ( + this.props.actions && + this.props.actions.filter( + (a) => a.position === "row" || typeof a === "function" + ).length > 0 + ) { addColumn++; } if (this.props.hasDetailPanel) { @@ -25,8 +36,26 @@ class MTableBody extends React.Component { addColumn++; } return ( - - columnDef.hidden ? currentVal : currentVal + 1, addColumn)} key="empty-"> + + + columnDef.hidden ? currentVal : currentVal + 1, + addColumn + )} + key="empty-" + > {localization.emptyDataSourceMessage} @@ -34,8 +63,12 @@ class MTableBody extends React.Component { } else if (this.props.options.emptyRowsWhenPaging) { return ( - {[...Array(emptyRowCount)].map((r, index) => )} - {emptyRowCount > 0 && } + {[...Array(emptyRowCount)].map((r, index) => ( + + ))} + {emptyRowCount > 0 && ( + + )} ); } @@ -46,11 +79,18 @@ class MTableBody extends React.Component { if (data.tableData.editing) { return ( { return !columnDef.hidden })} + columns={this.props.columns.filter((columnDef) => { + return !columnDef.hidden; + })} components={this.props.components} data={data} icons={this.props.icons} - localization={{ ...MTableBody.defaultProps.localization.editRow, ...this.props.localization.editRow, dateTimePickerLocalization: this.props.localization.dateTimePickerLocalization }} + localization={{ + ...MTableBody.defaultProps.localization.editRow, + ...this.props.localization.editRow, + dateTimePickerLocalization: this.props.localization + .dateTimePickerLocalization, + }} key={index} mode={data.tableData.editing} options={this.props.options} @@ -61,8 +101,7 @@ class MTableBody extends React.Component { getFieldValue={this.props.getFieldValue} /> ); - } - else { + } else { return ( ( )); } @@ -125,8 +170,10 @@ class MTableBody extends React.Component { render() { let renderData = this.props.renderData; const groups = this.props.columns - .filter(col => col.tableData.groupOrder > -1) - .sort((col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder); + .filter((col) => col.tableData.groupOrder > -1) + .sort( + (col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder + ); let emptyRowCount = 0; if (this.props.options.paging) { @@ -135,55 +182,76 @@ class MTableBody extends React.Component { return ( - {this.props.options.filtering && + {this.props.options.filtering && ( !columnDef.hidden)} + columns={this.props.columns.filter( + (columnDef) => !columnDef.hidden + )} icons={this.props.icons} - hasActions={this.props.actions.filter(a => a.position === "row" || typeof a === "function").length > 0} + hasActions={ + this.props.actions.filter( + (a) => a.position === "row" || typeof a === "function" + ).length > 0 + } actionsColumnIndex={this.props.options.actionsColumnIndex} onFilterChanged={this.props.onFilterChanged} selection={this.props.options.selection} - localization={{ ...MTableBody.defaultProps.localization.filterRow, ...this.props.localization.filterRow, dateTimePickerLocalization: this.props.localization.dateTimePickerLocalization }} + localization={{ + ...MTableBody.defaultProps.localization.filterRow, + ...this.props.localization.filterRow, + dateTimePickerLocalization: this.props.localization + .dateTimePickerLocalization, + }} hasDetailPanel={!!this.props.detailPanel} isTreeData={this.props.isTreeData} filterCellStyle={this.props.options.filterCellStyle} filterRowStyle={this.props.options.filterRowStyle} hideFilterIcons={this.props.options.hideFilterIcons} /> - } + )} - {this.props.showAddRow && this.props.options.addRowPosition === "first" && - { return !columnDef.hidden })} - data={this.props.initialFormData} - components={this.props.components} - icons={this.props.icons} - key="key-add-row" - mode="add" - localization={{ ...MTableBody.defaultProps.localization.editRow, ...this.props.localization.editRow }} - options={this.props.options} - isTreeData={this.props.isTreeData} - detailPanel={this.props.detailPanel} - onEditingCanceled={this.props.onEditingCanceled} - onEditingApproved={this.props.onEditingApproved} - getFieldValue={this.props.getFieldValue} - /> - } + {this.props.showAddRow && + this.props.options.addRowPosition === "first" && ( + { + return !columnDef.hidden; + })} + data={this.props.initialFormData} + components={this.props.components} + icons={this.props.icons} + key="key-add-row" + mode="add" + localization={{ + ...MTableBody.defaultProps.localization.editRow, + ...this.props.localization.editRow, + }} + options={this.props.options} + isTreeData={this.props.isTreeData} + detailPanel={this.props.detailPanel} + onEditingCanceled={this.props.onEditingCanceled} + onEditingApproved={this.props.onEditingApproved} + getFieldValue={this.props.getFieldValue} + /> + )} - {groups.length > 0 ? - this.renderGroupedRows(groups, renderData) : - this.renderUngroupedRows(renderData) - } + {groups.length > 0 + ? this.renderGroupedRows(groups, renderData) + : this.renderUngroupedRows(renderData)} - {this.props.showAddRow && this.props.options.addRowPosition === "last" && + {this.props.showAddRow && this.props.options.addRowPosition === "last" && ( { return !columnDef.hidden })} + columns={this.props.columns.filter((columnDef) => { + return !columnDef.hidden; + })} data={this.props.initialFormData} components={this.props.components} icons={this.props.icons} key="key-add-row" mode="add" - localization={{ ...MTableBody.defaultProps.localization.editRow, ...this.props.localization.editRow }} + localization={{ + ...MTableBody.defaultProps.localization.editRow, + ...this.props.localization.editRow, + }} options={this.props.options} isTreeData={this.props.isTreeData} detailPanel={this.props.detailPanel} @@ -191,7 +259,7 @@ class MTableBody extends React.Component { onEditingApproved={this.props.onEditingApproved} getFieldValue={this.props.getFieldValue} /> - } + )} {this.renderEmpty(emptyRowCount, renderData)} ); @@ -205,10 +273,10 @@ MTableBody.defaultProps = { renderData: [], selection: false, localization: { - emptyDataSourceMessage: 'No records to display', + emptyDataSourceMessage: "No records to display", filterRow: {}, - editRow: {} - } + editRow: {}, + }, }; MTableBody.propTypes = { @@ -216,7 +284,10 @@ MTableBody.propTypes = { components: PropTypes.object.isRequired, columns: PropTypes.array.isRequired, currentPage: PropTypes.number, - detailPanel: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func]))]), + detailPanel: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func])), + ]), getFieldValue: PropTypes.func.isRequired, hasAnyEditingRow: PropTypes.bool, hasDetailPanel: PropTypes.bool.isRequired, diff --git a/src/components/m-table-cell.js b/src/components/m-table-cell.js index 930a749c2..2c409d2de 100644 --- a/src/components/m-table-cell.js +++ b/src/components/m-table-cell.js @@ -1,7 +1,7 @@ /* eslint-disable no-unused-vars */ -import * as React from 'react'; -import TableCell from '@material-ui/core/TableCell'; -import PropTypes from 'prop-types'; +import * as React from "react"; +import TableCell from "@material-ui/core/TableCell"; +import PropTypes from "prop-types"; /* eslint-enable no-unused-vars */ /* eslint-disable no-useless-escape */ @@ -9,57 +9,61 @@ const isoDateRegex = /^\d{4}-(0[1-9]|1[0-2])-([12]\d|0[1-9]|3[01])([T\s](([01]\d /* eslint-enable no-useless-escape */ export default class MTableCell extends React.Component { - getRenderValue() { - const dateLocale = this.props.columnDef.dateSetting && this.props.columnDef.dateSetting.locale + const dateLocale = + this.props.columnDef.dateSetting && + this.props.columnDef.dateSetting.locale ? this.props.columnDef.dateSetting.locale : undefined; - if (this.props.columnDef.emptyValue !== undefined && (this.props.value === undefined || this.props.value === null)) { + if ( + this.props.columnDef.emptyValue !== undefined && + (this.props.value === undefined || this.props.value === null) + ) { return this.getEmptyValue(this.props.columnDef.emptyValue); } if (this.props.columnDef.render) { if (this.props.rowData) { - return this.props.columnDef.render(this.props.rowData, 'row'); - } - else { - return this.props.columnDef.render(this.props.value, 'group'); + return this.props.columnDef.render(this.props.rowData, "row"); + } else { + return this.props.columnDef.render(this.props.value, "group"); } - - } else if (this.props.columnDef.type === 'boolean') { - const style = { textAlign: 'left', verticalAlign: 'middle', width: 48 }; + } else if (this.props.columnDef.type === "boolean") { + const style = { textAlign: "left", verticalAlign: "middle", width: 48 }; if (this.props.value) { return ; } else { return ; } - } else if (this.props.columnDef.type === 'date') { + } else if (this.props.columnDef.type === "date") { if (this.props.value instanceof Date) { return this.props.value.toLocaleDateString(); - } else if(isoDateRegex.exec(this.props.value)) { + } else if (isoDateRegex.exec(this.props.value)) { return new Date(this.props.value).toLocaleDateString(dateLocale); } else { return this.props.value; } - } else if (this.props.columnDef.type === 'time') { + } else if (this.props.columnDef.type === "time") { if (this.props.value instanceof Date) { return this.props.value.toLocaleTimeString(); - } else if(isoDateRegex.exec(this.props.value)) { + } else if (isoDateRegex.exec(this.props.value)) { return new Date(this.props.value).toLocaleTimeString(dateLocale); } else { return this.props.value; } - } else if (this.props.columnDef.type === 'datetime') { + } else if (this.props.columnDef.type === "datetime") { if (this.props.value instanceof Date) { return this.props.value.toLocaleString(); - } else if(isoDateRegex.exec(this.props.value)) { + } else if (isoDateRegex.exec(this.props.value)) { return new Date(this.props.value).toLocaleString(dateLocale); } else { return this.props.value; } - } else if (this.props.columnDef.type === 'currency') { - return this.getCurrencyValue(this.props.columnDef.currencySetting, this.props.value); - } - else if(typeof this.props.value === "boolean") { + } else if (this.props.columnDef.type === "currency") { + return this.getCurrencyValue( + this.props.columnDef.currencySetting, + this.props.value + ); + } else if (typeof this.props.value === "boolean") { // To avoid forwardref boolean children. return this.props.value.toString(); } @@ -68,7 +72,7 @@ export default class MTableCell extends React.Component { } getEmptyValue(emptyValue) { - if (typeof emptyValue === 'function') { + if (typeof emptyValue === "function") { return this.props.columnDef.emptyValue(this.props.rowData); } else { return emptyValue; @@ -77,51 +81,72 @@ export default class MTableCell extends React.Component { getCurrencyValue(currencySetting, value) { if (currencySetting !== undefined) { - return new Intl.NumberFormat((currencySetting.locale !== undefined) ? currencySetting.locale : 'en-US', + return new Intl.NumberFormat( + currencySetting.locale !== undefined ? currencySetting.locale : "en-US", { - style: 'currency', - currency: (currencySetting.currencyCode !== undefined) ? currencySetting.currencyCode : 'USD', - minimumFractionDigits: (currencySetting.minimumFractionDigits !== undefined) ? currencySetting.minimumFractionDigits : 2, - maximumFractionDigits: (currencySetting.maximumFractionDigits !== undefined) ? currencySetting.maximumFractionDigits : 2 - }).format((value !== undefined) ? value : 0); + style: "currency", + currency: + currencySetting.currencyCode !== undefined + ? currencySetting.currencyCode + : "USD", + minimumFractionDigits: + currencySetting.minimumFractionDigits !== undefined + ? currencySetting.minimumFractionDigits + : 2, + maximumFractionDigits: + currencySetting.maximumFractionDigits !== undefined + ? currencySetting.maximumFractionDigits + : 2, + } + ).format(value !== undefined ? value : 0); } else { - return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format((value !== undefined) ? value : 0); + return new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(value !== undefined ? value : 0); } } - handleClickCell = e => { + handleClickCell = (e) => { if (this.props.columnDef.disableClick) { e.stopPropagation(); } - } + }; getStyle = () => { let cellStyle = { - color: 'inherit', + color: "inherit", width: this.props.columnDef.tableData.width, - boxSizing: 'border-box', + boxSizing: "border-box", fontSize: "inherit", fontFamily: "inherit", fontWeight: "inherit", }; - if (typeof this.props.columnDef.cellStyle === 'function') { - cellStyle = { ...cellStyle, ...this.props.columnDef.cellStyle(this.props.value, this.props.rowData) }; + if (typeof this.props.columnDef.cellStyle === "function") { + cellStyle = { + ...cellStyle, + ...this.props.columnDef.cellStyle(this.props.value, this.props.rowData), + }; } else { cellStyle = { ...cellStyle, ...this.props.columnDef.cellStyle }; } if (this.props.columnDef.disableClick) { - cellStyle.cursor = 'default'; + cellStyle.cursor = "default"; } return { ...this.props.style, ...cellStyle }; - } + }; render() { - const { icons, columnDef, rowData, ...cellProps } = this.props; - const cellAlignment = columnDef.align !== undefined ? columnDef.align : ['numeric', 'currency'].indexOf(this.props.columnDef.type) !== -1 ? "right" : "left"; + const cellAlignment = + columnDef.align !== undefined + ? columnDef.align + : ["numeric", "currency"].indexOf(this.props.columnDef.type) !== -1 + ? "right" + : "left"; return ( this.props.onChange(event.target.value)} - style={{ - fontSize: 13, - }} - SelectDisplayProps={{ 'aria-label': this.props.columnDef.title }} - > - {Object.keys(this.props.columnDef.lookup).map(key => ( - {this.props.columnDef.lookup[key]}) - )} - + ); } @@ -37,14 +44,14 @@ class MTableEditField extends React.Component { {...this.getProps()} value={String(this.props.value)} checked={Boolean(this.props.value)} - onChange={event => this.props.onChange(event.target.checked)} + onChange={(event) => this.props.onChange(event.target.checked)} style={{ paddingLeft: 0, paddingTop: 0, - paddingBottom: 0 + paddingBottom: 0, }} inputProps={{ - 'aria-label': this.props.columnDef.title + "aria-label": this.props.columnDef.title, }} /> ); @@ -52,23 +59,20 @@ class MTableEditField extends React.Component { renderDateField() { return ( - + @@ -76,23 +80,20 @@ class MTableEditField extends React.Component { } renderTimeField() { return ( - + @@ -101,25 +102,21 @@ class MTableEditField extends React.Component { renderDateTimeField() { return ( - + ); @@ -129,18 +126,22 @@ class MTableEditField extends React.Component { return ( this.props.onChange(event.target.value)} + style={ + this.props.columnDef.type === "numeric" ? { float: "right" } : {} + } + type={this.props.columnDef.type === "numeric" ? "number" : "text"} + placeholder={ + this.props.columnDef.editPlaceholder || this.props.columnDef.title + } + value={this.props.value === undefined ? "" : this.props.value} + onChange={(event) => this.props.onChange(event.target.value)} InputProps={{ style: { fontSize: 13, }, inputProps: { - 'aria-label': this.props.columnDef.title - } + "aria-label": this.props.columnDef.title, + }, }} /> ); @@ -150,15 +151,17 @@ class MTableEditField extends React.Component { return ( this.props.onChange(event.target.value)} + placeholder={ + this.props.columnDef.editPlaceholder || this.props.columnDef.title + } + value={this.props.value === undefined ? "" : this.props.value} + onChange={(event) => this.props.onChange(event.target.value)} inputProps={{ style: { fontSize: 13, - textAlign: 'right', - 'aria-label': this.props.columnDef.title - } + textAlign: "right", + "aria-label": this.props.columnDef.title, + }, }} /> ); @@ -169,28 +172,21 @@ class MTableEditField extends React.Component { if (this.props.columnDef.lookup) { component = this.renderLookupField(); - } - else if (this.props.columnDef.type === "boolean") { + } else if (this.props.columnDef.type === "boolean") { component = this.renderBooleanField(); - } - else if (this.props.columnDef.type === "date") { + } else if (this.props.columnDef.type === "date") { component = this.renderDateField(); - } - else if (this.props.columnDef.type === "time") { + } else if (this.props.columnDef.type === "time") { component = this.renderTimeField(); - } - else if (this.props.columnDef.type === "datetime") { + } else if (this.props.columnDef.type === "datetime") { component = this.renderDateTimeField(); - } - else if (this.props.columnDef.type === "currency") { + } else if (this.props.columnDef.type === "currency") { component = this.renderCurrencyField(); - } - else { + } else { component = this.renderTextField(); } return component; - } } @@ -198,7 +194,7 @@ MTableEditField.propTypes = { value: PropTypes.any, onChange: PropTypes.func.isRequired, columnDef: PropTypes.object.isRequired, - dateTimePickerLocalization: PropTypes.object + dateTimePickerLocalization: PropTypes.object, }; export default MTableEditField; diff --git a/src/components/m-table-edit-row.js b/src/components/m-table-edit-row.js index 86b9fafb4..a94ccb09f 100644 --- a/src/components/m-table-edit-row.js +++ b/src/components/m-table-edit-row.js @@ -1,48 +1,64 @@ /* eslint-disable no-unused-vars */ -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import Typography from '@material-ui/core/Typography'; -import PropTypes from 'prop-types'; -import * as React from 'react'; -import { byString, setByString } from '../utils'; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import Typography from "@material-ui/core/Typography"; +import PropTypes from "prop-types"; +import * as React from "react"; +import { byString, setByString } from "../utils"; import * as CommonValues from "../utils/common-values"; /* eslint-enable no-unused-vars */ - export default class MTableEditRow extends React.Component { - constructor(props) { super(props); this.state = { - data: props.data ? JSON.parse(JSON.stringify(props.data)) : this.createRowData() + data: props.data + ? JSON.parse(JSON.stringify(props.data)) + : this.createRowData(), }; } createRowData() { - return this.props.columns.filter(column => (column.initialEditValue || column.initialEditValue === 0) && column.field).reduce((prev,column)=>{ - prev[column.field]=column.initialEditValue; - return prev; - },{}); + return this.props.columns + .filter( + (column) => + (column.initialEditValue || column.initialEditValue === 0) && + column.field + ) + .reduce((prev, column) => { + prev[column.field] = column.initialEditValue; + return prev; + }, {}); } renderColumns() { const size = CommonValues.elementSize(this.props); - const mapArr = this.props.columns.filter(columnDef => !columnDef.hidden && !(columnDef.tableData.groupOrder > -1)) + const mapArr = this.props.columns + .filter( + (columnDef) => + !columnDef.hidden && !(columnDef.tableData.groupOrder > -1) + ) .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) .map((columnDef, index) => { - const value = (typeof this.state.data[columnDef.field] !== 'undefined' ? this.state.data[columnDef.field] : byString(this.state.data, columnDef.field)); + const value = + typeof this.state.data[columnDef.field] !== "undefined" + ? this.state.data[columnDef.field] + : byString(this.state.data, columnDef.field); const getCellStyle = (columnDef, value) => { let cellStyle = { - color: 'inherit' + color: "inherit", }; - if (typeof columnDef.cellStyle === 'function') { - cellStyle = { ...cellStyle, ...columnDef.cellStyle(value, this.props.data) }; + if (typeof columnDef.cellStyle === "function") { + cellStyle = { + ...cellStyle, + ...columnDef.cellStyle(value, this.props.data), + }; } else { cellStyle = { ...cellStyle, ...columnDef.cellStyle }; } if (columnDef.disableClick) { - cellStyle.cursor = 'default'; + cellStyle.cursor = "default"; } return { ...cellStyle }; @@ -58,20 +74,23 @@ export default class MTableEditRow extends React.Component { if (columnDef.editable === undefined) { allowEditing = true; } - if (columnDef.editable === 'always') { + if (columnDef.editable === "always") { allowEditing = true; } - if (columnDef.editable === 'onAdd' && this.props.mode === 'add') { + if (columnDef.editable === "onAdd" && this.props.mode === "add") { allowEditing = true; } - if (columnDef.editable === 'onUpdate' && this.props.mode === 'update') { + if (columnDef.editable === "onUpdate" && this.props.mode === "update") { allowEditing = true; } - if (typeof columnDef.editable == 'function'){ - allowEditing = columnDef.editable(columnDef, this.props.data); + if (typeof columnDef.editable == "function") { + allowEditing = columnDef.editable(columnDef, this.props.data); } if (!columnDef.field || !allowEditing) { - const readonlyValue = this.props.getFieldValue(this.state.data, columnDef); + const readonlyValue = this.props.getFieldValue( + this.state.data, + columnDef + ); return ( ); - } - else { + } else { const { editComponent, ...cellProps } = columnDef; - const EditComponent = editComponent || this.props.components.EditField; - + const EditComponent = + editComponent || this.props.components.EditField; + return ( { + onChange={(value) => { const data = { ...this.state.data }; setByString(data, columnDef.field, value); // data[columnDef.field] = value; this.setState({ data }); }} - onRowDataChange={data => { + onRowDataChange={(data) => { this.setState({ data }); }} /> @@ -120,7 +141,10 @@ export default class MTableEditRow extends React.Component { renderActions() { const size = CommonValues.elementSize(this.props); - const localization = { ...MTableEditRow.defaultProps.localization, ...this.props.localization }; + const localization = { + ...MTableEditRow.defaultProps.localization, + ...this.props.localization, + }; const actions = [ { icon: this.props.icons.Check, @@ -128,21 +152,39 @@ export default class MTableEditRow extends React.Component { onClick: () => { const newData = this.state.data; delete newData.tableData; - this.props.onEditingApproved(this.props.mode, this.state.data, this.props.data); - } + this.props.onEditingApproved( + this.props.mode, + this.state.data, + this.props.data + ); + }, }, { icon: this.props.icons.Clear, tooltip: localization.cancelTooltip, onClick: () => { this.props.onEditingCanceled(this.props.mode, this.props.data); - } - } + }, + }, ]; return ( - -
- + +
+
); @@ -151,46 +193,59 @@ export default class MTableEditRow extends React.Component { getStyle() { const style = { // boxShadow: '1px 1px 1px 1px rgba(0,0,0,0.2)', - borderBottom: '1px solid red' + borderBottom: "1px solid red", }; return style; } cancelEdit = (e) => { - if(e.keyCode === 27) { + if (e.keyCode === 27) { this.props.onEditingCanceled(this.props.mode, this.props.data); } - } + }; render() { const size = CommonValues.elementSize(this.props); - const localization = { ...MTableEditRow.defaultProps.localization, ...this.props.localization }; + const localization = { + ...MTableEditRow.defaultProps.localization, + ...this.props.localization, + }; let columns; if (this.props.mode === "add" || this.props.mode === "update") { columns = this.renderColumns(); - } - else { - const colSpan = this.props.columns.filter(columnDef => !columnDef.hidden && !(columnDef.tableData.groupOrder > -1)).length; + } else { + const colSpan = this.props.columns.filter( + (columnDef) => + !columnDef.hidden && !(columnDef.tableData.groupOrder > -1) + ).length; columns = [ - - {localization.deleteText} - - + colSpan={colSpan} + > + {localization.deleteText} + , ]; } - if (this.props.options.selection) { - columns.splice(0, 0, ); + columns.splice( + 0, + 0, + + ); } if (this.props.isTreeData) { - columns.splice(0, 0, ); + columns.splice( + 0, + 0, + + ); } if (this.props.options.actionsColumnIndex === -1) { @@ -206,20 +261,35 @@ export default class MTableEditRow extends React.Component { columns.splice(1, 1); } } - columns.splice(this.props.options.actionsColumnIndex + endPos, 0, this.renderActions()); + columns.splice( + this.props.options.actionsColumnIndex + endPos, + 0, + this.renderActions() + ); } // Lastly we add detail panel icon if (this.props.detailPanel) { const aligment = this.props.options.detailPanelColumnAlignment; const index = aligment === "left" ? 0 : columns.length; - columns.splice(index, 0, ); + columns.splice( + index, + 0, + + ); } this.props.columns - .filter(columnDef => columnDef.tableData.groupOrder > -1) - .forEach(columnDef => { - columns.splice(0, 0, ); + .filter((columnDef) => columnDef.tableData.groupOrder > -1) + .forEach((columnDef) => { + columns.splice( + 0, + 0, + + ); }); const { @@ -244,7 +314,7 @@ export default class MTableEditRow extends React.Component { return ( <> @@ -261,10 +331,10 @@ MTableEditRow.defaultProps = { options: {}, path: [], localization: { - saveTooltip: 'Save', - cancelTooltip: 'Cancel', - deleteText: 'Are you sure you want to delete this row?', - } + saveTooltip: "Save", + cancelTooltip: "Cancel", + deleteText: "Are you sure you want to delete this row?", + }, }; MTableEditRow.propTypes = { @@ -272,7 +342,10 @@ MTableEditRow.propTypes = { icons: PropTypes.any.isRequired, index: PropTypes.number.isRequired, data: PropTypes.object, - detailPanel: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func]))]), + detailPanel: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.object, PropTypes.func])), + ]), options: PropTypes.object.isRequired, onRowSelected: PropTypes.func, path: PropTypes.arrayOf(PropTypes.number), @@ -281,5 +354,5 @@ MTableEditRow.propTypes = { onEditingApproved: PropTypes.func, onEditingCanceled: PropTypes.func, localization: PropTypes.object, - getFieldValue: PropTypes.func + getFieldValue: PropTypes.func, }; diff --git a/src/components/m-table-filter-row.js b/src/components/m-table-filter-row.js index 016bc50e9..f04e04d07 100644 --- a/src/components/m-table-filter-row.js +++ b/src/components/m-table-filter-row.js @@ -1,21 +1,26 @@ /* eslint-disable no-unused-vars */ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import TextField from '@material-ui/core/TextField'; -import FormControl from '@material-ui/core/FormControl'; -import Select from '@material-ui/core/Select'; -import Input from '@material-ui/core/Input'; -import InputLabel from '@material-ui/core/InputLabel'; -import MenuItem from '@material-ui/core/MenuItem'; -import Checkbox from '@material-ui/core/Checkbox'; -import ListItemText from '@material-ui/core/ListItemText'; -import InputAdornment from '@material-ui/core/InputAdornment'; -import Icon from '@material-ui/core/Icon'; -import Tooltip from '@material-ui/core/Tooltip'; -import DateFnsUtils from '@date-io/date-fns'; -import { MuiPickersUtilsProvider, TimePicker, DatePicker, DateTimePicker } from '@material-ui/pickers'; +import * as React from "react"; +import PropTypes from "prop-types"; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import TextField from "@material-ui/core/TextField"; +import FormControl from "@material-ui/core/FormControl"; +import Select from "@material-ui/core/Select"; +import Input from "@material-ui/core/Input"; +import InputLabel from "@material-ui/core/InputLabel"; +import MenuItem from "@material-ui/core/MenuItem"; +import Checkbox from "@material-ui/core/Checkbox"; +import ListItemText from "@material-ui/core/ListItemText"; +import InputAdornment from "@material-ui/core/InputAdornment"; +import Icon from "@material-ui/core/Icon"; +import Tooltip from "@material-ui/core/Tooltip"; +import DateFnsUtils from "@date-io/date-fns"; +import { + MuiPickersUtilsProvider, + TimePicker, + DatePicker, + DateTimePicker, +} from "@material-ui/pickers"; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; @@ -23,133 +28,159 @@ const MenuProps = { PaperProps: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, - width: 250 - } - } + width: 250, + }, + }, }; class MTableFilterRow extends React.Component { - getLocalizationData = () => ({ ...MTableFilterRow.defaultProps.localization, ...this.props.localization }); - getLocalizedFilterPlaceHolder = columnDef => columnDef.filterPlaceholder || this.getLocalizationData().filterPlaceHolder || ""; + getLocalizationData = () => ({ + ...MTableFilterRow.defaultProps.localization, + ...this.props.localization, + }); + getLocalizedFilterPlaceHolder = (columnDef) => + columnDef.filterPlaceholder || + this.getLocalizationData().filterPlaceHolder || + ""; LookupFilter = ({ columnDef }) => { - const [selectedFilter, setSelectedFilter] = React.useState(columnDef.tableData.filterValue || []); + const [selectedFilter, setSelectedFilter] = React.useState( + columnDef.tableData.filterValue || [] + ); React.useEffect(() => { setSelectedFilter(columnDef.tableData.filterValue || []); }, [columnDef.tableData.filterValue]); - return - {this.getLocalizedFilterPlaceHolder(columnDef)} - } - renderValue={selecteds => selecteds.map(selected => columnDef.lookup[selected]).join(', ')} - MenuProps={MenuProps} - style={{marginTop: 0}} - > - { - Object.keys(columnDef.lookup).map(key => ( + return ( + + + {this.getLocalizedFilterPlaceHolder(columnDef)} + + + } + renderValue={(selecteds) => + selecteds.map((selected) => columnDef.lookup[selected]).join(", ") + } + MenuProps={MenuProps} + style={{ marginTop: 0 }} + > + {Object.keys(columnDef.lookup).map((key) => ( -1} /> - )) - } - - ; - } - + ))} + + + ); + }; - renderFilterComponent = (columnDef) => ( - React.createElement(columnDef.filterComponent, { columnDef: columnDef, onFilterChanged: this.props.onFilterChanged }) - ) + renderFilterComponent = (columnDef) => + React.createElement(columnDef.filterComponent, { + columnDef: columnDef, + onFilterChanged: this.props.onFilterChanged, + }); renderBooleanFilter = (columnDef) => ( { let val; if (columnDef.tableData.filterValue === undefined) { - val = 'checked'; - } else if (columnDef.tableData.filterValue === 'checked') { - val = 'unchecked'; + val = "checked"; + } else if (columnDef.tableData.filterValue === "checked") { + val = "unchecked"; } this.props.onFilterChanged(columnDef.tableData.id, val); }} /> - ) + ); renderDefaultFilter = (columnDef) => { const localization = this.getLocalizationData(); const FilterIcon = this.props.icons.Filter; return ( { - this.props.onFilterChanged(columnDef.tableData.id, event.target.value); - }} - inputProps={{'aria-label': `filter data by ${columnDef.title}`}} - InputProps={this.props.hideFilterIcons || columnDef.hideFilterIcon ? undefined : { - startAdornment: ( - - - - - - ) + this.props.onFilterChanged( + columnDef.tableData.id, + event.target.value + ); }} + inputProps={{ "aria-label": `filter data by ${columnDef.title}` }} + InputProps={ + this.props.hideFilterIcons || columnDef.hideFilterIcon + ? undefined + : { + startAdornment: ( + + + + + + ), + } + } /> ); - } + }; renderDateTypeFilter = (columnDef) => { - const onDateInputChange = date => this.props.onFilterChanged(columnDef.tableData.id, date); + const onDateInputChange = (date) => + this.props.onFilterChanged(columnDef.tableData.id, date); const pickerProps = { value: columnDef.tableData.filterValue || null, onChange: onDateInputChange, placeholder: this.getLocalizedFilterPlaceHolder(columnDef), - clearable: true + clearable: true, }; let dateInputElement = null; - if (columnDef.type === 'date') { - dateInputElement = ( - - ); - } else if (columnDef.type === 'datetime') { - dateInputElement = ( - - ); - } else if (columnDef.type === 'time') { - dateInputElement = ( - - ); + if (columnDef.type === "date") { + dateInputElement = ; + } else if (columnDef.type === "datetime") { + dateInputElement = ; + } else if (columnDef.type === "time") { + dateInputElement = ; } return ( + locale={this.props.localization.dateTimePickerLocalization} + > {dateInputElement} ); - } + }; getComponentForColumn(columnDef) { if (columnDef.filtering === false) { @@ -161,9 +192,9 @@ class MTableFilterRow extends React.Component { return this.renderFilterComponent(columnDef); } else if (columnDef.lookup) { return ; - } else if (columnDef.type === 'boolean') { + } else if (columnDef.type === "boolean") { return this.renderBooleanFilter(columnDef); - } else if (['date', 'datetime', 'time'].includes(columnDef.type)) { + } else if (["date", "datetime", "time"].includes(columnDef.type)) { return this.renderDateTypeFilter(columnDef); } else { return this.renderDefaultFilter(columnDef); @@ -173,16 +204,29 @@ class MTableFilterRow extends React.Component { render() { const columns = this.props.columns - .filter(columnDef => !columnDef.hidden && !(columnDef.tableData.groupOrder > -1)) + .filter( + (columnDef) => + !columnDef.hidden && !(columnDef.tableData.groupOrder > -1) + ) .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) - .map(columnDef => ( - + .map((columnDef) => ( + {this.getComponentForColumn(columnDef)} )); if (this.props.selection) { - columns.splice(0, 0, ); + columns.splice( + 0, + 0, + + ); } if (this.props.hasActions) { @@ -193,27 +237,41 @@ class MTableFilterRow extends React.Component { if (this.props.selection) { endPos = 1; } - columns.splice(this.props.actionsColumnIndex + endPos, 0, ); + columns.splice( + this.props.actionsColumnIndex + endPos, + 0, + + ); } } if (this.props.hasDetailPanel) { - columns.splice(0, 0, ); + columns.splice( + 0, + 0, + + ); } if (this.props.isTreeData > 0) { - columns.splice(0, 0, - + columns.splice( + 0, + 0, + ); } this.props.columns - .filter(columnDef => columnDef.tableData.groupOrder > -1) - .forEach(columnDef => { - columns.splice(0, 0, ); + .filter((columnDef) => columnDef.tableData.groupOrder > -1) + .forEach((columnDef) => { + columns.splice( + 0, + 0, + + ); }); return ( @@ -229,7 +287,7 @@ MTableFilterRow.defaultProps = { selection: false, hasActions: false, localization: { - filterTooltip: 'Filter' + filterTooltip: "Filter", }, hideFilterIcons: false, }; diff --git a/src/components/m-table-group-row.js b/src/components/m-table-group-row.js index 54b171963..4e7fd399f 100644 --- a/src/components/m-table-group-row.js +++ b/src/components/m-table-group-row.js @@ -1,38 +1,38 @@ /* eslint-disable no-unused-vars */ -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import IconButton from '@material-ui/core/IconButton'; -import PropTypes from 'prop-types'; -import * as React from 'react'; +import TableCell from "@material-ui/core/TableCell"; +import TableRow from "@material-ui/core/TableRow"; +import IconButton from "@material-ui/core/IconButton"; +import PropTypes from "prop-types"; +import * as React from "react"; /* eslint-enable no-unused-vars */ - export default class MTableGroupRow extends React.Component { - - rotateIconStyle = isOpen => ({ - transform: isOpen ? 'rotate(90deg)' : 'none' + rotateIconStyle = (isOpen) => ({ + transform: isOpen ? "rotate(90deg)" : "none", }); render() { - let colSpan = this.props.columns.filter(columnDef => !columnDef.hidden).length; - this.props.options.selection && colSpan++; + let colSpan = this.props.columns.filter((columnDef) => !columnDef.hidden) + .length; + this.props.options.selection && colSpan++; this.props.detailPanel && colSpan++; this.props.actions && this.props.actions.length > 0 && colSpan++; const column = this.props.groups[this.props.level]; let detail; if (this.props.groupData.isExpanded) { - if (this.props.groups.length > (this.props.level + 1)) { // Is there another group + if (this.props.groups.length > this.props.level + 1) { + // Is there another group detail = this.props.groupData.groups.map((groupData, index) => ( )); - } - else { + } else { detail = this.props.groupData.data.map((rowData, index) => { if (rowData.tableData.editing) { return ( @@ -100,14 +99,14 @@ export default class MTableGroupRow extends React.Component { const freeCells = []; for (let i = 0; i < this.props.level; i++) { - freeCells.push(); + freeCells.push(); } let value = this.props.groupData.value; if (column.lookup) { value = column.lookup[value]; } - + let title = column.title; if (typeof this.props.options.groupTitle === "function") { title = this.props.options.groupTitle(this.props.groupData); @@ -121,22 +120,28 @@ export default class MTableGroupRow extends React.Component { <> {freeCells} - { this.props.onGroupExpandChanged(this.props.path); }} > - {title}{separator} + + {title} + {separator} + {detail} @@ -149,14 +154,17 @@ MTableGroupRow.defaultProps = { columns: [], groups: [], options: {}, - level: 0 + level: 0, }; MTableGroupRow.propTypes = { actions: PropTypes.array, columns: PropTypes.arrayOf(PropTypes.object), components: PropTypes.object, - detailPanel: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.object)]), + detailPanel: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.arrayOf(PropTypes.object), + ]), getFieldValue: PropTypes.func, groupData: PropTypes.object, groups: PropTypes.arrayOf(PropTypes.object), @@ -167,7 +175,7 @@ MTableGroupRow.propTypes = { localization: PropTypes.object, onGroupExpandChanged: PropTypes.func, onRowSelected: PropTypes.func, - onRowClick: PropTypes.func, + onRowClick: PropTypes.func, onToggleDetailPanel: PropTypes.func.isRequired, onTreeExpandChanged: PropTypes.func.isRequired, onEditingCanceled: PropTypes.func, diff --git a/src/components/m-table-groupbar.js b/src/components/m-table-groupbar.js index a23dc667c..f49596150 100644 --- a/src/components/m-table-groupbar.js +++ b/src/components/m-table-groupbar.js @@ -1,23 +1,21 @@ /* eslint-disable no-unused-vars */ -import Toolbar from '@material-ui/core/Toolbar'; -import Chip from '@material-ui/core/Chip'; -import Typography from '@material-ui/core/Typography'; -import PropTypes from 'prop-types'; -import * as React from 'react'; -import { Droppable, Draggable } from 'react-beautiful-dnd'; +import Toolbar from "@material-ui/core/Toolbar"; +import Chip from "@material-ui/core/Chip"; +import Typography from "@material-ui/core/Typography"; +import PropTypes from "prop-types"; +import * as React from "react"; +import { Droppable, Draggable } from "react-beautiful-dnd"; /* eslint-enable no-unused-vars */ - class MTableGroupbar extends React.Component { constructor(props) { super(props); - this.state = { - }; + this.state = {}; } getItemStyle = (isDragging, draggableStyle) => ({ // some basic styles to make the items look a bit nicer - userSelect: 'none', + userSelect: "none", // padding: '8px 16px', margin: `0 ${8}px 0 0`, @@ -28,74 +26,91 @@ class MTableGroupbar extends React.Component { ...draggableStyle, }); - getListStyle = isDraggingOver => ({ + getListStyle = (isDraggingOver) => ({ // background: isDraggingOver ? 'lightblue' : '#0000000a', - background: '#0000000a', - display: 'flex', - width: '100%', + background: "#0000000a", + display: "flex", + width: "100%", padding: 8, - overflow: 'auto', - border: '1px solid #ccc', - borderStyle: 'dashed' + overflow: "auto", + border: "1px solid #ccc", + borderStyle: "dashed", }); render() { return ( - - + + {(provided, snapshot) => (
- {this.props.groupColumns.length > 0 && + {this.props.groupColumns.length > 0 && ( {this.props.localization.groupedBy} - } + )} {this.props.groupColumns.map((columnDef, index) => { return ( + index={index} + > {(provided, snapshot) => (
this.props.onSortChanged(columnDef)} label={ -
-
{columnDef.title}
- {columnDef.tableData.groupSort && +
+
+ {columnDef.title} +
+ {columnDef.tableData.groupSort && ( - } + )}
} - style={{ boxShadow: 'none', textTransform: 'none' }} - onDelete={() => this.props.onGroupRemoved(columnDef, index)} + style={{ boxShadow: "none", textTransform: "none" }} + onDelete={() => + this.props.onGroupRemoved(columnDef, index) + } />
)} ); })} - {this.props.groupColumns.length === 0 && + {this.props.groupColumns.length === 0 && ( {this.props.localization.placeholder} - } + )} {provided.placeholder}
)} @@ -105,13 +120,12 @@ class MTableGroupbar extends React.Component { } } -MTableGroupbar.defaultProps = { -}; +MTableGroupbar.defaultProps = {}; MTableGroupbar.propTypes = { localization: PropTypes.shape({ groupedBy: PropTypes.string, - placeholder: PropTypes.string + placeholder: PropTypes.string, }), }; diff --git a/src/components/m-table-header.js b/src/components/m-table-header.js index 4a41e4ee8..7bc18a6e1 100644 --- a/src/components/m-table-header.js +++ b/src/components/m-table-header.js @@ -1,23 +1,26 @@ /* eslint-disable no-unused-vars */ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import TableHead from '@material-ui/core/TableHead'; -import TableRow from '@material-ui/core/TableRow'; -import TableCell from '@material-ui/core/TableCell'; -import TableSortLabel from '@material-ui/core/TableSortLabel'; -import Checkbox from '@material-ui/core/Checkbox'; -import withStyles from '@material-ui/core/styles/withStyles'; -import { Draggable } from 'react-beautiful-dnd'; -import { Tooltip } from '@material-ui/core'; -import * as CommonValues from '../utils/common-values'; +import * as React from "react"; +import PropTypes from "prop-types"; +import TableHead from "@material-ui/core/TableHead"; +import TableRow from "@material-ui/core/TableRow"; +import TableCell from "@material-ui/core/TableCell"; +import TableSortLabel from "@material-ui/core/TableSortLabel"; +import Checkbox from "@material-ui/core/Checkbox"; +import withStyles from "@material-ui/core/styles/withStyles"; +import { Draggable } from "react-beautiful-dnd"; +import { Tooltip } from "@material-ui/core"; +import * as CommonValues from "../utils/common-values"; /* eslint-enable no-unused-vars */ export class MTableHeader extends React.Component { - renderHeader() { - const size = this.props.options.padding === 'default' ? 'medium' : 'small'; + const size = this.props.options.padding === "default" ? "medium" : "small"; - const mapArr = this.props.columns.filter(columnDef => !columnDef.hidden && !(columnDef.tableData.groupOrder > -1)) + const mapArr = this.props.columns + .filter( + (columnDef) => + !columnDef.hidden && !(columnDef.tableData.groupOrder > -1) + ) .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) .map((columnDef, index) => { let content = columnDef.title; @@ -27,7 +30,8 @@ export class MTableHeader extends React.Component { + index={index} + > {(provided, snapshot) => (
{ const orderDirection = columnDef.tableData.id !== this.props.orderBy - ? 'asc' - : this.props.orderDirection === 'asc' - ? 'desc' - : this.props.orderDirection === 'desc' && this.props.thirdSortClick - ? '' - : this.props.orderDirection === 'desc' && !this.props.thirdSortClick - ? 'asc' - : this.props.orderDirection === '' - ? 'asc' - : 'desc'; - this.props.onOrderChange(columnDef.tableData.id, orderDirection); + ? "asc" + : this.props.orderDirection === "asc" + ? "desc" + : this.props.orderDirection === "desc" && + this.props.thirdSortClick + ? "" + : this.props.orderDirection === "desc" && + !this.props.thirdSortClick + ? "asc" + : this.props.orderDirection === "" + ? "asc" + : "desc"; + this.props.onOrderChange( + columnDef.tableData.id, + orderDirection + ); }} > {content} @@ -69,15 +78,29 @@ export class MTableHeader extends React.Component { } if (columnDef.tooltip) { - content = {content}; + content = ( + + {content} + + ); } - const cellAlignment = columnDef.align !== undefined ? columnDef.align : ['numeric', 'currency'].indexOf(columnDef.type) !== -1 ? "right" : "left"; + const cellAlignment = + columnDef.align !== undefined + ? columnDef.align + : ["numeric", "currency"].indexOf(columnDef.type) !== -1 + ? "right" + : "left"; return ( {content} @@ -87,24 +110,35 @@ export class MTableHeader extends React.Component { return mapArr; } - - renderActionsHeader() { - const localization = { ...MTableHeader.defaultProps.localization, ...this.props.localization }; + const localization = { + ...MTableHeader.defaultProps.localization, + ...this.props.localization, + }; const width = CommonValues.actionsColumnWidth(this.props); return ( - {localization.actions} + + {localization.actions} + ); } renderSelectionHeader() { - const selectionWidth = CommonValues.selectionMaxWidth(this.props, this.props.treeDataMaxLevel); + const selectionWidth = CommonValues.selectionMaxWidth( + this.props, + this.props.treeDataMaxLevel + ); return ( - {this.props.showSelectAllCheckbox && + {this.props.showSelectAllCheckbox && ( 0 && this.props.selectedCount < this.props.dataCount} - checked={this.props.dataCount > 0 && this.props.selectedCount === this.props.dataCount} - onChange={(event, checked) => this.props.onAllSelected && this.props.onAllSelected(checked)} + indeterminate={ + this.props.selectedCount > 0 && + this.props.selectedCount < this.props.dataCount + } + checked={ + this.props.dataCount > 0 && + this.props.selectedCount === this.props.dataCount + } + onChange={(event, checked) => + this.props.onAllSelected && this.props.onAllSelected(checked) + } /> - } + )} ); } renderDetailPanelColumnCell() { - return ; + return ( + + ); } render() { @@ -145,14 +189,18 @@ export class MTableHeader extends React.Component { if (this.props.hasSelection) { endPos = 1; } - headers.splice(this.props.actionsHeaderIndex + endPos, 0, this.renderActionsHeader()); + headers.splice( + this.props.actionsHeaderIndex + endPos, + 0, + this.renderActionsHeader() + ); } else if (this.props.actionsHeaderIndex === -1) { headers.push(this.renderActionsHeader()); } } if (this.props.hasDetailPanel) { - if (this.props.detailPanelColumnAlignment === 'right') { + if (this.props.detailPanelColumnAlignment === "right") { headers.push(this.renderDetailPanelColumnCell()); } else { headers.splice(0, 0, this.renderDetailPanelColumnCell()); @@ -160,7 +208,9 @@ export class MTableHeader extends React.Component { } if (this.props.isTreeData > 0) { - headers.splice(0, 0, + headers.splice( + 0, + 0, columnDef.tableData.groupOrder > -1) - .forEach(columnDef => { - headers.splice(0, 0, ); + .filter((columnDef) => columnDef.tableData.groupOrder > -1) + .forEach((columnDef) => { + headers.splice( + 0, + 0, + + ); }); return ( - - {headers} - + {headers} ); } @@ -193,10 +249,10 @@ MTableHeader.defaultProps = { selectedCount: 0, sorting: true, localization: { - actions: 'Actions' + actions: "Actions", }, orderBy: undefined, - orderDirection: 'asc', + orderDirection: "asc", actionsHeaderIndex: 0, detailPanelColumnAlignment: "left", draggable: true, @@ -222,17 +278,16 @@ MTableHeader.propTypes = { showSelectAllCheckbox: PropTypes.bool, draggable: PropTypes.bool, thirdSortClick: PropTypes.bool, - tooltip: PropTypes.string + tooltip: PropTypes.string, }; - -export const styles = theme => ({ +export const styles = (theme) => ({ header: { - position: 'sticky', + position: "sticky", top: 0, zIndex: 10, backgroundColor: theme.palette.background.paper, // Change according to theme, - } + }, }); export default withStyles(styles)(MTableHeader); diff --git a/src/components/m-table-pagination.js b/src/components/m-table-pagination.js index a671ff77f..ecab5770f 100644 --- a/src/components/m-table-pagination.js +++ b/src/components/m-table-pagination.js @@ -1,36 +1,49 @@ /* eslint-disable no-unused-vars */ -import IconButton from '@material-ui/core/IconButton'; -import withStyles from '@material-ui/core/styles/withStyles'; -import Tooltip from '@material-ui/core/Tooltip'; -import Typography from '@material-ui/core/Typography'; -import PropTypes from 'prop-types'; -import * as React from 'react'; +import IconButton from "@material-ui/core/IconButton"; +import withStyles from "@material-ui/core/styles/withStyles"; +import Tooltip from "@material-ui/core/Tooltip"; +import Typography from "@material-ui/core/Typography"; +import PropTypes from "prop-types"; +import * as React from "react"; /* eslint-enable no-unused-vars */ class MTablePaginationInner extends React.Component { - handleFirstPageButtonClick = event => { + handleFirstPageButtonClick = (event) => { this.props.onChangePage(event, 0); }; - handleBackButtonClick = event => { + handleBackButtonClick = (event) => { this.props.onChangePage(event, this.props.page - 1); }; - handleNextButtonClick = event => { + handleNextButtonClick = (event) => { this.props.onChangePage(event, this.props.page + 1); }; - handleLastPageButtonClick = event => { - this.props.onChangePage(event, Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1)); + handleLastPageButtonClick = (event) => { + this.props.onChangePage( + event, + Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1) + ); }; render() { - const { classes, count, page, rowsPerPage, theme, showFirstLastPageButtons } = this.props; - const localization = { ...MTablePaginationInner.defaultProps.localization, ...this.props.localization }; + const { + classes, + count, + page, + rowsPerPage, + theme, + showFirstLastPageButtons, + } = this.props; + const localization = { + ...MTablePaginationInner.defaultProps.localization, + ...this.props.localization, + }; return (
- {showFirstLastPageButtons && + {showFirstLastPageButtons && ( - {theme.direction === 'rtl' ? : } + {theme.direction === "rtl" ? ( + + ) : ( + + )} - } + )} - {theme.direction === 'rtl' ? : } + {theme.direction === "rtl" ? ( + + ) : ( + + )} - - {localization.labelDisplayedRows.replace('{from}', this.props.count === 0 ? 0 : ((this.props.page * this.props.rowsPerPage) + 1)).replace('{to}', Math.min((this.props.page + 1) * this.props.rowsPerPage, this.props.count)).replace('{count}', this.props.count)} + + {localization.labelDisplayedRows + .replace( + "{from}", + this.props.count === 0 + ? 0 + : this.props.page * this.props.rowsPerPage + 1 + ) + .replace( + "{to}", + Math.min( + (this.props.page + 1) * this.props.rowsPerPage, + this.props.count + ) + ) + .replace("{count}", this.props.count)} @@ -64,11 +107,15 @@ class MTablePaginationInner extends React.Component { disabled={page >= Math.ceil(count / rowsPerPage) - 1} aria-label={localization.nextAriaLabel} > - {theme.direction === 'rtl' ? : } + {theme.direction === "rtl" ? ( + + ) : ( + + )} - {showFirstLastPageButtons && + {showFirstLastPageButtons && ( = Math.ceil(count / rowsPerPage) - 1} aria-label={localization.lastAriaLabel} > - {theme.direction === 'rtl' ? : } + {theme.direction === "rtl" ? ( + + ) : ( + + )} - } -
+ )} +
); } } -const actionsStyles = theme => ({ +const actionsStyles = (theme) => ({ root: { flexShrink: 0, color: theme.palette.text.secondary, - display: 'flex', + display: "flex", // lineHeight: '48px' - } + }, }); MTablePaginationInner.propTypes = { @@ -103,21 +154,23 @@ MTablePaginationInner.propTypes = { classes: PropTypes.object, localization: PropTypes.object, theme: PropTypes.any, - showFirstLastPageButtons: PropTypes.bool + showFirstLastPageButtons: PropTypes.bool, }; MTablePaginationInner.defaultProps = { showFirstLastPageButtons: true, localization: { - firstTooltip: 'First Page', - previousTooltip: 'Previous Page', - nextTooltip: 'Next Page', - lastTooltip: 'Last Page', - labelDisplayedRows: '{from}-{to} of {count}', - labelRowsPerPage: 'Rows per page:' - } + firstTooltip: "First Page", + previousTooltip: "Previous Page", + nextTooltip: "Next Page", + lastTooltip: "Last Page", + labelDisplayedRows: "{from}-{to} of {count}", + labelRowsPerPage: "Rows per page:", + }, }; -const MTablePagination = withStyles(actionsStyles, { withTheme: true })(MTablePaginationInner); +const MTablePagination = withStyles(actionsStyles, { withTheme: true })( + MTablePaginationInner +); export default MTablePagination; diff --git a/src/components/m-table-stepped-pagination.js b/src/components/m-table-stepped-pagination.js index 624446227..ba16fbca1 100644 --- a/src/components/m-table-stepped-pagination.js +++ b/src/components/m-table-stepped-pagination.js @@ -1,31 +1,31 @@ /* eslint-disable no-unused-vars */ -import IconButton from '@material-ui/core/IconButton'; -import withStyles from '@material-ui/core/styles/withStyles'; -import Tooltip from '@material-ui/core/Tooltip'; -import Hidden from '@material-ui/core/Hidden'; -import Button from '@material-ui/core/Button'; -import PropTypes from 'prop-types'; -import * as React from 'react'; +import IconButton from "@material-ui/core/IconButton"; +import withStyles from "@material-ui/core/styles/withStyles"; +import Tooltip from "@material-ui/core/Tooltip"; +import Hidden from "@material-ui/core/Hidden"; +import Button from "@material-ui/core/Button"; +import PropTypes from "prop-types"; +import * as React from "react"; /* eslint-enable no-unused-vars */ class MTablePaginationInner extends React.Component { - handleFirstPageButtonClick = event => { + handleFirstPageButtonClick = (event) => { this.props.onChangePage(event, 0); }; - handleBackButtonClick = event => { + handleBackButtonClick = (event) => { this.props.onChangePage(event, this.props.page - 1); }; - handleNextButtonClick = event => { + handleNextButtonClick = (event) => { this.props.onChangePage(event, this.props.page + 1); }; - handleNumberButtonClick = number => event => { + handleNumberButtonClick = (number) => (event) => { this.props.onChangePage(event, number); }; - handleLastPageButtonClick = event => { + handleLastPageButtonClick = (event) => { this.props.onChangePage( event, Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1) @@ -41,8 +41,11 @@ class MTablePaginationInner extends React.Component {
); } } -const actionsStyles = theme => ({ +const actionsStyles = (theme) => ({ root: { flexShrink: 0, color: theme.palette.text.secondary, - marginLeft: theme.spacing(2.5) - } + marginLeft: theme.spacing(2.5), + }, }); MTablePaginationInner.propTypes = { @@ -140,21 +161,23 @@ MTablePaginationInner.propTypes = { classes: PropTypes.object, localization: PropTypes.object, theme: PropTypes.any, - showFirstLastPageButtons: PropTypes.bool + showFirstLastPageButtons: PropTypes.bool, }; MTablePaginationInner.defaultProps = { showFirstLastPageButtons: true, localization: { - firstTooltip: 'First Page', - previousTooltip: 'Previous Page', - nextTooltip: 'Next Page', - lastTooltip: 'Last Page', - labelDisplayedRows: '{from}-{to} of {count}', - labelRowsPerPage: 'Rows per page:' - } + firstTooltip: "First Page", + previousTooltip: "Previous Page", + nextTooltip: "Next Page", + lastTooltip: "Last Page", + labelDisplayedRows: "{from}-{to} of {count}", + labelRowsPerPage: "Rows per page:", + }, }; -const MTableSteppedPagination = withStyles(actionsStyles, { withTheme: true })(MTablePaginationInner); +const MTableSteppedPagination = withStyles(actionsStyles, { withTheme: true })( + MTablePaginationInner +); export default MTableSteppedPagination; diff --git a/src/components/m-table-toolbar.js b/src/components/m-table-toolbar.js index 29036fc2e..e35f7f4f5 100644 --- a/src/components/m-table-toolbar.js +++ b/src/components/m-table-toolbar.js @@ -1,20 +1,22 @@ /* eslint-disable no-unused-vars */ -import Checkbox from '@material-ui/core/Checkbox'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import IconButton from '@material-ui/core/IconButton'; -import InputAdornment from '@material-ui/core/InputAdornment'; -import Menu from '@material-ui/core/Menu'; -import MenuItem from '@material-ui/core/MenuItem'; -import TextField from '@material-ui/core/TextField'; -import Toolbar from '@material-ui/core/Toolbar'; -import Tooltip from '@material-ui/core/Tooltip'; -import Typography from '@material-ui/core/Typography'; -import withStyles from '@material-ui/core/styles/withStyles'; -import { lighten } from '@material-ui/core/styles/colorManipulator'; -import classNames from 'classnames'; -import { CsvBuilder } from 'filefy'; -import PropTypes, { oneOf } from 'prop-types'; -import * as React from 'react'; +import Checkbox from "@material-ui/core/Checkbox"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import IconButton from "@material-ui/core/IconButton"; +import InputAdornment from "@material-ui/core/InputAdornment"; +import Menu from "@material-ui/core/Menu"; +import MenuItem from "@material-ui/core/MenuItem"; +import TextField from "@material-ui/core/TextField"; +import Toolbar from "@material-ui/core/Toolbar"; +import Tooltip from "@material-ui/core/Tooltip"; +import Typography from "@material-ui/core/Typography"; +import withStyles from "@material-ui/core/styles/withStyles"; +import { lighten } from "@material-ui/core/styles/colorManipulator"; +import classNames from "classnames"; +import { CsvBuilder } from "filefy"; +import PropTypes, { oneOf } from "prop-types"; +import jsPDF from "jspdf"; +import "jspdf-autotable"; +import * as React from "react"; /* eslint-enable no-unused-vars */ export class MTableToolbar extends React.Component { @@ -23,35 +25,68 @@ export class MTableToolbar extends React.Component { this.state = { columnsButtonAnchorEl: null, exportButtonAnchorEl: null, - searchText: props.searchText + searchText: props.searchText, }; } - onSearchChange = searchText => { + onSearchChange = (searchText) => { this.props.dataManager.changeSearchText(searchText); - this.setState(({ searchText }), this.props.onSearchChanged(searchText)); - } + this.setState({ searchText }, this.props.onSearchChanged(searchText)); + }; - defaultExportCsv = () => { + getTableData = () => { const columns = this.props.columns - .filter(columnDef => { - return !columnDef.hidden && columnDef.field && columnDef.export !== false; - }) - .sort((a, b) => (a.tableData.columnOrder > b.tableData.columnOrder) ? 1 : -1); - const dataToExport = this.props.exportAllData ? this.props.data : this.props.renderData; - const data = dataToExport.map(rowData => - columns.map(columnDef => { - return this.props.getFieldValue(rowData, columnDef); - }) + .filter( + (columnDef) => + !columnDef.hidden && columnDef.field && columnDef.export !== false + ) + .sort((a, b) => + a.tableData.columnOrder > b.tableData.columnOrder ? 1 : -1 + ); + const data = (this.props.exportAllData + ? this.props.data + : this.props.renderData + ).map((rowData) => + columns.map((columnDef) => this.props.getFieldValue(rowData, columnDef)) ); - const builder = new CsvBuilder((this.props.exportFileName || this.props.title || 'data') + '.csv'); + return [columns, data]; + }; + + defaultExportCsv = () => { + const [columns, data] = this.getTableData(); + + const builder = new CsvBuilder( + (this.props.exportFileName || this.props.title || "data") + ".csv" + ); builder .setDelimeter(this.props.exportDelimiter) - .setColumns(columns.map(columnDef => columnDef.title)) + .setColumns(columns.map((columnDef) => columnDef.title)) .addRows(data) .exportFile(); - } + }; + + defaultExportPdf = () => { + const [columns, data] = this.getTableData(); + + let content = { + startY: 50, + head: [columns.map((columnDef) => columnDef.title)], + body: data, + }; + + const unit = "pt"; + const size = "A4"; + const orientation = "landscape"; + + const doc = new jsPDF(orientation, unit, size); + doc.setFontSize(15); + doc.text(this.props.title, 40, 40); + doc.autoTable(content); + doc.save( + (this.props.exportFileName || this.props.title || "data") + ".pdf" + ); + }; exportCsv = () => { if (this.props.exportCsv) { @@ -60,17 +95,34 @@ export class MTableToolbar extends React.Component { this.defaultExportCsv(); } this.setState({ exportButtonAnchorEl: null }); - } + }; + + exportPdf = () => { + if (this.props.exportPdf) { + this.props.exportPdf(this.props.columns, this.props.data); + } else { + this.defaultExportPdf(); + } + this.setState({ exportButtonAnchorEl: null }); + }; renderSearch() { - const localization = { ...MTableToolbar.defaultProps.localization, ...this.props.localization }; + const localization = { + ...MTableToolbar.defaultProps.localization, + ...this.props.localization, + }; if (this.props.search) { return ( this.onSearchChange(event.target.value)} + onChange={(event) => this.onSearchChange(event.target.value)} placeholder={localization.searchPlaceholder} variant={this.props.searchFieldVariant} InputProps={{ @@ -93,72 +145,84 @@ export class MTableToolbar extends React.Component { ), style: this.props.searchFieldStyle, inputProps: { - 'aria-label': "Search" - } + "aria-label": "Search", + }, }} /> ); - } - else { + } else { return null; } } renderDefaultActions() { - const localization = { ...MTableToolbar.defaultProps.localization, ...this.props.localization }; + const localization = { + ...MTableToolbar.defaultProps.localization, + ...this.props.localization, + }; const { classes } = this.props; return (
- {this.props.columnsButton && + {this.props.columnsButton && ( this.setState({ columnsButtonAnchorEl: event.currentTarget })} - aria-label={localization.showColumnsAriaLabel}> - + onClick={(event) => + this.setState({ columnsButtonAnchorEl: event.currentTarget }) + } + aria-label={localization.showColumnsAriaLabel} + > this.setState({ columnsButtonAnchorEl: null })}> - + onClose={() => this.setState({ columnsButtonAnchorEl: null })} + > + {localization.addRemoveColumns} - { - this.props.columns.map((col) => { - return ( -
  • - - this.props.onColumnsChanged(col, !col.hidden)} - /> - {col.title} - -
  • - ); - }) - } + {this.props.columns.map((col) => { + return ( +
  • + + + this.props.onColumnsChanged(col, !col.hidden) + } + /> + {col.title} + +
  • + ); + })}
    - } - {this.props.exportButton && + )} + {this.props.exportButton && ( this.setState({ exportButtonAnchorEl: event.currentTarget })} - aria-label={localization.exportAriaLabel}> + onClick={(event) => + this.setState({ exportButtonAnchorEl: event.currentTarget }) + } + aria-label={localization.exportAriaLabel} + > @@ -168,14 +232,22 @@ export class MTableToolbar extends React.Component { onClose={() => this.setState({ exportButtonAnchorEl: null })} > - {localization.exportName} + {localization.exportCSVName} + + + {localization.exportPDFName} - - } + )} - a.position === "toolbar")} components={this.props.components} /> + a.position === "toolbar") + } + components={this.props.components} + />
    ); @@ -184,7 +256,13 @@ export class MTableToolbar extends React.Component { renderSelectedActions() { return ( - a.position === "toolbarOnSelect")} data={this.props.selectedRows} components={this.props.components} /> + a.position === "toolbarOnSelect" + )} + data={this.props.selectedRows} + components={this.props.components} + /> ); } @@ -197,8 +275,7 @@ export class MTableToolbar extends React.Component {
    {this.props.selectedRows && this.props.selectedRows.length > 0 ? this.renderSelectedActions() - : this.renderDefaultActions() - } + : this.renderDefaultActions()}
    ); @@ -206,32 +283,60 @@ export class MTableToolbar extends React.Component { renderToolbarTitle(title) { const { classes } = this.props; - const toolBarTitle = (typeof title === 'string') ? {title} : title; + const toolBarTitle = + typeof title === "string" ? ( + + {title} + + ) : ( + title + ); - return ( -
    - {toolBarTitle} -
    - ); + return
    {toolBarTitle}
    ; } render() { const { classes } = this.props; - const localization = { ...MTableToolbar.defaultProps.localization, ...this.props.localization }; - const title = this.props.showTextRowsSelected && this.props.selectedRows && this.props.selectedRows.length > 0 ? (typeof localization.nRowsSelected === 'function' ? localization.nRowsSelected(this.props.selectedRows.length) : localization.nRowsSelected.replace('{0}', this.props.selectedRows.length)) : this.props.showTitle ? this.props.title : null; + const localization = { + ...MTableToolbar.defaultProps.localization, + ...this.props.localization, + }; + const title = + this.props.showTextRowsSelected && + this.props.selectedRows && + this.props.selectedRows.length > 0 + ? typeof localization.nRowsSelected === "function" + ? localization.nRowsSelected(this.props.selectedRows.length) + : localization.nRowsSelected.replace( + "{0}", + this.props.selectedRows.length + ) + : this.props.showTitle + ? this.props.title + : null; return ( - 0 })}> + 0, + })} + > {title && this.renderToolbarTitle(title)} - {this.props.searchFieldAlignment === 'left' && this.renderSearch()} - {this.props.toolbarButtonAlignment === 'left' && this.renderActions()} + {this.props.searchFieldAlignment === "left" && this.renderSearch()} + {this.props.toolbarButtonAlignment === "left" && this.renderActions()}
    - {this.props.searchFieldAlignment === 'right' && this.renderSearch()} - {this.props.toolbarButtonAlignment === 'right' && this.renderActions()} - + {this.props.searchFieldAlignment === "right" && this.renderSearch()} + {this.props.toolbarButtonAlignment === "right" && this.renderActions()} + ); } } @@ -241,26 +346,26 @@ MTableToolbar.defaultProps = { columns: [], columnsButton: false, localization: { - addRemoveColumns: 'Add or remove columns', - nRowsSelected: '{0} row(s) selected', - showColumnsTitle: 'Show Columns', - showColumnsAriaLabel: 'Show Columns', - exportTitle: 'Export', - exportAriaLabel: 'Export', - exportName: 'Export as CSV', - searchTooltip: 'Search', - searchPlaceholder: 'Search' + addRemoveColumns: "Add or remove columns", + nRowsSelected: "{0} row(s) selected", + showColumnsTitle: "Show Columns", + showColumnsAriaLabel: "Show Columns", + exportTitle: "Export", + exportAriaLabel: "Export", + exportName: "Export as CSV", + searchTooltip: "Search", + searchPlaceholder: "Search", }, search: true, showTitle: true, - searchText: '', + searchText: "", showTextRowsSelected: true, - toolbarButtonAlignment: 'right', + toolbarButtonAlignment: "right", searchAutoFocus: false, - searchFieldAlignment: 'right', - searchFieldVariant: 'standard', + searchFieldAlignment: "right", + searchFieldVariant: "standard", selectedRows: [], - title: 'No Title!' + title: "No Title!", }; MTableToolbar.propTypes = { @@ -290,41 +395,42 @@ MTableToolbar.propTypes = { exportDelimiter: PropTypes.string, exportFileName: PropTypes.string, exportCsv: PropTypes.func, + exportPdf: PropTypes.func, classes: PropTypes.object, - searchAutoFocus: PropTypes.bool + searchAutoFocus: PropTypes.bool, }; -export const styles = theme => ({ +export const styles = (theme) => ({ root: { - paddingRight: theme.spacing(1) + paddingRight: theme.spacing(1), }, highlight: - theme.palette.type === 'light' + theme.palette.type === "light" ? { - color: theme.palette.secondary.main, - backgroundColor: lighten(theme.palette.secondary.light, 0.85) - } + color: theme.palette.secondary.main, + backgroundColor: lighten(theme.palette.secondary.light, 0.85), + } : { - color: theme.palette.text.primary, - backgroundColor: theme.palette.secondary.dark - }, + color: theme.palette.text.primary, + backgroundColor: theme.palette.secondary.dark, + }, spacer: { - flex: '1 1 10%' + flex: "1 1 10%", }, actions: { color: theme.palette.text.secondary, }, title: { - overflow: 'hidden' + overflow: "hidden", }, searchField: { minWidth: 150, - paddingLeft: theme.spacing(2) + paddingLeft: theme.spacing(2), }, formControlLabel: { paddingLeft: theme.spacing(1), paddingRight: theme.spacing(1), - } + }, }); export default withStyles(styles)(MTableToolbar); diff --git a/src/default-props.js b/src/default-props.js index 94e6321b3..1bfae4761 100644 --- a/src/default-props.js +++ b/src/default-props.js @@ -1,21 +1,36 @@ -import React from 'react'; -import CircularProgress from '@material-ui/core/CircularProgress'; -import Icon from '@material-ui/core/Icon'; -import Paper from '@material-ui/core/Paper'; -import TablePagination from '@material-ui/core/TablePagination'; -import * as MComponents from './components'; -import PropTypes from 'prop-types'; -import { fade } from '@material-ui/core/styles/colorManipulator'; +import React from "react"; +import CircularProgress from "@material-ui/core/CircularProgress"; +import Icon from "@material-ui/core/Icon"; +import Paper from "@material-ui/core/Paper"; +import TablePagination from "@material-ui/core/TablePagination"; +import * as MComponents from "./components"; +import PropTypes from "prop-types"; +import { fade } from "@material-ui/core/styles/colorManipulator"; -const OverlayLoading = props => ( -
    -
    +const OverlayLoading = (props) => ( +
    +
    ); OverlayLoading.propTypes = { - theme: PropTypes.any + theme: PropTypes.any, }; const Container = (props) => ; @@ -39,98 +54,165 @@ export const defaultProps = { OverlayLoading: OverlayLoading, Pagination: TablePagination, Row: MComponents.MTableBodyRow, - Toolbar: MComponents.MTableToolbar + Toolbar: MComponents.MTableToolbar, }, data: [], icons: { /* eslint-disable react/display-name */ - Add: React.forwardRef((props, ref) => add_box), - Check: React.forwardRef((props, ref) => check), - Clear: React.forwardRef((props, ref) => clear), - Delete: React.forwardRef((props, ref) => delete_outline), - DetailPanel: React.forwardRef((props, ref) => chevron_right), - Edit: React.forwardRef((props, ref) => edit), - Export: React.forwardRef((props, ref) => save_alt), - Filter: React.forwardRef((props, ref) => filter_list), - FirstPage: React.forwardRef((props, ref) => first_page), - LastPage: React.forwardRef((props, ref) => last_page), - NextPage: React.forwardRef((props, ref) => chevron_right), - PreviousPage: React.forwardRef((props, ref) => chevron_left), - ResetSearch: React.forwardRef((props, ref) => clear), - Search: React.forwardRef((props, ref) => search), - SortArrow: React.forwardRef((props, ref) => arrow_downward), - ThirdStateCheck: React.forwardRef((props, ref) => remove), - ViewColumn: React.forwardRef((props, ref) => view_column) + Add: React.forwardRef((props, ref) => ( + + add_box + + )), + Check: React.forwardRef((props, ref) => ( + + check + + )), + Clear: React.forwardRef((props, ref) => ( + + clear + + )), + Delete: React.forwardRef((props, ref) => ( + + delete_outline + + )), + DetailPanel: React.forwardRef((props, ref) => ( + + chevron_right + + )), + Edit: React.forwardRef((props, ref) => ( + + edit + + )), + Export: React.forwardRef((props, ref) => ( + + save_alt + + )), + Filter: React.forwardRef((props, ref) => ( + + filter_list + + )), + FirstPage: React.forwardRef((props, ref) => ( + + first_page + + )), + LastPage: React.forwardRef((props, ref) => ( + + last_page + + )), + NextPage: React.forwardRef((props, ref) => ( + + chevron_right + + )), + PreviousPage: React.forwardRef((props, ref) => ( + + chevron_left + + )), + ResetSearch: React.forwardRef((props, ref) => ( + + clear + + )), + Search: React.forwardRef((props, ref) => ( + + search + + )), + SortArrow: React.forwardRef((props, ref) => ( + + arrow_downward + + )), + ThirdStateCheck: React.forwardRef((props, ref) => ( + + remove + + )), + ViewColumn: React.forwardRef((props, ref) => ( + + view_column + + )), /* eslint-enable react/display-name */ }, isLoading: false, - title: 'Table Title', + title: "Table Title", options: { actionsColumnIndex: 0, - addRowPosition: 'last', + addRowPosition: "last", columnsButton: false, - detailPanelType: 'multiple', + detailPanelType: "multiple", debounceInterval: 200, doubleHorizontalScroll: false, emptyRowsWhenPaging: true, exportAllData: false, exportButton: false, - exportDelimiter: ',', + exportDelimiter: ",", filtering: false, groupTitle: false, header: true, hideFilterIcons: false, - loadingType: 'overlay', - padding: 'default', + loadingType: "overlay", + padding: "default", searchAutoFocus: false, paging: true, pageSize: 5, pageSizeOptions: [5, 10, 20], - paginationType: 'normal', + paginationType: "normal", showEmptyDataSourceMessage: true, showFirstLastPageButtons: true, showSelectAllCheckbox: true, search: true, showTitle: true, showTextRowsSelected: true, - tableLayout: 'auto', - toolbarButtonAlignment: 'right', - searchFieldAlignment: 'right', + tableLayout: "auto", + toolbarButtonAlignment: "right", + searchFieldAlignment: "right", searchFieldStyle: {}, - searchFieldVariant: 'standard', + searchFieldVariant: "standard", selection: false, selectionProps: {}, sorting: true, toolbar: true, defaultExpanded: false, - detailPanelColumnAlignment: 'left', + detailPanelColumnAlignment: "left", thirdSortClick: true, - overflowY: 'auto', + overflowY: "auto", }, localization: { grouping: { - groupedBy: 'Grouped By:', - placeholder: 'Drag headers here to group by', + groupedBy: "Grouped By:", + placeholder: "Drag headers here to group by", }, pagination: { - labelDisplayedRows: '{from}-{to} of {count}', - labelRowsPerPage: 'Rows per page:', - labelRowsSelect: 'rows' + labelDisplayedRows: "{from}-{to} of {count}", + labelRowsPerPage: "Rows per page:", + labelRowsSelect: "rows", }, toolbar: {}, header: {}, body: { filterRow: {}, editRow: { - saveTooltip: 'Save', - cancelTooltip: 'Cancel', - deleteText: 'Are you sure you want to delete this row?', + saveTooltip: "Save", + cancelTooltip: "Cancel", + deleteText: "Are you sure you want to delete this row?", }, - addTooltip: 'Add', - deleteTooltip: 'Delete', - editTooltip: 'Edit' - } + addTooltip: "Add", + deleteTooltip: "Delete", + editTooltip: "Edit", + }, }, - style: { - } + style: {}, }; diff --git a/src/index.js b/src/index.js index 979f3a213..aea823f1d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,31 +1,32 @@ import "./utils/polyfill"; -import React from 'react'; -import { defaultProps } from './default-props'; -import { propTypes } from './prop-types'; -import MaterialTable from './material-table'; -import withStyles from '@material-ui/core/styles/withStyles'; +import React from "react"; +import { defaultProps } from "./default-props"; +import { propTypes } from "./prop-types"; +import MaterialTable from "./material-table"; +import withStyles from "@material-ui/core/styles/withStyles"; MaterialTable.defaultProps = defaultProps; MaterialTable.propTypes = propTypes; export { MaterialTable as MTable }; -const styles = theme => ({ +const styles = (theme) => ({ paginationRoot: { - width: '100%' + width: "100%", }, paginationToolbar: { padding: 0, - width: '100%' + width: "100%", }, paginationCaption: { - display: 'none' + display: "none", }, paginationSelectRoot: { - margin: 0 - } + margin: 0, + }, }); - -export default withStyles(styles, { withTheme: true })(props => ); -export * from './components'; +export default withStyles(styles, { withTheme: true })((props) => ( + +)); +export * from "./components"; diff --git a/src/material-table.js b/src/material-table.js index c37d7402b..76e99f267 100644 --- a/src/material-table.js +++ b/src/material-table.js @@ -1,17 +1,17 @@ /* eslint-disable no-unused-vars */ -import Table from '@material-ui/core/Table'; -import TableFooter from '@material-ui/core/TableFooter'; -import TableRow from '@material-ui/core/TableRow'; -import LinearProgress from '@material-ui/core/LinearProgress'; +import Table from "@material-ui/core/Table"; +import TableFooter from "@material-ui/core/TableFooter"; +import TableRow from "@material-ui/core/TableRow"; +import LinearProgress from "@material-ui/core/LinearProgress"; import DoubleScrollbar from "react-double-scrollbar"; -import * as React from 'react'; -import { MTablePagination, MTableSteppedPagination } from './components'; -import { DragDropContext, Droppable } from 'react-beautiful-dnd'; -import DataManager from './utils/data-manager'; -import { debounce } from 'debounce'; -import equal from 'fast-deep-equal'; -import { withStyles } from '@material-ui/core'; -import * as CommonValues from './utils/common-values'; +import * as React from "react"; +import { MTablePagination, MTableSteppedPagination } from "./components"; +import { DragDropContext, Droppable } from "react-beautiful-dnd"; +import DataManager from "./utils/data-manager"; +import { debounce } from "debounce"; +import equal from "fast-deep-equal"; +import { withStyles } from "@material-ui/core"; +import * as CommonValues from "./utils/common-values"; /* eslint-enable no-unused-vars */ @@ -30,41 +30,54 @@ export default class MaterialTable extends React.Component { ...renderState, query: { filters: renderState.columns - .filter(a => a.tableData.filterValue) - .map(a => ({ + .filter((a) => a.tableData.filterValue) + .map((a) => ({ column: a, operator: "=", - value: a.tableData.filterValue + value: a.tableData.filterValue, })), - orderBy: renderState.columns.find(a => a.tableData.id === renderState.orderBy), + orderBy: renderState.columns.find( + (a) => a.tableData.id === renderState.orderBy + ), orderDirection: renderState.orderDirection, page: 0, pageSize: calculatedProps.options.pageSize, search: renderState.searchText, - totalCount: 0 + totalCount: 0, }, showAddRow: false, - width: 0 + width: 0, }; this.tableContainerDiv = React.createRef(); } componentDidMount() { - this.setState({ ...this.dataManager.getRenderState(), width: this.tableContainerDiv.current.scrollWidth }, () => { - if (this.isRemoteData()) { - this.onQueryChange(this.state.query); + this.setState( + { + ...this.dataManager.getRenderState(), + width: this.tableContainerDiv.current.scrollWidth, + }, + () => { + if (this.isRemoteData()) { + this.onQueryChange(this.state.query); + } } - }); + ); } setDataManagerFields(props, isInit) { let defaultSortColumnIndex = -1; - let defaultSortDirection = ''; + let defaultSortDirection = ""; if (props && props.options.sorting !== false) { - defaultSortColumnIndex = props.columns.findIndex(a => a.defaultSort && a.sorting !== false); - defaultSortDirection = defaultSortColumnIndex > -1 ? props.columns[defaultSortColumnIndex].defaultSort : ''; + defaultSortColumnIndex = props.columns.findIndex( + (a) => a.defaultSort && a.sorting !== false + ); + defaultSortDirection = + defaultSortColumnIndex > -1 + ? props.columns[defaultSortColumnIndex].defaultSort + : ""; } this.dataManager.setColumns(props.columns); @@ -75,8 +88,7 @@ export default class MaterialTable extends React.Component { this.dataManager.changeApplySearch(false); this.dataManager.changeApplyFilters(false); this.dataManager.changeApplySort(false); - } - else { + } else { this.dataManager.changeApplySearch(true); this.dataManager.changeApplyFilters(true); this.dataManager.changeApplySort(true); @@ -84,19 +96,30 @@ export default class MaterialTable extends React.Component { } // If the columns changed and the defaultSorting differs from the current sorting, it will trigger a new sorting - const shouldReorder = (isInit || (defaultSortColumnIndex !== this.dataManager.orderBy && defaultSortDirection !== this.dataManager.orderDirection)); - shouldReorder && this.dataManager.changeOrder(defaultSortColumnIndex, defaultSortDirection); - isInit && this.dataManager.changeSearchText(props.options.searchText || ''); - isInit && this.dataManager.changeCurrentPage(props.options.initialPage ? props.options.initialPage : 0); - (isInit || this.isRemoteData()) && this.dataManager.changePageSize(props.options.pageSize); + const shouldReorder = + isInit || + (defaultSortColumnIndex !== this.dataManager.orderBy && + defaultSortDirection !== this.dataManager.orderDirection); + shouldReorder && + this.dataManager.changeOrder( + defaultSortColumnIndex, + defaultSortDirection + ); + isInit && this.dataManager.changeSearchText(props.options.searchText || ""); + isInit && + this.dataManager.changeCurrentPage( + props.options.initialPage ? props.options.initialPage : 0 + ); + (isInit || this.isRemoteData()) && + this.dataManager.changePageSize(props.options.pageSize); this.dataManager.changePaging(props.options.paging); isInit && this.dataManager.changeParentFunc(props.parentChildData); this.dataManager.changeDetailPanelType(props.options.detailPanelType); } cleanColumns(columns) { - return columns.map(col => { - const colClone = {...col}; + return columns.map((col) => { + const colClone = { ...col }; delete colClone.tableData; return colClone; }); @@ -109,8 +132,9 @@ export default class MaterialTable extends React.Component { const fixedPropsColumns = this.cleanColumns(this.props.columns); let propsChanged = !equal(fixedPrevColumns, fixedPropsColumns); - propsChanged = propsChanged || !equal(prevProps.options, this.props.options); - if(!this.isRemoteData()) { + propsChanged = + propsChanged || !equal(prevProps.options, this.props.options); + if (!this.isRemoteData()) { propsChanged = propsChanged || !equal(prevProps.data, this.props.data); } @@ -120,9 +144,15 @@ export default class MaterialTable extends React.Component { this.setState(this.dataManager.getRenderState()); } - const count = this.isRemoteData() ? this.state.query.totalCount : this.state.data.length; - const currentPage = this.isRemoteData() ? this.state.query.page : this.state.currentPage; - const pageSize = this.isRemoteData() ? this.state.query.pageSize : this.state.pageSize; + const count = this.isRemoteData() + ? this.state.query.totalCount + : this.state.data.length; + const currentPage = this.isRemoteData() + ? this.state.query.page + : this.state.currentPage; + const pageSize = this.isRemoteData() + ? this.state.query.pageSize + : this.state.pageSize; if (count <= pageSize * currentPage && currentPage !== 0) { this.onChangePage(null, Math.max(0, Math.ceil(count / pageSize) - 1)); @@ -131,42 +161,62 @@ export default class MaterialTable extends React.Component { getProps(props) { const calculatedProps = { ...(props || this.props) }; - calculatedProps.components = { ...MaterialTable.defaultProps.components, ...calculatedProps.components }; - calculatedProps.icons = { ...MaterialTable.defaultProps.icons, ...calculatedProps.icons }; - calculatedProps.options = { ...MaterialTable.defaultProps.options, ...calculatedProps.options }; + calculatedProps.components = { + ...MaterialTable.defaultProps.components, + ...calculatedProps.components, + }; + calculatedProps.icons = { + ...MaterialTable.defaultProps.icons, + ...calculatedProps.icons, + }; + calculatedProps.options = { + ...MaterialTable.defaultProps.options, + ...calculatedProps.options, + }; - const localization = { ...MaterialTable.defaultProps.localization.body, ...calculatedProps.localization.body }; + const localization = { + ...MaterialTable.defaultProps.localization.body, + ...calculatedProps.localization.body, + }; calculatedProps.actions = [...(calculatedProps.actions || [])]; if (calculatedProps.options.selection) - calculatedProps.actions = calculatedProps.actions.filter(a => a).map(action => { - if ( - (action.position === "auto") || - (action.isFreeAction === false) || - (action.position === undefined && action.isFreeAction === undefined) - ) - if (typeof action === "function") return { action: action, position: "toolbarOnSelect" }; - else return { ...action, position: "toolbarOnSelect" }; - else if (action.isFreeAction) - if (typeof action === "function") return { action: action, position: "toolbar" }; - else return { ...action, position: "toolbar" }; - else return action; - }); + calculatedProps.actions = calculatedProps.actions + .filter((a) => a) + .map((action) => { + if ( + action.position === "auto" || + action.isFreeAction === false || + (action.position === undefined && action.isFreeAction === undefined) + ) + if (typeof action === "function") + return { action: action, position: "toolbarOnSelect" }; + else return { ...action, position: "toolbarOnSelect" }; + else if (action.isFreeAction) + if (typeof action === "function") + return { action: action, position: "toolbar" }; + else return { ...action, position: "toolbar" }; + else return action; + }); else - calculatedProps.actions = calculatedProps.actions.filter(a => a).map(action => { - if ( - (action.position === "auto") || - (action.isFreeAction === false) || - (action.position === undefined && action.isFreeAction === undefined) - ) - if (typeof action === "function") return { action: action, position: "row" }; - else return { ...action, position: "row" }; - else if (action.isFreeAction) - if (typeof action === "function") return { action: action, position: "toolbar" }; - else return { ...action, position: "toolbar" }; - else return action; - }); + calculatedProps.actions = calculatedProps.actions + .filter((a) => a) + .map((action) => { + if ( + action.position === "auto" || + action.isFreeAction === false || + (action.position === undefined && action.isFreeAction === undefined) + ) + if (typeof action === "function") + return { action: action, position: "row" }; + else return { ...action, position: "row" }; + else if (action.isFreeAction) + if (typeof action === "function") + return { action: action, position: "toolbar" }; + else return { ...action, position: "toolbar" }; + else return action; + }); if (calculatedProps.editable) { if (calculatedProps.editable.onRowAdd) { @@ -174,44 +224,56 @@ export default class MaterialTable extends React.Component { icon: calculatedProps.icons.Add, tooltip: localization.addTooltip, position: "toolbar", - disabled: !!(this.dataManager.lastEditingRow), + disabled: !!this.dataManager.lastEditingRow, onClick: () => { this.dataManager.changeRowEditing(); this.setState({ ...this.dataManager.getRenderState(), - showAddRow: !this.state.showAddRow + showAddRow: !this.state.showAddRow, }); - } + }, }); } if (calculatedProps.editable.onRowUpdate) { - calculatedProps.actions.push(rowData => ({ + calculatedProps.actions.push((rowData) => ({ icon: calculatedProps.icons.Edit, - tooltip: calculatedProps.editable.editTooltip ? calculatedProps.editable.editTooltip(rowData) : localization.editTooltip, - disabled: calculatedProps.editable.isEditable && !calculatedProps.editable.isEditable(rowData), - hidden: calculatedProps.editable.isEditHidden && calculatedProps.editable.isEditHidden(rowData), + tooltip: calculatedProps.editable.editTooltip + ? calculatedProps.editable.editTooltip(rowData) + : localization.editTooltip, + disabled: + calculatedProps.editable.isEditable && + !calculatedProps.editable.isEditable(rowData), + hidden: + calculatedProps.editable.isEditHidden && + calculatedProps.editable.isEditHidden(rowData), onClick: (e, rowData) => { this.dataManager.changeRowEditing(rowData, "update"); this.setState({ ...this.dataManager.getRenderState(), - showAddRow: false + showAddRow: false, }); - } + }, })); } if (calculatedProps.editable.onRowDelete) { - calculatedProps.actions.push(rowData => ({ + calculatedProps.actions.push((rowData) => ({ icon: calculatedProps.icons.Delete, - tooltip: calculatedProps.editable.deleteTooltip ? calculatedProps.editable.deleteTooltip(rowData) :localization.deleteTooltip, - disabled: calculatedProps.editable.isDeletable && !calculatedProps.editable.isDeletable(rowData), - hidden: calculatedProps.editable.isDeleteHidden && calculatedProps.editable.isDeleteHidden(rowData), + tooltip: calculatedProps.editable.deleteTooltip + ? calculatedProps.editable.deleteTooltip(rowData) + : localization.deleteTooltip, + disabled: + calculatedProps.editable.isDeletable && + !calculatedProps.editable.isDeletable(rowData), + hidden: + calculatedProps.editable.isDeleteHidden && + calculatedProps.editable.isDeleteHidden(rowData), onClick: (e, rowData) => { this.dataManager.changeRowEditing(rowData, "delete"); this.setState({ ...this.dataManager.getRenderState(), - showAddRow: false + showAddRow: false, }); - } + }, })); } } @@ -219,102 +281,118 @@ export default class MaterialTable extends React.Component { return calculatedProps; } - isRemoteData = (props) => !Array.isArray((props || this.props).data) + isRemoteData = (props) => !Array.isArray((props || this.props).data); - isOutsidePageNumbers = (props) => (props.page !== undefined && props.totalCount !== undefined); + isOutsidePageNumbers = (props) => + props.page !== undefined && props.totalCount !== undefined; onAllSelected = (checked) => { this.dataManager.changeAllSelected(checked); - this.setState(this.dataManager.getRenderState(), () => this.onSelectionChange()); - } + this.setState(this.dataManager.getRenderState(), () => + this.onSelectionChange() + ); + }; onChangeColumnHidden = (column, hidden) => { this.dataManager.changeColumnHidden(column, hidden); this.setState(this.dataManager.getRenderState(), () => { - this.props.onChangeColumnHidden && this.props.onChangeColumnHidden(column, hidden); + this.props.onChangeColumnHidden && + this.props.onChangeColumnHidden(column, hidden); }); - } + }; onChangeGroupOrder = (groupedColumn) => { this.dataManager.changeGroupOrder(groupedColumn.tableData.id); this.setState(this.dataManager.getRenderState()); - } + }; onChangeOrder = (orderBy, orderDirection) => { - const newOrderBy = orderDirection === '' ? -1 : orderBy; + const newOrderBy = orderDirection === "" ? -1 : orderBy; this.dataManager.changeOrder(newOrderBy, orderDirection); if (this.isRemoteData()) { const query = { ...this.state.query }; query.page = 0; - query.orderBy = this.state.columns.find(a => a.tableData.id === newOrderBy); + query.orderBy = this.state.columns.find( + (a) => a.tableData.id === newOrderBy + ); query.orderDirection = orderDirection; this.onQueryChange(query, () => { - this.props.onOrderChange && this.props.onOrderChange(newOrderBy, orderDirection); + this.props.onOrderChange && + this.props.onOrderChange(newOrderBy, orderDirection); }); } else { this.setState(this.dataManager.getRenderState(), () => { - this.props.onOrderChange && this.props.onOrderChange(newOrderBy, orderDirection); + this.props.onOrderChange && + this.props.onOrderChange(newOrderBy, orderDirection); }); } - } + }; onChangePage = (event, page) => { if (this.isRemoteData()) { const query = { ...this.state.query }; query.page = page; this.onQueryChange(query, () => { - this.props.onChangePage && this.props.onChangePage(page); + this.props.onChangePage && + this.props.onChangePage(page, query.pageSize); }); - } - else { + } else { if (!this.isOutsidePageNumbers(this.props)) { this.dataManager.changeCurrentPage(page); } this.setState(this.dataManager.getRenderState(), () => { - this.props.onChangePage && this.props.onChangePage(page); + this.props.onChangePage && + this.props.onChangePage(page, this.state.query.pageSize); }); } - } + }; onChangeRowsPerPage = (event) => { const pageSize = event.target.value; this.dataManager.changePageSize(pageSize); - this.props.onChangePage && this.props.onChangePage(0); + this.props.onChangePage && this.props.onChangePage(0, pageSize); if (this.isRemoteData()) { const query = { ...this.state.query }; query.pageSize = event.target.value; query.page = 0; this.onQueryChange(query, () => { - this.props.onChangeRowsPerPage && this.props.onChangeRowsPerPage(pageSize); + this.props.onChangeRowsPerPage && + this.props.onChangeRowsPerPage(pageSize); }); - } - else { + } else { this.dataManager.changeCurrentPage(0); this.setState(this.dataManager.getRenderState(), () => { - this.props.onChangeRowsPerPage && this.props.onChangeRowsPerPage(pageSize); + this.props.onChangeRowsPerPage && + this.props.onChangeRowsPerPage(pageSize); }); } - } + }; - onDragEnd = result => { + onDragEnd = (result) => { if (!result || !result.source || !result.destination) return; this.dataManager.changeByDrag(result); this.setState(this.dataManager.getRenderState(), () => { - if (this.props.onColumnDragged && result.destination.droppableId === "headers" && - result.source.droppableId === "headers") { - this.props.onColumnDragged(result.source.index, result.destination.index); + if ( + this.props.onColumnDragged && + result.destination.droppableId === "headers" && + result.source.droppableId === "headers" + ) { + this.props.onColumnDragged( + result.source.index, + result.destination.index + ); } }); - } + }; onGroupExpandChanged = (path) => { this.dataManager.changeGroupExpand(path); this.setState(this.dataManager.getRenderState()); - } + }; onGroupRemoved = (groupedColumn, index) => { const result = { @@ -324,87 +402,101 @@ export default class MaterialTable extends React.Component { mode: "FLUID", reason: "DROP", source: { index, droppableId: "groups" }, - type: "DEFAULT" + type: "DEFAULT", }; this.dataManager.changeByDrag(result); this.setState(this.dataManager.getRenderState(), () => { - this.props.onGroupRemoved && this.props.onGroupRemoved(groupedColumn, index); + this.props.onGroupRemoved && + this.props.onGroupRemoved(groupedColumn, index); }); - } + }; onEditingApproved = (mode, newData, oldData) => { - if (mode === "add" && this.props.editable && this.props.editable.onRowAdd) { + if (mode === "add" && this.props.editable && this.props.editable.onRowAdd) { this.setState({ isLoading: true }, () => { - this.props.editable.onRowAdd(newData) - .then(result => { + this.props.editable + .onRowAdd(newData) + .then((result) => { this.setState({ isLoading: false, showAddRow: false }, () => { if (this.isRemoteData()) { this.onQueryChange(this.state.query); } }); }) - .catch(reason => { + .catch((reason) => { this.setState({ isLoading: false }); }); }); - } - else if(mode === "update" && this.props.editable && this.props.editable.onRowUpdate) { + } else if ( + mode === "update" && + this.props.editable && + this.props.editable.onRowUpdate + ) { this.setState({ isLoading: true }, () => { - this.props.editable.onRowUpdate(newData, oldData) - .then(result => { + this.props.editable + .onRowUpdate(newData, oldData) + .then((result) => { this.dataManager.changeRowEditing(oldData); - this.setState({ - isLoading: false, - ...this.dataManager.getRenderState() - }, () => { - if (this.isRemoteData()) { - this.onQueryChange(this.state.query); + this.setState( + { + isLoading: false, + ...this.dataManager.getRenderState(), + }, + () => { + if (this.isRemoteData()) { + this.onQueryChange(this.state.query); + } } - }); + ); }) - .catch(reason => { + .catch((reason) => { this.setState({ isLoading: false }); }); }); - - } - else if(mode === "delete" && this.props.editable && this.props.editable.onRowDelete) { + } else if ( + mode === "delete" && + this.props.editable && + this.props.editable.onRowDelete + ) { this.setState({ isLoading: true }, () => { - this.props.editable.onRowDelete(oldData) - .then(result => { + this.props.editable + .onRowDelete(oldData) + .then((result) => { this.dataManager.changeRowEditing(oldData); - this.setState({ - isLoading: false, - ...this.dataManager.getRenderState() - }, () => { - if (this.isRemoteData()) { - this.onQueryChange(this.state.query); + this.setState( + { + isLoading: false, + ...this.dataManager.getRenderState(), + }, + () => { + if (this.isRemoteData()) { + this.onQueryChange(this.state.query); + } } - }); + ); }) - .catch(reason => { + .catch((reason) => { this.setState({ isLoading: false }); }); }); } - } + }; onEditingCanceled = (mode, rowData) => { if (mode === "add") { - this.props.editable.onRowAddCancelled && this.props.editable.onRowAddCancelled(); + this.props.editable.onRowAddCancelled && + this.props.editable.onRowAddCancelled(); this.setState({ showAddRow: false }); - } - else if(mode === "update") { - this.props.editable.onRowUpdateCancelled && this.props.editable.onRowUpdateCancelled(); + } else if (mode === "update") { + this.props.editable.onRowUpdateCancelled && + this.props.editable.onRowUpdateCancelled(); this.dataManager.changeRowEditing(rowData); this.setState(this.dataManager.getRenderState()); - } - else if(mode === "delete") { + } else if (mode === "delete") { this.dataManager.changeRowEditing(rowData); this.setState(this.dataManager.getRenderState()); } - - } + }; onQueryChange = (query, callback) => { query = { ...this.state.query, ...query }; @@ -413,28 +505,33 @@ export default class MaterialTable extends React.Component { query.totalCount = result.totalCount; query.page = result.page; this.dataManager.setData(result.data); - this.setState({ - isLoading: false, - ...this.dataManager.getRenderState(), - query - }, () => { - callback && callback(); - }); + this.setState( + { + isLoading: false, + ...this.dataManager.getRenderState(), + query, + }, + () => { + callback && callback(); + } + ); }); }); - } + }; onRowSelected = (event, path, dataClicked) => { this.dataManager.changeRowSelected(event.target.checked, path); - this.setState(this.dataManager.getRenderState(), () => this.onSelectionChange(dataClicked)); - } + this.setState(this.dataManager.getRenderState(), () => + this.onSelectionChange(dataClicked) + ); + }; onSelectionChange = (dataClicked) => { if (this.props.onSelectionChange) { const selectedRows = []; - const findSelecteds = list => { - list.forEach(row => { + const findSelecteds = (list) => { + list.forEach((row) => { if (row.tableData.checked) { selectedRows.push(row); } @@ -446,7 +543,7 @@ export default class MaterialTable extends React.Component { findSelecteds(this.state.originalData); this.props.onSelectionChange(selectedRows, dataClicked); } - } + }; onSearchChangeDebounce = debounce((searchText) => { if (this.isRemoteData()) { @@ -455,69 +552,74 @@ export default class MaterialTable extends React.Component { query.search = searchText; this.onQueryChange(query); - } - else { + } else { this.setState(this.dataManager.getRenderState(), () => { this.props.onSearchChange && this.props.onSearchChange(searchText); }); } - }, this.props.options.debounceInterval) + }, this.props.options.debounceInterval); onFilterChange = (columnId, value) => { this.dataManager.changeFilterValue(columnId, value); this.setState({}, this.onFilterChangeDebounce); - } + }; onFilterChangeDebounce = debounce(() => { if (this.isRemoteData()) { const query = { ...this.state.query }; query.page = 0; query.filters = this.state.columns - .filter(a => a.tableData.filterValue) - .map(a => ({ + .filter((a) => a.tableData.filterValue) + .map((a) => ({ column: a, operator: "=", - value: a.tableData.filterValue + value: a.tableData.filterValue, })); this.onQueryChange(query); - } - else { + } else { this.setState(this.dataManager.getRenderState(), () => { if (this.props.onFilterChange) { const appliedFilters = this.state.columns - .filter(a => a.tableData.filterValue) - .map(a => ({ + .filter((a) => a.tableData.filterValue) + .map((a) => ({ column: a, operator: "=", - value: a.tableData.filterValue + value: a.tableData.filterValue, })); this.props.onFilterChange(appliedFilters); } }); } - }, this.props.options.debounceInterval) + }, this.props.options.debounceInterval); onTreeExpandChanged = (path, data) => { this.dataManager.changeTreeExpand(path); this.setState(this.dataManager.getRenderState(), () => { - this.props.onTreeExpandChange && this.props.onTreeExpandChange(data, data.tableData.isTreeExpanded); + this.props.onTreeExpandChange && + this.props.onTreeExpandChange(data, data.tableData.isTreeExpanded); }); - } + }; onToggleDetailPanel = (path, render) => { this.dataManager.changeDetailPanelVisibility(path, render); this.setState(this.dataManager.getRenderState()); - } + }; renderFooter() { const props = this.getProps(); if (props.options.paging) { - const localization = { ...MaterialTable.defaultProps.localization.pagination, ...this.props.localization.pagination }; + const localization = { + ...MaterialTable.defaultProps.localization.pagination, + ...this.props.localization.pagination, + }; const isOutsidePageNumbers = this.isOutsidePageNumbers(props); const currentPage = isOutsidePageNumbers - ? Math.min(props.page, Math.floor(props.totalCount / this.state.pageSize)) + ? Math.min( + props.page, + Math.floor(props.totalCount / this.state.pageSize) + ) : this.state.currentPage; const totalCount = isOutsidePageNumbers ? props.totalCount @@ -525,7 +627,7 @@ export default class MaterialTable extends React.Component { return ( - +
    {value + ' ' + localization.labelRowsSelect + ' '}
    + renderValue: (value) => ( +
    + {value + " " + localization.labelRowsSelect + " "} +
    + ), }} page={this.isRemoteData() ? this.state.query.page : currentPage} onChangePage={this.onChangePage} onChangeRowsPerPage={this.onChangeRowsPerPage} - ActionsComponent={(subProps) => props.options.paginationType === 'normal' ? - : - } - labelDisplayedRows={(row) => localization.labelDisplayedRows.replace('{from}', row.from).replace('{to}', row.to).replace('{count}', row.count)} + ActionsComponent={(subProps) => + props.options.paginationType === "normal" ? ( + + ) : ( + + ) + } + labelDisplayedRows={(row) => + localization.labelDisplayedRows + .replace("{from}", row.from) + .replace("{to}", row.to) + .replace("{count}", row.count) + } labelRowsPerPage={localization.labelRowsPerPage} />
    @@ -560,24 +694,44 @@ export default class MaterialTable extends React.Component { } renderTable = (props) => ( -
    - {props.options.header && +
    + {props.options.header && ( col.tableData.groupOrder > -1).length > 0) ? this.state.groupedDataLength : this.state.data.length - ) + props.parentChildData + ? this.state.treefiedDataLength + : this.state.columns.filter( + (col) => col.tableData.groupOrder > -1 + ).length > 0 + ? this.state.groupedDataLength + : this.state.data.length } hasDetailPanel={!!props.detailPanel} detailPanelColumnAlignment={props.options.detailPanelColumnAlignment} - showActionsColumn={props.actions && props.actions.filter(a => a.position === "row" || typeof a === "function").length > 0} + showActionsColumn={ + props.actions && + props.actions.filter( + (a) => a.position === "row" || typeof a === "function" + ).length > 0 + } showSelectAllCheckbox={props.options.showSelectAllCheckbox} orderBy={this.state.orderBy} orderDirection={this.state.orderDirection} @@ -592,7 +746,7 @@ export default class MaterialTable extends React.Component { treeDataMaxLevel={this.state.treeDataMaxLevel} options={props.options} /> - } + )}
    - ) + ); getColumnsWidth = (props, count) => { let result = []; const actionsWidth = CommonValues.actionsColumnWidth(props); if (actionsWidth > 0) { - if (count > 0 && props.options.actionsColumnIndex >= 0 && props.options.actionsColumnIndex < count) { + if ( + count > 0 && + props.options.actionsColumnIndex >= 0 && + props.options.actionsColumnIndex < count + ) { result.push(actionsWidth + "px"); - } - else if (count < 0 && props.options.actionsColumnIndex < 0 && props.options.actionsColumnIndex >= count) { + } else if ( + count < 0 && + props.options.actionsColumnIndex < 0 && + props.options.actionsColumnIndex >= count + ) { result.push(actionsWidth + "px"); } } if (props.options.selection) { - const selectionWidth = CommonValues.selectionMaxWidth(props, this.state.treeDataMaxLevel); + const selectionWidth = CommonValues.selectionMaxWidth( + props, + this.state.treeDataMaxLevel + ); result.push(selectionWidth + "px"); } for (let i = 0; i < Math.abs(count) && i < props.columns.length; i++) { const colDef = props.columns[i >= 0 ? i : props.columns.length - 1 - i]; - if(colDef.tableData) { + if (colDef.tableData) { if (typeof colDef.tableData.width === "number") { result.push(colDef.tableData.width + "px"); - } - else { + } else { result.push(colDef.tableData.width); } } } - return "calc(" + result.join(' + ') + ")"; - } + return "calc(" + result.join(" + ") + ")"; + }; render() { const props = this.getProps(); return ( - - - {props.options.toolbar && + + + {props.options.toolbar && ( 0 ? this.state.originalData.filter(a => { return a.tableData.checked }) : []} + selectedRows={ + this.state.selectedCount > 0 + ? this.state.originalData.filter((a) => { + return a.tableData.checked; + }) + : [] + } columns={this.state.columns} columnsButton={props.options.columnsButton} icons={props.icons} @@ -675,6 +854,7 @@ export default class MaterialTable extends React.Component { exportDelimiter={props.options.exportDelimiter} exportFileName={props.options.exportFileName} exportCsv={props.options.exportCsv} + exportPdf={props.options.exportPdf} getFieldValue={this.dataManager.getFieldValue} data={this.state.data} renderData={this.state.renderData} @@ -691,71 +871,144 @@ export default class MaterialTable extends React.Component { onSearchChanged={this.onSearchChangeDebounce} dataManager={this.dataManager} onColumnsChanged={this.onChangeColumnHidden} - localization={{ ...MaterialTable.defaultProps.localization.toolbar, ...this.props.localization.toolbar }} + localization={{ + ...MaterialTable.defaultProps.localization.toolbar, + ...this.props.localization.toolbar, + }} /> - } - {props.options.grouping && + )} + {props.options.grouping && ( col.tableData.groupOrder > -1) - .sort((col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder) - } + .filter((col) => col.tableData.groupOrder > -1) + .sort( + (col1, col2) => + col1.tableData.groupOrder - col2.tableData.groupOrder + )} onSortChanged={this.onChangeGroupOrder} onGroupRemoved={this.onGroupRemoved} /> - } + )} {(provided, snapshot) => { const table = this.renderTable(props); return (
    -
    - - {this.state.width && props.options.fixedColumns && props.options.fixedColumns.right ? -
    -
    +
    + {this.state.width && + props.options.fixedColumns && + props.options.fixedColumns.right ? ( +
    +
    {table}
    -
    : null - } - -
    - {table} -
    - - {this.state.width && props.options.fixedColumns && props.options.fixedColumns.left ? -
    -
    +
    + ) : null} + +
    {table}
    + + {this.state.width && + props.options.fixedColumns && + props.options.fixedColumns.left ? ( +
    +
    {table}
    -
    : null - } - +
    + ) : null}
    {provided.placeholder}
    ); }} - - {(this.state.isLoading || props.isLoading) && props.options.loadingType === "linear" && -
    -
    - + {(this.state.isLoading || props.isLoading) && + props.options.loadingType === "linear" && ( +
    +
    + +
    -
    - } + )} {this.renderFooter()} - {(this.state.isLoading || props.isLoading) && props.options.loadingType === 'overlay' && -
    - -
    - } + {(this.state.isLoading || props.isLoading) && + props.options.loadingType === "overlay" && ( +
    + +
    + )} ); @@ -764,32 +1017,29 @@ export default class MaterialTable extends React.Component { var style = () => ({ horizontalScrollContainer: { - '& ::-webkit-scrollbar': { - '-webkit-appearance': 'none' + "& ::-webkit-scrollbar": { + "-webkit-appearance": "none", }, - '& ::-webkit-scrollbar:horizontal': { - height: 8 + "& ::-webkit-scrollbar:horizontal": { + height: 8, }, - '& ::-webkit-scrollbar-thumb': { + "& ::-webkit-scrollbar-thumb": { borderRadius: 4, - border: '2px solid white', - backgroundColor: 'rgba(0, 0, 0, .3)' - } - } + border: "2px solid white", + backgroundColor: "rgba(0, 0, 0, .3)", + }, + }, }); - const ScrollBar = withStyles(style)(({ double, children, classes }) => { if (double) { + return {children}; + } else { return ( - - {children} - - ); - } - else { - return ( -
    +
    {children}
    ); diff --git a/src/prop-types.js b/src/prop-types.js index 972cec5c9..cbd440883 100644 --- a/src/prop-types.js +++ b/src/prop-types.js @@ -1,74 +1,169 @@ -import PropTypes from 'prop-types'; +import PropTypes from "prop-types"; const RefComponent = PropTypes.shape({ current: PropTypes.element }); const StyledComponent = PropTypes.shape({ classes: PropTypes.object, - innerRef: RefComponent + innerRef: RefComponent, }); export const propTypes = { - actions: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ - icon: PropTypes.oneOfType([PropTypes.element, PropTypes.func, PropTypes.string, RefComponent]).isRequired, - isFreeAction: PropTypes.bool, - position: PropTypes.oneOf(['auto', 'toolbar', 'toolbarOnSelect', 'row']), - tooltip: PropTypes.string, - onClick: PropTypes.func.isRequired, - iconProps: PropTypes.object, - disabled: PropTypes.bool, - hidden: PropTypes.bool, - })])), - columns: PropTypes.arrayOf(PropTypes.shape({ - cellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), - currencySetting: PropTypes.shape({ - locale: PropTypes.string, - currencyCode: PropTypes.string, - minimumFractionDigits: PropTypes.number, - maximumFractionDigits: PropTypes.number - }), - customFilterAndSearch: PropTypes.func, - customSort: PropTypes.func, - defaultFilter: PropTypes.any, - defaultSort: PropTypes.oneOf(['asc', 'desc']), - editComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), - emptyValue: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]), - export: PropTypes.bool, - field: PropTypes.string, - filtering: PropTypes.bool, - filterCellStyle: PropTypes.object, - filterPlaceholder: PropTypes.string, - filterComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), - grouping: PropTypes.bool, - headerStyle: PropTypes.object, - hidden: PropTypes.bool, - hideFilterIcon: PropTypes.bool, - initialEditValue: PropTypes.any, - lookup: PropTypes.object, - editable: PropTypes.oneOfType([PropTypes.func, PropTypes.oneOf(['always', 'onUpdate', 'onAdd', 'never'])]), - removable: PropTypes.bool, - render: PropTypes.func, - searchable: PropTypes.bool, - sorting: PropTypes.bool, - title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), - type: PropTypes.oneOf(['string', 'boolean', 'numeric', 'date', 'datetime', 'time', 'currency']) - })).isRequired, + actions: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + icon: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + PropTypes.string, + RefComponent, + ]).isRequired, + isFreeAction: PropTypes.bool, + position: PropTypes.oneOf([ + "auto", + "toolbar", + "toolbarOnSelect", + "row", + ]), + tooltip: PropTypes.string, + onClick: PropTypes.func.isRequired, + iconProps: PropTypes.object, + disabled: PropTypes.bool, + hidden: PropTypes.bool, + }), + ]) + ), + columns: PropTypes.arrayOf( + PropTypes.shape({ + cellStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), + currencySetting: PropTypes.shape({ + locale: PropTypes.string, + currencyCode: PropTypes.string, + minimumFractionDigits: PropTypes.number, + maximumFractionDigits: PropTypes.number, + }), + customFilterAndSearch: PropTypes.func, + customSort: PropTypes.func, + defaultFilter: PropTypes.any, + defaultSort: PropTypes.oneOf(["asc", "desc"]), + editComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), + emptyValue: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.node, + PropTypes.func, + ]), + export: PropTypes.bool, + field: PropTypes.string, + filtering: PropTypes.bool, + filterCellStyle: PropTypes.object, + filterPlaceholder: PropTypes.string, + filterComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), + grouping: PropTypes.bool, + headerStyle: PropTypes.object, + hidden: PropTypes.bool, + hideFilterIcon: PropTypes.bool, + initialEditValue: PropTypes.any, + lookup: PropTypes.object, + editable: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.oneOf(["always", "onUpdate", "onAdd", "never"]), + ]), + removable: PropTypes.bool, + render: PropTypes.func, + searchable: PropTypes.bool, + sorting: PropTypes.bool, + title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), + type: PropTypes.oneOf([ + "string", + "boolean", + "numeric", + "date", + "datetime", + "time", + "currency", + ]), + }) + ).isRequired, components: PropTypes.shape({ - Action: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Actions: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Body: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Cell: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Container: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - EditField: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - EditRow: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - FilterRow: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Groupbar: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - GroupRow: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Header: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - OverlayLoading: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Pagination: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Row: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]), - Toolbar: PropTypes.oneOfType([PropTypes.element, PropTypes.func, StyledComponent]) + Action: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Actions: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Body: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Cell: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Container: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + EditField: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + EditRow: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + FilterRow: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Groupbar: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + GroupRow: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Header: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + OverlayLoading: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Pagination: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Row: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), + Toolbar: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + StyledComponent, + ]), }), - data: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.func]).isRequired, + data: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.object), + PropTypes.func, + ]).isRequired, editable: PropTypes.shape({ isEditable: PropTypes.func, isDeletable: PropTypes.func, @@ -78,40 +173,120 @@ export const propTypes = { onRowAddCancelled: PropTypes.func, onRowUpdateCancelled: PropTypes.func, isEditHidden: PropTypes.func, - isDeleteHidden: PropTypes.func + isDeleteHidden: PropTypes.func, }), detailPanel: PropTypes.oneOfType([ PropTypes.func, - PropTypes.arrayOf(PropTypes.oneOfType([ - PropTypes.func, - PropTypes.shape({ - disabled: PropTypes.bool, - icon: PropTypes.oneOfType([PropTypes.element, PropTypes.func, PropTypes.string, RefComponent]), - openIcon: PropTypes.oneOfType([PropTypes.element, PropTypes.func, PropTypes.string, RefComponent]), - tooltip: PropTypes.string, - render: PropTypes.func.isRequired - }) - ])) + PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({ + disabled: PropTypes.bool, + icon: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + PropTypes.string, + RefComponent, + ]), + openIcon: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + PropTypes.string, + RefComponent, + ]), + tooltip: PropTypes.string, + render: PropTypes.func.isRequired, + }), + ]) + ), ]), icons: PropTypes.shape({ Add: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Check: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Clear: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Delete: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - DetailPanel: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Edit: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Export: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Filter: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - FirstPage: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - LastPage: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - NextPage: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - PreviousPage: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Refresh: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - ResetSearch: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - Search: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - SortArrow: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - ThirdStateCheck: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), - ViewColumn: PropTypes.oneOfType([PropTypes.element, PropTypes.func, RefComponent]), + Check: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Clear: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Delete: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + DetailPanel: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Edit: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Export: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Filter: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + FirstPage: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + LastPage: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + NextPage: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + PreviousPage: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Refresh: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + ResetSearch: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + Search: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + SortArrow: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + ThirdStateCheck: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), + ViewColumn: PropTypes.oneOfType([ + PropTypes.element, + PropTypes.func, + RefComponent, + ]), }), isLoading: PropTypes.bool, title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]), @@ -120,11 +295,11 @@ export const propTypes = { editCellStyle: PropTypes.object, detailPanelColumnStyle: PropTypes.object, actionsColumnIndex: PropTypes.number, - addRowPosition: PropTypes.oneOf(['first', 'last']), + addRowPosition: PropTypes.oneOf(["first", "last"]), columnsButton: PropTypes.bool, defaultExpanded: PropTypes.bool | PropTypes.func, debounceInterval: PropTypes.number, - detailPanelType: PropTypes.oneOf(['single', 'multiple']), + detailPanelType: PropTypes.oneOf(["single", "multiple"]), doubleHorizontalScroll: PropTypes.bool, emptyRowsWhenPaging: PropTypes.bool, exportAllData: PropTypes.bool, @@ -141,27 +316,28 @@ export const propTypes = { initialPage: PropTypes.number, maxBodyHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), minBodyHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - loadingType: PropTypes.oneOf(['overlay', 'linear']), - overflowY: PropTypes.oneOf(['visible', 'hidden', 'scroll', 'auto', 'initial', 'inherit']), - padding: PropTypes.oneOf(['default', 'dense']), + loadingType: PropTypes.oneOf(["overlay", "linear"]), + overflowY: PropTypes.oneOf([ + "visible", + "hidden", + "scroll", + "auto", + "initial", + "inherit", + ]), + padding: PropTypes.oneOf(["default", "dense"]), paging: PropTypes.bool, pageSize: PropTypes.number, - pageSizeOptions: PropTypes.arrayOf(PropTypes.oneOfType([ - PropTypes.number, - PropTypes.shape({ - value: PropTypes.number, - label: PropTypes.string - }) - ])), - paginationType: PropTypes.oneOf(['normal', 'stepped']), + pageSizeOptions: PropTypes.arrayOf(PropTypes.number), + paginationType: PropTypes.oneOf(["normal", "stepped"]), rowStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), search: PropTypes.bool, searchText: PropTypes.string, - toolbarButtonAlignment: PropTypes.oneOf(['left', 'right']), - searchFieldAlignment: PropTypes.oneOf(['left', 'right']), + toolbarButtonAlignment: PropTypes.oneOf(["left", "right"]), + searchFieldAlignment: PropTypes.oneOf(["left", "right"]), searchFieldStyle: PropTypes.object, searchAutoFocus: PropTypes.bool, - searchFieldVariant: PropTypes.oneOf( ['standard', 'filled', 'outlined']), + searchFieldVariant: PropTypes.oneOf(["standard", "filled", "outlined"]), selection: PropTypes.bool, selectionProps: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), showEmptyDataSourceMessage: PropTypes.bool, @@ -171,17 +347,17 @@ export const propTypes = { showTextRowsSelected: PropTypes.bool, sorting: PropTypes.bool, toolbar: PropTypes.bool, - thirdSortClick: PropTypes.bool + thirdSortClick: PropTypes.bool, }), localization: PropTypes.shape({ grouping: PropTypes.shape({ groupedBy: PropTypes.string, - placeholder: PropTypes.string + placeholder: PropTypes.string, }), pagination: PropTypes.object, toolbar: PropTypes.object, header: PropTypes.object, - body: PropTypes.object + body: PropTypes.object, }), initialFormData: PropTypes.object, onSearchChange: PropTypes.func, @@ -199,5 +375,5 @@ export const propTypes = { tableRef: PropTypes.any, style: PropTypes.object, page: PropTypes.number, - totalCount: PropTypes.number + totalCount: PropTypes.number, }; diff --git a/src/utils/common-values.js b/src/utils/common-values.js index 46f206627..dab286251 100644 --- a/src/utils/common-values.js +++ b/src/utils/common-values.js @@ -1,5 +1,10 @@ -export const elementSize = (props) => props.options.padding === 'default' ? 'medium' : 'small'; -export const baseIconSize = (props) => elementSize(props) === "medium" ? 48 : 32; -export const rowActions = (props) => props.actions.filter(a => a.position === "row" || typeof a === "function"); -export const actionsColumnWidth = (props) => rowActions(props).length * baseIconSize(props); -export const selectionMaxWidth = (props, maxTreeLevel) => baseIconSize(props) + 9 * maxTreeLevel; \ No newline at end of file +export const elementSize = (props) => + props.options.padding === "default" ? "medium" : "small"; +export const baseIconSize = (props) => + elementSize(props) === "medium" ? 48 : 32; +export const rowActions = (props) => + props.actions.filter((a) => a.position === "row" || typeof a === "function"); +export const actionsColumnWidth = (props) => + rowActions(props).length * baseIconSize(props); +export const selectionMaxWidth = (props, maxTreeLevel) => + baseIconSize(props) + 9 * maxTreeLevel; diff --git a/src/utils/data-manager.js b/src/utils/data-manager.js index 774790cde..12c5237e2 100644 --- a/src/utils/data-manager.js +++ b/src/utils/data-manager.js @@ -1,26 +1,26 @@ -import formatDate from 'date-fns/format'; -import { byString } from './'; +import formatDate from "date-fns/format"; +import { byString } from "./"; export default class DataManager { applyFilters = false; applySearch = false; applySort = false; currentPage = 0; - detailPanelType = 'multiple' + detailPanelType = "multiple"; lastDetailPanelRow = undefined; lastEditingRow = undefined; orderBy = -1; - orderDirection = ''; + orderDirection = ""; pageSize = 5; paging = true; parentFunc = null; - searchText = ''; + searchText = ""; selectedCount = 0; treefiedDataLength = 0; treeDataMaxLevel = 0; groupedDataLength = 0; defaultExpanded = false; - + data = []; columns = []; @@ -41,8 +41,7 @@ export default class DataManager { rootGroupsIndex = {}; - constructor() { - } + constructor() {} setData(data) { this.selectedCount = 0; @@ -58,8 +57,10 @@ export default class DataManager { this.filtered = false; } - setColumns(columns) { - const undefinedWidthColumns = columns.filter(c => c.width === undefined && !c.hidden); + setColumns(columns) { + const undefinedWidthColumns = columns.filter( + (c) => c.width === undefined && !c.hidden + ); let usedWidth = ["0px"]; this.columns = columns.map((columnDef, index) => { @@ -67,17 +68,16 @@ export default class DataManager { columnOrder: index, filterValue: columnDef.defaultFilter, groupOrder: columnDef.defaultGroupOrder, - groupSort: columnDef.defaultGroupSort || 'asc', - width: columnDef.width, + groupSort: columnDef.defaultGroupSort || "asc", + width: columnDef.width, ...columnDef.tableData, id: index, }; - if(columnDef.width !== undefined) { - if(typeof columnDef.width === "number") { + if (columnDef.width !== undefined) { + if (typeof columnDef.width === "number") { usedWidth.push(columnDef.width + "px"); - } - else { + } else { usedWidth.push(columnDef.width); } } @@ -85,8 +85,8 @@ export default class DataManager { return columnDef; }); - usedWidth = "(" + usedWidth.join(' + ') + ")"; - undefinedWidthColumns.forEach(columnDef => { + usedWidth = "(" + usedWidth.join(" + ") + ")"; + undefinedWidthColumns.forEach((columnDef) => { columnDef.tableData.width = `calc((100% - ${usedWidth}) / ${undefinedWidthColumns.length})`; }); } @@ -139,9 +139,9 @@ export default class DataManager { rowData.tableData.checked = checked; this.selectedCount = this.selectedCount + (checked ? 1 : -1); - const checkChildRows = rowData => { + const checkChildRows = (rowData) => { if (rowData.tableData.childRows) { - rowData.tableData.childRows.forEach(childRow => { + rowData.tableData.childRows.forEach((childRow) => { if (childRow.tableData.checked !== checked) { childRow.tableData.checked = checked; this.selectedCount = this.selectedCount + (checked ? 1 : -1); @@ -159,14 +159,19 @@ export default class DataManager { changeDetailPanelVisibility(path, render) { const rowData = this.findDataByPath(this.sortedData, path); - if ((rowData.tableData.showDetailPanel || '').toString() === render.toString()) { + if ( + (rowData.tableData.showDetailPanel || "").toString() === render.toString() + ) { rowData.tableData.showDetailPanel = undefined; - } - else { + } else { rowData.tableData.showDetailPanel = render; } - if (this.detailPanelType === 'single' && this.lastDetailPanelRow && this.lastDetailPanelRow != rowData) { + if ( + this.detailPanelType === "single" && + this.lastDetailPanelRow && + this.lastDetailPanelRow != rowData + ) { this.lastDetailPanelRow.tableData.showDetailPanel = undefined; } @@ -194,12 +199,10 @@ export default class DataManager { if (mode) { this.lastEditingRow = rowData; - } - else { + } else { this.lastEditingRow = undefined; } - } - else if (this.lastEditingRow) { + } else if (this.lastEditingRow) { this.lastEditingRow.tableData.editing = undefined; this.lastEditingRow = undefined; } @@ -209,12 +212,11 @@ export default class DataManager { let selectedCount = 0; if (this.isDataType("group")) { const setCheck = (data) => { - data.forEach(element => { + data.forEach((element) => { if (element.groups.length > 0) { setCheck(element.groups); - } - else { - element.data.forEach(d => { + } else { + element.data.forEach((d) => { d.tableData.checked = d.tableData.disabled ? false : checked; selectedCount++; }); @@ -223,9 +225,8 @@ export default class DataManager { }; setCheck(this.groupedData); - } - else { - this.searchedData.map(row => { + } else { + this.searchedData.map((row) => { row.tableData.checked = row.tableData.disabled ? false : checked; return row; }); @@ -244,19 +245,18 @@ export default class DataManager { } changeGroupOrder(columnId) { - const column = this.columns.find(c => c.tableData.id === columnId); + const column = this.columns.find((c) => c.tableData.id === columnId); - if (column.tableData.groupSort === 'asc') { - column.tableData.groupSort = 'desc'; - } - else { - column.tableData.groupSort = 'asc'; + if (column.tableData.groupSort === "asc") { + column.tableData.groupSort = "desc"; + } else { + column.tableData.groupSort = "asc"; } this.sorted = false; } - changeColumnHidden(column, hidden) { + changeColumnHidden(column, hidden) { column.hidden = hidden; } @@ -273,11 +273,15 @@ export default class DataManager { let start = 0; let groups = this.columns - .filter(col => col.tableData.groupOrder > -1) - .sort((col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder); - + .filter((col) => col.tableData.groupOrder > -1) + .sort( + (col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder + ); - if (result.destination.droppableId === "groups" && result.source.droppableId === "groups") { + if ( + result.destination.droppableId === "groups" && + result.source.droppableId === "groups" + ) { start = Math.min(result.destination.index, result.source.index); const end = Math.max(result.destination.index, result.source.index); @@ -287,38 +291,51 @@ export default class DataManager { // Take last and add as first const last = groups.pop(); groups.unshift(last); - } - else { + } else { // Take first and add as last const last = groups.shift(); groups.push(last); } - } - else if (result.destination.droppableId === "groups" && result.source.droppableId === "headers") { - const newGroup = this.columns.find(c => c.tableData.id == result.draggableId); + } else if ( + result.destination.droppableId === "groups" && + result.source.droppableId === "headers" + ) { + const newGroup = this.columns.find( + (c) => c.tableData.id == result.draggableId + ); if (newGroup.grouping === false || !newGroup.field) { return; } groups.splice(result.destination.index, 0, newGroup); - } - else if (result.destination.droppableId === "headers" && result.source.droppableId === "groups") { - const removeGroup = this.columns.find(c => c.tableData.id == result.draggableId); + } else if ( + result.destination.droppableId === "headers" && + result.source.droppableId === "groups" + ) { + const removeGroup = this.columns.find( + (c) => c.tableData.id == result.draggableId + ); removeGroup.tableData.groupOrder = undefined; groups.splice(result.source.index, 1); - } - else if (result.destination.droppableId === "headers" && result.source.droppableId === "headers") { + } else if ( + result.destination.droppableId === "headers" && + result.source.droppableId === "headers" + ) { start = Math.min(result.destination.index, result.source.index); const end = Math.max(result.destination.index, result.source.index); // get the effective start and end considering hidden columns const sorted = this.columns - .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) - .filter(column => column.tableData.groupOrder === undefined); + .sort((a, b) => a.tableData.columnOrder - b.tableData.columnOrder) + .filter((column) => column.tableData.groupOrder === undefined); let numHiddenBeforeStart = 0; let numVisibleBeforeStart = 0; - for (let i = 0; i < sorted.length && numVisibleBeforeStart <= start; i++) { + for ( + let i = 0; + i < sorted.length && numVisibleBeforeStart <= start; + i++ + ) { if (sorted[i].hidden) { numHiddenBeforeStart++; } else { @@ -328,7 +345,11 @@ export default class DataManager { const effectiveStart = start + numHiddenBeforeStart; let effectiveEnd = effectiveStart; - for (let numVisibleInRange = 0; numVisibleInRange < (end - start) && effectiveEnd < sorted.length; effectiveEnd++) { + for ( + let numVisibleInRange = 0; + numVisibleInRange < end - start && effectiveEnd < sorted.length; + effectiveEnd++ + ) { if (!sorted[effectiveEnd].hidden) { numVisibleInRange++; } @@ -339,8 +360,7 @@ export default class DataManager { // Take last and add as first const last = colsToMov.pop(); colsToMov.unshift(last); - } - else { + } else { // Take first and add as last const last = colsToMov.shift(); colsToMov.push(last); @@ -351,8 +371,7 @@ export default class DataManager { } return; - } - else { + } else { return; } @@ -364,7 +383,7 @@ export default class DataManager { } expandTreeForNodes = (data) => { - data.forEach(row => { + data.forEach((row) => { let currentRow = row; while (this.parentFunc(currentRow, this.data)) { let parent = this.parentFunc(currentRow, this.data); @@ -374,38 +393,38 @@ export default class DataManager { currentRow = parent; } }); - } + }; findDataByPath = (renderData, path) => { if (this.isDataType("tree")) { - const node = path.reduce((result, current) => { - return ( - result && - result.tableData && - result.tableData.childRows && - result.tableData.childRows[current] - ); - }, { tableData: { childRows: renderData } }); + const node = path.reduce( + (result, current) => { + return ( + result && + result.tableData && + result.tableData.childRows && + result.tableData.childRows[current] + ); + }, + { tableData: { childRows: renderData } } + ); return node; - } - else { + } else { const data = { groups: renderData }; const node = path.reduce((result, current) => { if (result.groups.length > 0) { return result.groups[current]; - } - else if (result.data) { + } else if (result.data) { return result.data[current]; - } - else { + } else { return undefined; } }, data); return node; } - } + }; findGroupByGroupPath(renderData, path) { const data = { groups: renderData, groupsIndex: this.rootGroupsIndex }; @@ -426,21 +445,23 @@ export default class DataManager { } getFieldValue = (rowData, columnDef, lookup = true) => { - let value = (typeof rowData[columnDef.field] !== 'undefined' ? rowData[columnDef.field] : byString(rowData, columnDef.field)); + let value = + typeof rowData[columnDef.field] !== "undefined" + ? rowData[columnDef.field] + : byString(rowData, columnDef.field); if (columnDef.lookup && lookup) { value = columnDef.lookup[value]; } return value; - } + }; isDataType(type) { let dataType = "normal"; if (this.parentFunc) { dataType = "tree"; - } - else if (this.columns.find(a => a.tableData.groupOrder > -1)) { + } else if (this.columns.find((a) => a.tableData.groupOrder > -1)) { dataType = "group"; } @@ -448,10 +469,11 @@ export default class DataManager { } sort(a, b, type) { - if (type === 'numeric') { + if (type === "numeric") { return a - b; } else { - if (a !== b) { // to find nulls + if (a !== b) { + // to find nulls if (!a) return -1; if (!b) return 1; } @@ -460,22 +482,30 @@ export default class DataManager { } sortList(list) { - const columnDef = this.columns.find(_ => _.tableData.id === this.orderBy); + const columnDef = this.columns.find((_) => _.tableData.id === this.orderBy); let result = list; if (columnDef.customSort) { - if (this.orderDirection === 'desc') { - result = list.sort((a, b) => columnDef.customSort(b, a, 'row')); - } - else { - result = list.sort((a, b) => columnDef.customSort(a, b, 'row')); + if (this.orderDirection === "desc") { + result = list.sort((a, b) => columnDef.customSort(b, a, "row")); + } else { + result = list.sort((a, b) => columnDef.customSort(a, b, "row")); } - } - else { + } else { result = list.sort( - this.orderDirection === 'desc' - ? (a, b) => this.sort(this.getFieldValue(b, columnDef), this.getFieldValue(a, columnDef), columnDef.type) - : (a, b) => this.sort(this.getFieldValue(a, columnDef), this.getFieldValue(b, columnDef), columnDef.type) + this.orderDirection === "desc" + ? (a, b) => + this.sort( + this.getFieldValue(b, columnDef), + this.getFieldValue(a, columnDef), + columnDef.type + ) + : (a, b) => + this.sort( + this.getFieldValue(a, columnDef), + this.getFieldValue(b, columnDef), + columnDef.type + ) ); } @@ -521,9 +551,9 @@ export default class DataManager { selectedCount: this.selectedCount, treefiedDataLength: this.treefiedDataLength, treeDataMaxLevel: this.treeDataMaxLevel, - groupedDataLength: this.groupedDataLength + groupedDataLength: this.groupedDataLength, }; - } + }; // ===================================================================================================== // DATA MANUPULATIONS @@ -535,81 +565,115 @@ export default class DataManager { this.filteredData = [...this.data]; if (this.applyFilters) { - this.columns.filter(columnDef => columnDef.tableData.filterValue).forEach(columnDef => { - const { lookup, type, tableData } = columnDef; - if (columnDef.customFilterAndSearch) { - this.filteredData = this.filteredData.filter(row => !!columnDef.customFilterAndSearch(tableData.filterValue, row, columnDef)); - } - else { - if (lookup) { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef, false); - return !tableData.filterValue || - tableData.filterValue.length === 0 || - tableData.filterValue.indexOf(value !== undefined && value !== null && value.toString()) > -1; - }); - } else if (type === 'numeric') { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef); - return (value + "") === tableData.filterValue; - }); - } else if (type === 'boolean' && tableData.filterValue) { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef); - return (value && tableData.filterValue === 'checked') || - (!value && tableData.filterValue === 'unchecked'); - }); - } else if (['date', 'datetime'].includes(type)) { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef); - - const currentDate = value ? new Date(value) : null; - - if (currentDate && currentDate.toString() !== 'Invalid Date') { - const selectedDate = tableData.filterValue; - let currentDateToCompare = ''; - let selectedDateToCompare = ''; - - if (type === 'date') { - currentDateToCompare = formatDate(currentDate, 'MM/dd/yyyy'); - selectedDateToCompare = formatDate(selectedDate, 'MM/dd/yyyy'); - } else if (type === 'datetime') { - currentDateToCompare = formatDate(currentDate, 'MM/dd/yyyy - HH:mm'); - selectedDateToCompare = formatDate(selectedDate, 'MM/dd/yyyy - HH:mm'); + this.columns + .filter((columnDef) => columnDef.tableData.filterValue) + .forEach((columnDef) => { + const { lookup, type, tableData } = columnDef; + if (columnDef.customFilterAndSearch) { + this.filteredData = this.filteredData.filter( + (row) => + !!columnDef.customFilterAndSearch( + tableData.filterValue, + row, + columnDef + ) + ); + } else { + if (lookup) { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef, false); + return ( + !tableData.filterValue || + tableData.filterValue.length === 0 || + tableData.filterValue.indexOf( + value !== undefined && value !== null && value.toString() + ) > -1 + ); + }); + } else if (type === "numeric") { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef); + return value + "" === tableData.filterValue; + }); + } else if (type === "boolean" && tableData.filterValue) { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef); + return ( + (value && tableData.filterValue === "checked") || + (!value && tableData.filterValue === "unchecked") + ); + }); + } else if (["date", "datetime"].includes(type)) { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef); + + const currentDate = value ? new Date(value) : null; + + if (currentDate && currentDate.toString() !== "Invalid Date") { + const selectedDate = tableData.filterValue; + let currentDateToCompare = ""; + let selectedDateToCompare = ""; + + if (type === "date") { + currentDateToCompare = formatDate( + currentDate, + "MM/dd/yyyy" + ); + selectedDateToCompare = formatDate( + selectedDate, + "MM/dd/yyyy" + ); + } else if (type === "datetime") { + currentDateToCompare = formatDate( + currentDate, + "MM/dd/yyyy - HH:mm" + ); + selectedDateToCompare = formatDate( + selectedDate, + "MM/dd/yyyy - HH:mm" + ); + } + + return currentDateToCompare === selectedDateToCompare; } - return currentDateToCompare === selectedDateToCompare; - } - - return true; - }); - } else if (type === 'time') { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef); - const currentHour = value || null; - - if (currentHour) { - const selectedHour = tableData.filterValue; - const currentHourToCompare = formatDate(selectedHour, 'HH:mm'); - - return currentHour === currentHourToCompare; - } + return true; + }); + } else if (type === "time") { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef); + const currentHour = value || null; + + if (currentHour) { + const selectedHour = tableData.filterValue; + const currentHourToCompare = formatDate( + selectedHour, + "HH:mm" + ); + + return currentHour === currentHourToCompare; + } - return true; - }); - } else { - this.filteredData = this.filteredData.filter(row => { - const value = this.getFieldValue(row, columnDef); - return value && value.toString().toUpperCase().includes(tableData.filterValue.toUpperCase()); - }); + return true; + }); + } else { + this.filteredData = this.filteredData.filter((row) => { + const value = this.getFieldValue(row, columnDef); + return ( + value && + value + .toString() + .toUpperCase() + .includes(tableData.filterValue.toUpperCase()) + ); + }); + } } - } - }); - + }); } this.filtered = true; - } + }; searchData = () => { this.grouped = this.treefied = this.sorted = this.paged = false; @@ -617,24 +681,34 @@ export default class DataManager { this.searchedData = [...this.filteredData]; if (this.searchText && this.applySearch) { - this.searchedData = this.searchedData.filter(row => { + this.searchedData = this.searchedData.filter((row) => { return this.columns - .filter(columnDef => { return columnDef.searchable === undefined ? !columnDef.hidden : columnDef.searchable }) - .some(columnDef => { + .filter((columnDef) => { + return columnDef.searchable === undefined + ? !columnDef.hidden + : columnDef.searchable; + }) + .some((columnDef) => { if (columnDef.customFilterAndSearch) { - return !!columnDef.customFilterAndSearch(this.searchText, row, columnDef); - } - else if (columnDef.field) { + return !!columnDef.customFilterAndSearch( + this.searchText, + row, + columnDef + ); + } else if (columnDef.field) { const value = this.getFieldValue(row, columnDef); if (value) { - return value.toString().toUpperCase().includes(this.searchText.toUpperCase()); + return value + .toString() + .toUpperCase() + .includes(this.searchText.toUpperCase()); } } }); }); } this.searched = true; - } + }; groupData() { this.sorted = this.paged = false; @@ -643,35 +717,56 @@ export default class DataManager { const tmpData = [...this.searchedData]; const groups = this.columns - .filter(col => col.tableData.groupOrder > -1) - .sort((col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder); + .filter((col) => col.tableData.groupOrder > -1) + .sort( + (col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder + ); - const subData = tmpData.reduce((result, currentRow) => { - let object = result; - object = groups.reduce((o, colDef) => { - const value = currentRow[colDef.field] || byString(currentRow, colDef.field); + const subData = tmpData.reduce( + (result, currentRow) => { + let object = result; + object = groups.reduce((o, colDef) => { + const value = + currentRow[colDef.field] || byString(currentRow, colDef.field); - let group; - if (o.groupsIndex[value] !== undefined) { - group = o.groups[o.groupsIndex[value]]; - } - - if (!group) { - const path = [...(o.path || []), value]; - let oldGroup = this.findGroupByGroupPath(this.groupedData, path) || { isExpanded: (typeof this.defaultExpanded ==='boolean') ? this.defaultExpanded : false }; + let group; + if (o.groupsIndex[value] !== undefined) { + group = o.groups[o.groupsIndex[value]]; + } - group = { value, groups: [], groupsIndex: {}, data: [], isExpanded: oldGroup.isExpanded, path: path }; - o.groups.push(group); - o.groupsIndex[value] = o.groups.length - 1; - } - return group; - }, object); + if (!group) { + const path = [...(o.path || []), value]; + let oldGroup = this.findGroupByGroupPath( + this.groupedData, + path + ) || { + isExpanded: + typeof this.defaultExpanded === "boolean" + ? this.defaultExpanded + : false, + }; + + group = { + value, + groups: [], + groupsIndex: {}, + data: [], + isExpanded: oldGroup.isExpanded, + path: path, + }; + o.groups.push(group); + o.groupsIndex[value] = o.groups.length - 1; + } + return group; + }, object); - object.data.push(currentRow); - this.groupedDataLength++; + object.data.push(currentRow); + this.groupedDataLength++; - return result; - }, { groups: [], groupsIndex: {} }); + return result; + }, + { groups: [], groupsIndex: {} } + ); this.groupedData = subData.groups; this.grouped = true; @@ -680,14 +775,17 @@ export default class DataManager { treefyData() { this.sorted = this.paged = false; - this.data.forEach(a => a.tableData.childRows = null); + this.data.forEach((a) => (a.tableData.childRows = null)); this.treefiedData = []; this.treefiedDataLength = 0; this.treeDataMaxLevel = 0; // if filter or search is enabled, collapse the tree - if (this.searchText || this.columns.some(columnDef => columnDef.tableData.filterValue)) { - this.data.forEach(row => { + if ( + this.searchText || + this.columns.some((columnDef) => columnDef.tableData.filterValue) + ) { + this.data.forEach((row) => { row.tableData.isTreeExpanded = false; }); @@ -707,10 +805,15 @@ export default class DataManager { addRow(parent); - rowData.tableData.path = [...parent.tableData.path, parent.tableData.childRows.length - 1]; - this.treeDataMaxLevel = Math.max(this.treeDataMaxLevel, rowData.tableData.path.length); - } - else { + rowData.tableData.path = [ + ...parent.tableData.path, + parent.tableData.childRows.length - 1, + ]; + this.treeDataMaxLevel = Math.max( + this.treeDataMaxLevel, + rowData.tableData.path.length + ); + } else { if (!this.treefiedData.includes(rowData)) { this.treefiedData.push(rowData); this.treefiedDataLength++; @@ -720,12 +823,12 @@ export default class DataManager { }; // Add all rows initially - this.data.forEach(rowData => { + this.data.forEach((rowData) => { addRow(rowData); }); const markForTreeRemove = (rowData) => { let pointer = this.treefiedData; - rowData.tableData.path.forEach(pathPart => { + rowData.tableData.path.forEach((pathPart) => { if (pointer.tableData && pointer.tableData.childRows) { pointer = pointer.tableData.childRows; } @@ -736,7 +839,7 @@ export default class DataManager { const traverseChildrenAndUnmark = (rowData) => { if (rowData.tableData.childRows) { - rowData.tableData.childRows.forEach(row => { + rowData.tableData.childRows.forEach((row) => { traverseChildrenAndUnmark(row); }); } @@ -744,10 +847,16 @@ export default class DataManager { }; // for all data rows, restore initial expand if no search term is available and remove items that shouldn't be there - this.data.forEach(rowData => { - if (!this.searchText && !this.columns.some(columnDef => columnDef.tableData.filterValue)) { + this.data.forEach((rowData) => { + if ( + !this.searchText && + !this.columns.some((columnDef) => columnDef.tableData.filterValue) + ) { if (rowData.tableData.isTreeExpanded === undefined) { - var isExpanded = (typeof this.defaultExpanded ==='boolean') ? this.defaultExpanded : this.defaultExpanded(rowData); + var isExpanded = + typeof this.defaultExpanded === "boolean" + ? this.defaultExpanded + : this.defaultExpanded(rowData); rowData.tableData.isTreeExpanded = isExpanded; } } @@ -759,7 +868,7 @@ export default class DataManager { }); // preserve all children of nodes that are matched by search or filters - this.data.forEach(rowData => { + this.data.forEach((rowData) => { if (this.searchedData.indexOf(rowData) > -1) { traverseChildrenAndUnmark(rowData); } @@ -771,8 +880,7 @@ export default class DataManager { if (item.tableData.childRows) { traverseTreeAndDeleteMarked(item.tableData.childRows); } - if (item.tableData.markedForTreeRemove) - rowDataArray.splice(i, 1); + if (item.tableData.markedForTreeRemove) rowDataArray.splice(i, 1); } }; @@ -787,20 +895,21 @@ export default class DataManager { this.sortedData = [...this.groupedData]; const groups = this.columns - .filter(col => col.tableData.groupOrder > -1) - .sort((col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder); + .filter((col) => col.tableData.groupOrder > -1) + .sort( + (col1, col2) => col1.tableData.groupOrder - col2.tableData.groupOrder + ); const sortGroups = (list, columnDef) => { if (columnDef.customSort) { return list.sort( - columnDef.tableData.groupSort === 'desc' - ? (a, b) => columnDef.customSort(b.value, a.value, 'group') - : (a, b) => columnDef.customSort(a.value, b.value, 'group') + columnDef.tableData.groupSort === "desc" + ? (a, b) => columnDef.customSort(b.value, a.value, "group") + : (a, b) => columnDef.customSort(a.value, b.value, "group") ); - } - else { + } else { return list.sort( - columnDef.tableData.groupSort === 'desc' + columnDef.tableData.groupSort === "desc" ? (a, b) => this.sort(b.value, a.value, columnDef.type) : (a, b) => this.sort(a.value, b.value, columnDef.type) ); @@ -810,13 +919,12 @@ export default class DataManager { this.sortedData = sortGroups(this.sortedData, groups[0]); const sortGroupData = (list, level) => { - list.forEach(element => { + list.forEach((element) => { if (element.groups.length > 0) { const column = groups[level]; element.groups = sortGroups(element.groups, column); sortGroupData(element.groups, level + 1); - } - else { + } else { if (this.orderBy >= 0 && this.orderDirection) { element.data = this.sortList(element.data); } @@ -825,16 +933,17 @@ export default class DataManager { }; sortGroupData(this.sortedData, 1); - } - else if (this.isDataType("tree")) { + } else if (this.isDataType("tree")) { this.sortedData = [...this.treefiedData]; if (this.orderBy != -1) { this.sortedData = this.sortList(this.sortedData); const sortTree = (list) => { - list.forEach(item => { + list.forEach((item) => { if (item.tableData.childRows) { - item.tableData.childRows = this.sortList(item.tableData.childRows); + item.tableData.childRows = this.sortList( + item.tableData.childRows + ); sortTree(item.tableData.childRows); } }); @@ -842,8 +951,7 @@ export default class DataManager { sortTree(this.sortedData); } - } - else if (this.isDataType("normal")) { + } else if (this.isDataType("normal")) { this.sortedData = [...this.searchedData]; if (this.orderBy != -1 && this.applySort) { this.sortedData = this.sortList(this.sortedData); diff --git a/src/utils/index.js b/src/utils/index.js index 7125fb42e..ededfae8d 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -3,9 +3,9 @@ export const byString = (o, s) => { return; } - s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties - s = s.replace(/^\./, ''); // strip a leading dot - var a = s.split('.'); + s = s.replace(/\[(\w+)\]/g, ".$1"); // convert indexes to properties + s = s.replace(/^\./, ""); // strip a leading dot + var a = s.split("."); for (var i = 0, n = a.length; i < n; ++i) { var x = a[i]; if (o && x in o) { @@ -18,17 +18,17 @@ export const byString = (o, s) => { }; export const setByString = (obj, path, value) => { - var schema = obj; // a moving reference to internal objects within obj + var schema = obj; // a moving reference to internal objects within obj - path = path.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties - path = path.replace(/^\./, ''); // strip a leading dot - var pList = path.split('.'); + path = path.replace(/\[(\w+)\]/g, ".$1"); // convert indexes to properties + path = path.replace(/^\./, ""); // strip a leading dot + var pList = path.split("."); var len = pList.length; - for(var i = 0; i < len-1; i++) { - var elem = pList[i]; - if( !schema[elem] ) schema[elem] = {}; - schema = schema[elem]; + for (var i = 0; i < len - 1; i++) { + var elem = pList[i]; + if (!schema[elem]) schema[elem] = {}; + schema = schema[elem]; } - schema[pList[len-1]] = value; -}; \ No newline at end of file + schema[pList[len - 1]] = value; +}; diff --git a/src/utils/polyfill/array.find.js b/src/utils/polyfill/array.find.js index 8e6546877..28553fb4a 100644 --- a/src/utils/polyfill/array.find.js +++ b/src/utils/polyfill/array.find.js @@ -1,22 +1,22 @@ -Object.defineProperty(Array.prototype, 'find', { - value: function(predicate) { - if (this == null) { - throw new TypeError('"this" is null or not defined'); - } - var o = Object(this); - var len = o.length >>> 0; - if (typeof predicate !== 'function') { - throw new TypeError('predicate must be a function'); - } - var thisArg = arguments[1]; - var k = 0; - while (k < len) { - var kValue = o[k]; - if (predicate.call(thisArg, kValue, k, o)) { - return kValue; - } - k++; - } - return undefined; +Object.defineProperty(Array.prototype, "find", { + value: function (predicate) { + if (this == null) { + throw new TypeError('"this" is null or not defined'); } -}); \ No newline at end of file + var o = Object(this); + var len = o.length >>> 0; + if (typeof predicate !== "function") { + throw new TypeError("predicate must be a function"); + } + var thisArg = arguments[1]; + var k = 0; + while (k < len) { + var kValue = o[k]; + if (predicate.call(thisArg, kValue, k, o)) { + return kValue; + } + k++; + } + return undefined; + }, +}); diff --git a/src/utils/polyfill/index.js b/src/utils/polyfill/index.js index c91144a8f..284a23571 100644 --- a/src/utils/polyfill/index.js +++ b/src/utils/polyfill/index.js @@ -1,4 +1,4 @@ "use strict"; if (!Array.prototype.find) { - require("./array.find"); -} \ No newline at end of file + require("./array.find"); +} diff --git a/types/index.d.ts b/types/index.d.ts index 7d5c6056e..2414107de 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,7 +1,7 @@ -import * as React from 'react'; -import { IconProps } from '@material-ui/core/Icon'; -import SvgIcon from "@material-ui/core/SvgIcon" -import { string } from 'prop-types'; +import * as React from "react"; +import { IconProps } from "@material-ui/core/Icon"; +import SvgIcon from "@material-ui/core/SvgIcon"; +import { string } from "prop-types"; type SvgIconComponent = typeof SvgIcon; @@ -10,7 +10,9 @@ export interface MaterialTableProps { columns: Column[]; components?: Components; data: RowData[] | ((query: Query) => Promise>); - detailPanel?: ((rowData: RowData) => React.ReactNode) | (DetailPanel | ((rowData: RowData) => DetailPanel))[]; + detailPanel?: + | ((rowData: RowData) => React.ReactNode) + | (DetailPanel | ((rowData: RowData) => DetailPanel))[]; editable?: { isEditable?: (rowData: RowData) => boolean; isDeletable?: (rowData: RowData) => boolean; @@ -23,7 +25,7 @@ export interface MaterialTableProps { onRowUpdateCancelled?: (rowData: RowData) => void; isEditHidden?: (rowData: RowData) => boolean; isDeleteHidden?: (rowData: RowData) => boolean; - } + }; icons?: Icons; isLoading?: boolean; title?: string | React.ReactElement; @@ -31,17 +33,21 @@ export interface MaterialTableProps { parentChildData?: (row: RowData, rows: RowData[]) => RowData | undefined; localization?: Localization; onChangeRowsPerPage?: (pageSize: number) => void; - onChangePage?: (page: number) => void; - onChangeColumnHidden?: (column:Column, hidden:boolean) => void; + onChangePage?: (page: number, pageSize: number) => void; + onChangeColumnHidden?: (column: Column, hidden: boolean) => void; onColumnDragged?: (sourceIndex: number, destinationIndex: number) => void; - onOrderChange?: (orderBy: number, orderDirection: ("asc" | "desc")) => void; - onGroupRemoved?: (column:Column, index:boolean) => void; - onRowClick?: (event?: React.MouseEvent, rowData?: RowData, toggleDetailPanel?: (panelIndex?: number) => void) => void; + onOrderChange?: (orderBy: number, orderDirection: "asc" | "desc") => void; + onGroupRemoved?: (column: Column, index: boolean) => void; + onRowClick?: ( + event?: React.MouseEvent, + rowData?: RowData, + toggleDetailPanel?: (panelIndex?: number) => void + ) => void; onRowSelected?: (rowData: RowData) => void; onSearchChange?: (searchText: string) => void; - /** An event fired when the table has finished filtering data - * @param {Filter[]} filters All the filters that are applied to the table - */ + /** An event fired when the table has finished filtering data + * @param {Filter[]} filters All the filters that are applied to the table + */ onFilterChange?: (filters: Filter[]) => void; onSelectionChange?: (data: RowData[], rowData?: RowData) => void; onTreeExpandChange?: (data: any, isExpanded: boolean) => void; @@ -86,7 +92,7 @@ export interface Action { disabled?: boolean; icon: string | (() => React.ReactElement) | SvgIconComponent; isFreeAction?: boolean; - position?: 'auto' | 'toolbar' | 'toolbarOnSelect' | 'row'; + position?: "auto" | "toolbar" | "toolbarOnSelect" | "row"; tooltip?: string; onClick: (event: any, data: RowData | RowData[]) => void; iconProps?: IconProps; @@ -109,44 +115,79 @@ export interface EditCellColumnDef { groupOrder: any; groupSort: string; id: number; - } + }; } export interface Column { - align?: 'center' | 'inherit' | 'justify' | 'left' | 'right'; - cellStyle?: React.CSSProperties | ((data: RowData[], rowData: RowData) => React.CSSProperties); - currencySetting?: { locale?: string, currencyCode?: string, minimumFractionDigits?: number, maximumFractionDigits?: number }; + align?: "center" | "inherit" | "justify" | "left" | "right"; + cellStyle?: + | React.CSSProperties + | ((data: RowData[], rowData: RowData) => React.CSSProperties); + currencySetting?: { + locale?: string; + currencyCode?: string; + minimumFractionDigits?: number; + maximumFractionDigits?: number; + }; dateSetting?: { locale?: string }; - customFilterAndSearch?: (filter: any, rowData: RowData, columnDef: Column) => boolean; - customSort?: (data1: RowData, data2: RowData, type: (('row' | 'group'))) => number; + customFilterAndSearch?: ( + filter: any, + rowData: RowData, + columnDef: Column + ) => boolean; + customSort?: ( + data1: RowData, + data2: RowData, + type: "row" | "group" + ) => number; defaultFilter?: any; defaultGroupOrder?: number; - defaultGroupSort?: ('asc' | 'desc'); - defaultSort?: ('asc' | 'desc'); + defaultGroupSort?: "asc" | "desc"; + defaultSort?: "asc" | "desc"; disableClick?: boolean; - editComponent?: ((props: EditComponentProps) => React.ReactElement); - emptyValue?: string | React.ReactElement | ((data: any) => React.ReactElement | string); + editComponent?: ( + props: EditComponentProps + ) => React.ReactElement; + emptyValue?: + | string + | React.ReactElement + | ((data: any) => React.ReactElement | string); export?: boolean; field?: keyof RowData | string; filtering?: boolean; - filterComponent?: ((props: {columnDef: Column, onFilterChanged: (rowId: string, value: any) => void}) => React.ReactElement); + filterComponent?: (props: { + columnDef: Column; + onFilterChanged: (rowId: string, value: any) => void; + }) => React.ReactElement; filterPlaceholder?: string; filterCellStyle?: React.CSSProperties; grouping?: boolean; headerStyle?: React.CSSProperties; hidden?: boolean; hideFilterIcon?: boolean; - initialEditValue?: any, + initialEditValue?: any; lookup?: object; editPlaceholder?: string; - editable?: ('always' | 'onUpdate' | 'onAdd' | 'never' | ((columnDef: Column, rowData: RowData) => boolean)); + editable?: + | "always" + | "onUpdate" + | "onAdd" + | "never" + | ((columnDef: Column, rowData: RowData) => boolean); removable?: boolean; - render?: (data: RowData, type: ('row' | 'group')) => any; + render?: (data: RowData, type: "row" | "group") => any; searchable?: boolean; sorting?: boolean; title?: string | React.ReactElement; tooltip?: string; - type?: ('string' | 'boolean' | 'numeric' | 'date' | 'datetime' | 'time' | 'currency'); + type?: + | "string" + | "boolean" + | "numeric" + | "date" + | "datetime" + | "time" + | "currency"; width?: string | number; } @@ -188,19 +229,37 @@ export interface Icons { Check?: React.ForwardRefExoticComponent>; Clear?: React.ForwardRefExoticComponent>; Delete?: React.ForwardRefExoticComponent>; - DetailPanel?: React.ForwardRefExoticComponent>; + DetailPanel?: React.ForwardRefExoticComponent< + React.RefAttributes + >; Edit?: React.ForwardRefExoticComponent>; Export?: React.ForwardRefExoticComponent>; Filter?: React.ForwardRefExoticComponent>; - FirstPage?: React.ForwardRefExoticComponent>; - SortArrow?: React.ForwardRefExoticComponent>; - LastPage?: React.ForwardRefExoticComponent>; - NextPage?: React.ForwardRefExoticComponent>; - PreviousPage?: React.ForwardRefExoticComponent>; - ResetSearch?: React.ForwardRefExoticComponent>; + FirstPage?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + SortArrow?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + LastPage?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + NextPage?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + PreviousPage?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + ResetSearch?: React.ForwardRefExoticComponent< + React.RefAttributes + >; Search?: React.ForwardRefExoticComponent>; - ThirdStateCheck?: React.ForwardRefExoticComponent>; - ViewColumn?: React.ForwardRefExoticComponent>; + ThirdStateCheck?: React.ForwardRefExoticComponent< + React.RefAttributes + >; + ViewColumn?: React.ForwardRefExoticComponent< + React.RefAttributes + >; } export interface Options { @@ -208,11 +267,11 @@ export interface Options { detailPanelColumnStyle?: React.CSSProperties; editCellStyle?: React.CSSProperties; actionsColumnIndex?: number; - addRowPosition?: ('first' | 'last'); + addRowPosition?: "first" | "last"; columnsButton?: boolean; defaultExpanded?: boolean | ((rowData: any) => boolean); debounceInterval?: number; - detailPanelType?: ('single' | 'multiple'); + detailPanelType?: "single" | "multiple"; doubleHorizontalScroll?: boolean; draggable?: boolean; emptyRowsWhenPaging?: boolean; @@ -224,23 +283,25 @@ export interface Options { filtering?: boolean; filterCellStyle?: React.CSSProperties; filterRowStyle?: React.CSSProperties; - fixedColumns?: { left?: number; right?: number; }; + fixedColumns?: { left?: number; right?: number }; groupRowSeparator?: string; header?: boolean; headerStyle?: React.CSSProperties; hideFilterIcons?: boolean; initialPage?: number; - loadingType?: ('overlay' | 'linear'); + loadingType?: "overlay" | "linear"; maxBodyHeight?: number | string; minBodyHeight?: number | string; - padding?: ('default' | 'dense'); + padding?: "default" | "dense"; paging?: boolean; grouping?: boolean; - overflowY?: ('visible' | 'hidden' | 'scroll' | 'auto' | 'initial' | 'inherit'); + overflowY?: "visible" | "hidden" | "scroll" | "auto" | "initial" | "inherit"; pageSize?: number; pageSizeOptions?: number[]; - paginationType?: ('normal' | 'stepped'); - rowStyle?: React.CSSProperties | ((data: any, index: number, level: number) => React.CSSProperties); + paginationType?: "normal" | "stepped"; + rowStyle?: + | React.CSSProperties + | ((data: any, index: number, level: number) => React.CSSProperties); showEmptyDataSourceMessage?: boolean; showFirstLastPageButtons?: boolean; showSelectAllCheckbox?: boolean; @@ -248,18 +309,18 @@ export interface Options { showTextRowsSelected?: boolean; search?: boolean; searchText?: string; - searchFieldAlignment?: 'left' | 'right'; + searchFieldAlignment?: "left" | "right"; searchFieldStyle?: React.CSSProperties; - searchFieldVariant?: 'standard' | 'filled' | 'outlined'; + searchFieldVariant?: "standard" | "filled" | "outlined"; searchAutoFocus?: boolean; selection?: boolean; selectionProps?: any | ((data: any) => any); sorting?: boolean; - tableLayout?: 'auto' | 'fixed'; + tableLayout?: "auto" | "fixed"; thirdSortClick?: boolean; toolbar?: boolean; - toolbarButtonAlignment?: 'left' | 'right'; - detailPanelColumnAlignment?: 'left' | 'right'; + toolbarButtonAlignment?: "left" | "right"; + detailPanelColumnAlignment?: "left" | "right"; cspNonce?: string; } @@ -274,7 +335,7 @@ export interface Localization { saveTooltip?: React.ReactNode; cancelTooltip?: React.ReactNode; deleteText?: React.ReactNode; - }, + }; addTooltip?: React.ReactNode; deleteTooltip?: React.ReactNode; editTooltip?: React.ReactNode; @@ -290,13 +351,13 @@ export interface Localization { firstTooltip?: React.ReactNode; firstAriaLabel?: string; previousTooltip?: React.ReactNode; - previousAriaLabel?: string, + previousAriaLabel?: string; nextTooltip?: React.ReactNode; - nextAriaLabel?: string, + nextAriaLabel?: string; labelDisplayedRows?: React.ReactNode; labelRowsPerPage?: React.ReactNode; lastTooltip?: React.ReactNode; - lastAriaLabel?: string, + lastAriaLabel?: string; labelRowsSelect?: React.ReactNode; }; toolbar?: { @@ -312,4 +373,6 @@ export interface Localization { }; } -export default class MaterialTable extends React.Component> {} +export default class MaterialTable< + RowData extends object +> extends React.Component> {}