jattac.libs.web.responsive-table 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +8 -0
- package/.prettierrc +5 -0
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/Data/IResponsiveTableColumnDefinition.d.ts +6 -0
- package/dist/UI/FormField.d.ts +22 -0
- package/dist/UI/ResponsiveTable.d.ts +19 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
- package/rollup.config.js +23 -0
- package/src/Data/IResponsiveTableColumnDefinition.tsx +7 -0
- package/src/Styles/ResponsiveTable.module.css +54 -0
- package/src/UI/ResponsiveTable.tsx +125 -0
- package/src/index.tsx +5 -0
- package/src/typings.d.ts +14 -0
- package/tsconfig.json +22 -0
- package/update-dependancies.sh +4 -0
package/.eslintrc.json
ADDED
package/.prettierrc
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Nyingi Maina
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# FormField React Component
|
|
2
|
+
|
|
3
|
+
FormField is a powerful React component designed to streamline the creation of form fields with built-in support for validation, labels, hints, and optional indicators.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
npm install jattac.libs.web.form-field
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Example
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import React from 'react';
|
|
15
|
+
import FormField from 'jattac.libs.web.form-field';
|
|
16
|
+
|
|
17
|
+
const MyForm = () => {
|
|
18
|
+
const validationErrors = [
|
|
19
|
+
// Your validation errors here
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<form>
|
|
24
|
+
<FormField
|
|
25
|
+
label="Email"
|
|
26
|
+
id="email"
|
|
27
|
+
validationErrors={[{ key: 'email', errors: ['Invalid email address'] }]}
|
|
28
|
+
optional={true}
|
|
29
|
+
hint="We'll never share your email with anyone else."
|
|
30
|
+
>
|
|
31
|
+
<input type="email" />
|
|
32
|
+
</FormField>
|
|
33
|
+
|
|
34
|
+
{/* Add more FormField components for other form elements */}
|
|
35
|
+
</form>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Props
|
|
41
|
+
|
|
42
|
+
- **label** (required): The label for the form field.
|
|
43
|
+
- **id** (required): A unique identifier for the form field.
|
|
44
|
+
- **children** (required): The content of the form field, typically an input element.
|
|
45
|
+
- **validationErrors**: An array of validation errors for the form field.
|
|
46
|
+
- **optional**: A boolean indicating whether the field is optional. Defaults to false.
|
|
47
|
+
- **hint**: Additional information or guidance for the form field.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PureComponent, ReactNode } from 'react';
|
|
2
|
+
import { IValidationError } from 'jattac.libs.web.validationhelper';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
interface IFormFieldProps {
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
hint?: ReactNode;
|
|
8
|
+
id: string;
|
|
9
|
+
validationErrors?: IValidationError[];
|
|
10
|
+
optional?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export default class FormField extends PureComponent<IFormFieldProps> {
|
|
13
|
+
private contentRef;
|
|
14
|
+
private get firstInputOfContentRef();
|
|
15
|
+
private get validationError();
|
|
16
|
+
private setKeyOfFirstInput;
|
|
17
|
+
componentDidMount(): void;
|
|
18
|
+
private get isRequired();
|
|
19
|
+
private get errorDisplay();
|
|
20
|
+
render(): React.JSX.Element;
|
|
21
|
+
}
|
|
22
|
+
export { type IFormFieldProps };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { Component } from "react";
|
|
2
|
+
import IResponsiveTableColumnDefinition from "../Data/IResponsiveTableColumnDefinition";
|
|
3
|
+
type ColumnDefinition<TData> = IResponsiveTableColumnDefinition<TData> | ((data: TData, rowIndex?: number) => IResponsiveTableColumnDefinition<TData>);
|
|
4
|
+
interface IProps<TData> {
|
|
5
|
+
columnDefinitions: ColumnDefinition<TData>[];
|
|
6
|
+
data: TData[];
|
|
7
|
+
}
|
|
8
|
+
interface IState {
|
|
9
|
+
isMobile: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare class ResponsiveTable<TData> extends Component<IProps<TData>, IState> {
|
|
12
|
+
constructor(props: IProps<TData>);
|
|
13
|
+
componentDidMount(): void;
|
|
14
|
+
componentWillUnmount(): void;
|
|
15
|
+
handleResize: () => void;
|
|
16
|
+
private getColumnDefinition;
|
|
17
|
+
render(): React.JSX.Element;
|
|
18
|
+
}
|
|
19
|
+
export default ResponsiveTable;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
|
|
5
|
+
function styleInject(css, ref) {
|
|
6
|
+
if ( ref === void 0 ) ref = {};
|
|
7
|
+
var insertAt = ref.insertAt;
|
|
8
|
+
|
|
9
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
10
|
+
|
|
11
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
12
|
+
var style = document.createElement('style');
|
|
13
|
+
style.type = 'text/css';
|
|
14
|
+
|
|
15
|
+
if (insertAt === 'top') {
|
|
16
|
+
if (head.firstChild) {
|
|
17
|
+
head.insertBefore(style, head.firstChild);
|
|
18
|
+
} else {
|
|
19
|
+
head.appendChild(style);
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
head.appendChild(style);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (style.styleSheet) {
|
|
26
|
+
style.styleSheet.cssText = css;
|
|
27
|
+
} else {
|
|
28
|
+
style.appendChild(document.createTextNode(css));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var css_248z = ".ResponsiveTable-module_card__b-U2v {\n border: 1px solid #ccc;\n margin-bottom: 10px;\n border-radius: 8px;\n overflow: hidden;\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);\n}\n\n.ResponsiveTable-module_card-header__Ttk51 {\n background-color: #f0f0f0;\n padding: 10px;\n font-weight: bold;\n}\n\n.ResponsiveTable-module_card-body__XIy0h {\n padding: 10px;\n}\n\n/* Apply styles to the table with the specific class 'custom-table' */\n.ResponsiveTable-module_responsiveTable__4y-Od {\n width: 100%;\n border-collapse: collapse;\n margin-bottom: 20px;\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od thead {\n position: sticky;\n}\n\n/* Style the table header */\n.ResponsiveTable-module_responsiveTable__4y-Od th,\n.ResponsiveTable-module_responsiveTable__4y-Od td {\n padding: 12px;\n text-align: left;\n}\n\n.ResponsiveTable-module_responsiveTable__4y-Od th {\n background-color: #f2f2f2;\n}\n\n/* Alternate row colors */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:nth-child(even) {\n background-color: #f9f9f9;\n}\n\n/* Change background color on hover */\n.ResponsiveTable-module_responsiveTable__4y-Od tr:hover {\n background-color: #d9edf7;\n}\n\n.ResponsiveTable-module_tableContainer__VjWjH {\n overflow-x: auto;\n margin-bottom: 20px;\n}\n";
|
|
33
|
+
var styles = {"card":"ResponsiveTable-module_card__b-U2v","card-header":"ResponsiveTable-module_card-header__Ttk51","card-body":"ResponsiveTable-module_card-body__XIy0h","responsiveTable":"ResponsiveTable-module_responsiveTable__4y-Od","tableContainer":"ResponsiveTable-module_tableContainer__VjWjH"};
|
|
34
|
+
styleInject(css_248z);
|
|
35
|
+
|
|
36
|
+
// Class component
|
|
37
|
+
class ResponsiveTable extends React.Component {
|
|
38
|
+
constructor(props) {
|
|
39
|
+
super(props);
|
|
40
|
+
this.handleResize = () => {
|
|
41
|
+
this.setState(() => {
|
|
42
|
+
return { isMobile: window.innerWidth <= 600 };
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
this.state = {
|
|
46
|
+
isMobile: false,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
componentDidMount() {
|
|
50
|
+
this.setState(() => {
|
|
51
|
+
return { isMobile: window.innerWidth <= 600 };
|
|
52
|
+
});
|
|
53
|
+
window.addEventListener("resize", this.handleResize);
|
|
54
|
+
}
|
|
55
|
+
componentWillUnmount() {
|
|
56
|
+
window.removeEventListener("resize", this.handleResize);
|
|
57
|
+
}
|
|
58
|
+
getColumnDefinition(columnDefinition, rowIndex) {
|
|
59
|
+
return columnDefinition instanceof Function
|
|
60
|
+
? columnDefinition(this.props.data[0], rowIndex)
|
|
61
|
+
: columnDefinition;
|
|
62
|
+
}
|
|
63
|
+
render() {
|
|
64
|
+
if (this.state.isMobile) {
|
|
65
|
+
return (React.createElement("div", null, this.props.data.map((row, rowIndex) => (React.createElement("div", { key: rowIndex, className: styles["card"] },
|
|
66
|
+
React.createElement("div", { className: styles["card-header"] }, " "),
|
|
67
|
+
React.createElement("div", { className: styles["card-body"] }, this.props.columnDefinitions.map((columnDefinition, colIndex) => {
|
|
68
|
+
const colDef = this.getColumnDefinition(columnDefinition, rowIndex);
|
|
69
|
+
return (React.createElement("div", { key: colIndex },
|
|
70
|
+
React.createElement("p", null,
|
|
71
|
+
React.createElement("span", { className: "font-bold" },
|
|
72
|
+
colDef.displayLabel,
|
|
73
|
+
":"),
|
|
74
|
+
" ",
|
|
75
|
+
colDef.cellRenderer(row))));
|
|
76
|
+
})))))));
|
|
77
|
+
}
|
|
78
|
+
return (React.createElement("div", { className: styles.tableContainer },
|
|
79
|
+
React.createElement("table", { className: styles["responsiveTable"] },
|
|
80
|
+
React.createElement("thead", null,
|
|
81
|
+
React.createElement("tr", null, this.props.columnDefinitions.map((columnDefinition, colIndex) => (React.createElement("th", { key: colIndex }, this.getColumnDefinition(columnDefinition, 0).displayLabel))))),
|
|
82
|
+
React.createElement("tbody", null, this.props.data.map((row, rowIndex) => (React.createElement("tr", { key: rowIndex }, this.props.columnDefinitions.map((columnDefinition, colIndex) => (React.createElement("td", { key: colIndex }, this.getColumnDefinition(columnDefinition, rowIndex).cellRenderer(row)))))))))));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = ResponsiveTable;
|
|
87
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../node_modules/style-inject/dist/style-inject.es.js","../src/UI/ResponsiveTable.tsx"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n",null],"names":["Component"],"mappings":"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","x_google_ignoreList":[0]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jattac.libs.web.responsive-table",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.es.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "rollup -c",
|
|
10
|
+
"lint": "eslint './{src,app}/**/*.{ts,tsx}'",
|
|
11
|
+
"size": "size-limit",
|
|
12
|
+
"prepare": "npm run build"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"react",
|
|
16
|
+
"typescript"
|
|
17
|
+
],
|
|
18
|
+
"author": "Nyingi Maina",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"react": ">=18.2.0",
|
|
22
|
+
"react-dom": ">=18.2.0",
|
|
23
|
+
"typescript": ">=3.7.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
27
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
28
|
+
"@rollup/plugin-typescript": "^11.1.5",
|
|
29
|
+
"@size-limit/preset-small-lib": "^10.0.1",
|
|
30
|
+
"@testing-library/react": "^14.0.0",
|
|
31
|
+
"@types/react": "^18.2.33",
|
|
32
|
+
"@types/react-dom": "^18.2.14",
|
|
33
|
+
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
|
34
|
+
"@typescript-eslint/parser": "^6.9.1",
|
|
35
|
+
"eslint": "^8.52.0",
|
|
36
|
+
"eslint-config-prettier": "^9.0.0",
|
|
37
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
38
|
+
"eslint-plugin-react": "^7.33.2",
|
|
39
|
+
"identity-obj-proxy": "^3.0.0",
|
|
40
|
+
"npm": "^10.2.2",
|
|
41
|
+
"postcss": "^8.4.31",
|
|
42
|
+
"prettier": "^3.0.3",
|
|
43
|
+
"react": "^18.2.0",
|
|
44
|
+
"react-dom": "^18.2.0",
|
|
45
|
+
"rollup": "^4.2.0",
|
|
46
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
47
|
+
"rollup-plugin-delete": "^2.0.0",
|
|
48
|
+
"rollup-plugin-generate-package-json": "^3.2.0",
|
|
49
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
50
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
51
|
+
"size-limit": "^10.0.1",
|
|
52
|
+
"typescript": "^5.2.2"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
56
|
+
"tslib": "^2.6.2"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const postcss = require('rollup-plugin-postcss');
|
|
2
|
+
const typescript = require('@rollup/plugin-typescript');
|
|
3
|
+
const peerDepsExternal = require('rollup-plugin-peer-deps-external');
|
|
4
|
+
const resolve = require('@rollup/plugin-node-resolve').default;
|
|
5
|
+
const commonjs = require('@rollup/plugin-commonjs');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
input: 'src/index.tsx',
|
|
9
|
+
output: {
|
|
10
|
+
dir: 'dist',
|
|
11
|
+
format: 'cjs',
|
|
12
|
+
sourcemap: true,
|
|
13
|
+
},
|
|
14
|
+
plugins: [
|
|
15
|
+
peerDepsExternal(),
|
|
16
|
+
resolve(),
|
|
17
|
+
typescript(),
|
|
18
|
+
commonjs(),
|
|
19
|
+
postcss({
|
|
20
|
+
modules: true,
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
.card {
|
|
2
|
+
border: 1px solid #ccc;
|
|
3
|
+
margin-bottom: 10px;
|
|
4
|
+
border-radius: 8px;
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.card-header {
|
|
10
|
+
background-color: #f0f0f0;
|
|
11
|
+
padding: 10px;
|
|
12
|
+
font-weight: bold;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.card-body {
|
|
16
|
+
padding: 10px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Apply styles to the table with the specific class 'custom-table' */
|
|
20
|
+
.responsiveTable {
|
|
21
|
+
width: 100%;
|
|
22
|
+
border-collapse: collapse;
|
|
23
|
+
margin-bottom: 20px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.responsiveTable thead {
|
|
27
|
+
position: sticky;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Style the table header */
|
|
31
|
+
.responsiveTable th,
|
|
32
|
+
.responsiveTable td {
|
|
33
|
+
padding: 12px;
|
|
34
|
+
text-align: left;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.responsiveTable th {
|
|
38
|
+
background-color: #f2f2f2;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Alternate row colors */
|
|
42
|
+
.responsiveTable tr:nth-child(even) {
|
|
43
|
+
background-color: #f9f9f9;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Change background color on hover */
|
|
47
|
+
.responsiveTable tr:hover {
|
|
48
|
+
background-color: #d9edf7;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tableContainer {
|
|
52
|
+
overflow-x: auto;
|
|
53
|
+
margin-bottom: 20px;
|
|
54
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import React, { Component } from "react";
|
|
2
|
+
import styles from "../Styles/ResponsiveTable.module.css";
|
|
3
|
+
import IResponsiveTableColumnDefinition from "../Data/IResponsiveTableColumnDefinition";
|
|
4
|
+
|
|
5
|
+
type ColumnDefinition<TData> =
|
|
6
|
+
| IResponsiveTableColumnDefinition<TData>
|
|
7
|
+
| ((
|
|
8
|
+
data: TData,
|
|
9
|
+
rowIndex?: number
|
|
10
|
+
) => IResponsiveTableColumnDefinition<TData>);
|
|
11
|
+
interface IProps<TData> {
|
|
12
|
+
columnDefinitions: ColumnDefinition<TData>[];
|
|
13
|
+
data: TData[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IState {
|
|
17
|
+
isMobile: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Class component
|
|
21
|
+
class ResponsiveTable<TData> extends Component<IProps<TData>, IState> {
|
|
22
|
+
constructor(props: IProps<TData>) {
|
|
23
|
+
super(props);
|
|
24
|
+
this.state = {
|
|
25
|
+
isMobile: false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
componentDidMount(): void {
|
|
30
|
+
this.setState(() => {
|
|
31
|
+
return { isMobile: window.innerWidth <= 600 };
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
window.addEventListener("resize", this.handleResize);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
componentWillUnmount(): void {
|
|
38
|
+
window.removeEventListener("resize", this.handleResize);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
handleResize = (): void => {
|
|
42
|
+
this.setState(() => {
|
|
43
|
+
return { isMobile: window.innerWidth <= 600 };
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
private getColumnDefinition(
|
|
48
|
+
columnDefinition: ColumnDefinition<TData>,
|
|
49
|
+
rowIndex: number
|
|
50
|
+
): IResponsiveTableColumnDefinition<TData> {
|
|
51
|
+
return columnDefinition instanceof Function
|
|
52
|
+
? columnDefinition(this.props.data[0], rowIndex)
|
|
53
|
+
: columnDefinition;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
render() {
|
|
57
|
+
if (this.state.isMobile) {
|
|
58
|
+
return (
|
|
59
|
+
<div>
|
|
60
|
+
{this.props.data.map((row, rowIndex) => (
|
|
61
|
+
<div key={rowIndex} className={styles["card"]}>
|
|
62
|
+
<div className={styles["card-header"]}> </div>
|
|
63
|
+
<div className={styles["card-body"]}>
|
|
64
|
+
{this.props.columnDefinitions.map(
|
|
65
|
+
(columnDefinition, colIndex) => {
|
|
66
|
+
const colDef = this.getColumnDefinition(
|
|
67
|
+
columnDefinition,
|
|
68
|
+
rowIndex
|
|
69
|
+
);
|
|
70
|
+
return (
|
|
71
|
+
<div key={colIndex}>
|
|
72
|
+
<p>
|
|
73
|
+
<span className="font-bold">
|
|
74
|
+
{colDef.displayLabel}:
|
|
75
|
+
</span>{" "}
|
|
76
|
+
{colDef.cellRenderer(row)}
|
|
77
|
+
</p>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
))}
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div className={styles.tableContainer}>
|
|
91
|
+
<table className={styles["responsiveTable"]}>
|
|
92
|
+
<thead>
|
|
93
|
+
<tr>
|
|
94
|
+
{this.props.columnDefinitions.map(
|
|
95
|
+
(columnDefinition, colIndex) => (
|
|
96
|
+
<th key={colIndex}>
|
|
97
|
+
{this.getColumnDefinition(columnDefinition, 0).displayLabel}
|
|
98
|
+
</th>
|
|
99
|
+
)
|
|
100
|
+
)}
|
|
101
|
+
</tr>
|
|
102
|
+
</thead>
|
|
103
|
+
<tbody>
|
|
104
|
+
{this.props.data.map((row, rowIndex) => (
|
|
105
|
+
<tr key={rowIndex}>
|
|
106
|
+
{this.props.columnDefinitions.map(
|
|
107
|
+
(columnDefinition, colIndex) => (
|
|
108
|
+
<td key={colIndex}>
|
|
109
|
+
{this.getColumnDefinition(
|
|
110
|
+
columnDefinition,
|
|
111
|
+
rowIndex
|
|
112
|
+
).cellRenderer(row)}
|
|
113
|
+
</td>
|
|
114
|
+
)
|
|
115
|
+
)}
|
|
116
|
+
</tr>
|
|
117
|
+
))}
|
|
118
|
+
</tbody>
|
|
119
|
+
</table>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default ResponsiveTable;
|
package/src/index.tsx
ADDED
package/src/typings.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare module '*.css' {
|
|
2
|
+
const content: { [className: string]: string };
|
|
3
|
+
export default content;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
7
|
+
interface SvgrComponent extends React.StatelessComponent<React.SVGAttributes<SVGElement>> {}
|
|
8
|
+
|
|
9
|
+
declare module '*.svg' {
|
|
10
|
+
const svgUrl: string;
|
|
11
|
+
const svgComponent: SvgrComponent;
|
|
12
|
+
export default svgUrl;
|
|
13
|
+
export { svgComponent as ReactComponent };
|
|
14
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "dist",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"target": "es2015",
|
|
6
|
+
"lib": ["dom", "esnext"],
|
|
7
|
+
"moduleResolution": "node",
|
|
8
|
+
"jsx": "react",
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"noImplicitReturns": true,
|
|
13
|
+
"noImplicitThis": true,
|
|
14
|
+
"noImplicitAny": true,
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"allowSyntheticDefaultImports": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src"],
|
|
21
|
+
"exclude": ["node_modules", "dist"]
|
|
22
|
+
}
|