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 ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "plugins": ["@typescript-eslint"],
4
+ "extends": ["plugin:@typescript-eslint/recommended"],
5
+ "rules": {
6
+ "@typescript-eslint/no-var-requires": "warn"
7
+ }
8
+ }
package/.prettierrc ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": true,
4
+ "printWidth": 120
5
+ }
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,6 @@
1
+ import { ReactNode } from 'react';
2
+ export default interface IResponsiveTableColumnDefinition<TData> {
3
+ displayLabel: ReactNode;
4
+ dataKey?: keyof TData;
5
+ cellRenderer: (data: TData) => ReactNode;
6
+ }
@@ -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;
@@ -0,0 +1,4 @@
1
+ import IResponsiveTableColumnDefinition from "./Data/IResponsiveTableColumnDefinition";
2
+ import ResponsiveTable from "./UI/ResponsiveTable";
3
+ export { IResponsiveTableColumnDefinition };
4
+ export default ResponsiveTable;
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
+ }
@@ -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,7 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export default interface IResponsiveTableColumnDefinition<TData> {
4
+ displayLabel: ReactNode;
5
+ dataKey?: keyof TData;
6
+ cellRenderer: (data: TData) => ReactNode;
7
+ }
@@ -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
@@ -0,0 +1,5 @@
1
+ import IResponsiveTableColumnDefinition from "./Data/IResponsiveTableColumnDefinition";
2
+ import ResponsiveTable from "./UI/ResponsiveTable";
3
+
4
+ export {IResponsiveTableColumnDefinition}
5
+ export default ResponsiveTable
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ # Update all dependencies
4
+ npm update