react-data-matrix 0.2.0 → 0.3.2

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/README.md CHANGED
@@ -12,14 +12,49 @@ The most common usage for a table like React Matrix, is to display the **likelih
12
12
 
13
13
  # Usage
14
14
 
15
- ```js
15
+ ```ts
16
16
  import { ReactMatrix } from "react-data-matrix";
17
17
 
18
- const App = () => {
18
+ const App: FC = () => {
19
19
  ...
20
20
 
21
21
  return (
22
- <ReactMatrix data={data} {...seeOtherPropsBelow} />
22
+ <ReactMatrix
23
+ {...{
24
+ matrixName: "",
25
+ matrixDescription: "",
26
+ hasTableBorder: true,
27
+ rowPrimaryUpper: true,
28
+ hasInlineStyles: true,
29
+ matrixSizeSelected: 5,
30
+ headerPrimaryUpper: true,
31
+ hasContainerStyles: true,
32
+ reverseMatrixValues: true,
33
+
34
+ tableContainerStyles: {},
35
+ tableStyles: {},
36
+
37
+ thRowStyles: {},
38
+ thTitleStyles: {},
39
+ thSubTitleStyles: {},
40
+ thPrimaryTitleStyles: {},
41
+
42
+ trRowStyles: {},
43
+ trTitleStyles: {},
44
+ trSubTitleStyles: {},
45
+ trPrimaryTitleStyles: {},
46
+
47
+ tdStyles: {},
48
+
49
+ customHeaderRowIdValue: "",
50
+ customRowDynamicIdValue: "",
51
+ customTableDataDynamicIdValue: "",
52
+ customRowHeaderDynamicIdValue: "",
53
+ customDynamicHeaderTitleIdValue: "",
54
+ customDynamicSubHeaderTitleIdValue: "",
55
+ data,
56
+ }}
57
+ />
23
58
  )
24
59
  }
25
60
  ```
@@ -29,7 +64,7 @@ const App = () => {
29
64
  - See [`./src/lib/utils/data.js`](https://github.com/bronz3beard/react-matrix/blob/main/src/lib/utils/data.js) for an example of the data, this can be used for testing if needed,
30
65
  or an example of how to construct/deconstruct your data objects from your api.
31
66
 
32
- ```js
67
+ ```ts
33
68
  const data = {
34
69
  id: 1,
35
70
  matrix_size: 5,
@@ -83,74 +118,94 @@ const App = () => {
83
118
  }
84
119
  ```
85
120
 
86
- # PropTypes
87
-
88
- ```js
89
- propTypes = {
90
- data: PropTypes.shape({
91
- id: PropTypes.number,
92
- matrix_name: PropTypes.string,
93
- matrix_description: PropTypes.string,
94
- matrix_size: PropTypes.number.isRequired,
95
- matrix_details: PropTypes.arrayOf(
96
- PropTypes.shape({
97
- id: PropTypes.number,
98
- likelihood: PropTypes.string,
99
- consequence: PropTypes.number,
100
- header_title: PropTypes.string,
101
- header_sub_title: PropTypes.string,
102
- row_header_title: PropTypes.string,
103
- row_header_sub_title: PropTypes.string,
104
- })
105
- ).isRequired,
106
-
107
- matrix_values: PropTypes.arrayOf(
108
- PropTypes.shape({
109
- id: PropTypes.number.isRequired,
110
- colour: PropTypes.string,
111
- position: PropTypes.number.isRequired,
112
- matrix_id: PropTypes.number,
113
- score_value: PropTypes.number,
114
- description: PropTypes.string,
115
- response: PropTypes.string,
116
- likelihood_descriptor: PropTypes.string.isRequired,
117
- consequence_descriptor: PropTypes.number,
118
- })
119
- ).isRequired,
120
- }).isRequired,
121
-
122
- hasTableBorder: PropTypes.bool,
123
- hasInlineStyles: PropTypes.bool,
124
- hasContainerStyles: PropTypes.bool,
125
- reverseMatrixValues: PropTypes.bool,
126
- matrixSizeSelected: PropTypes.number,
127
-
128
- rowPrimaryUpper: PropTypes.bool,
129
- headerPrimaryUpper: PropTypes.bool,
130
-
131
- thRowStyles: PropTypes.shape({}),
132
- thTitleStyles: PropTypes.shape({}),
133
- thSubTitleStyles: PropTypes.shape({}),
134
- thPrimaryTitleStyles: PropTypes.shape({}),
135
-
136
- trRowStyles: PropTypes.shape({}),
137
- trTitleStyles: PropTypes.shape({}),
138
- trSubTitleStyles: PropTypes.shape({}),
139
- trPrimaryTitleStyles: PropTypes.shape({}),
140
-
141
- tdStyles: PropTypes.shape({}),
142
-
143
- customHeaderRowIdValue: PropTypes.string,
144
- customDynamicHeaderTitleIdValue: PropTypes.string,
145
- customDynamicSubHeaderTitleIdValue: PropTypes.string,
146
-
147
- customRowDynamicIdValue: PropTypes.string,
148
- customRowHeaderDynamicIdValue: PropTypes.string,
149
-
150
- customTableDataDynamicIdValue: PropTypes.string,
151
- };
121
+ # Types
122
+
123
+ ```ts
124
+ export interface MatrixDetail {
125
+ id: number;
126
+ position: number;
127
+ matrix_type: string;
128
+ likelihood: string;
129
+ consequence: number;
130
+ header_title: string;
131
+ header_sub_title: string;
132
+ row_header_title: string;
133
+ row_header_sub_title: string;
134
+ }
135
+
136
+ export interface MatrixValue {
137
+ id: number;
138
+ matrix_id: number;
139
+ description: string;
140
+ score_value: number;
141
+ colour: string;
142
+ position: number;
143
+ likelihood_descriptor: string;
144
+ consequence_descriptor: number;
145
+ response: string;
146
+ }
147
+
148
+ export interface MatrixData {
149
+ id: number;
150
+ matrix_size: number;
151
+ matrix_name: string;
152
+ primary_header_title: string;
153
+ primary_row_header_title: string;
154
+ matrix_description: string;
155
+ matrix_details: MatrixDetail[];
156
+ matrix_values: MatrixValue[];
157
+ }
158
+
159
+ export interface ReactMatrixProps {
160
+ data: MatrixData;
161
+ hasTableBorder?: boolean;
162
+ hasInlineStyles?: boolean;
163
+ hasContainerStyles?: boolean;
164
+ reverseMatrixValues?: boolean;
165
+ matrixSizeSelected?: number;
166
+ rowPrimaryUpper?: boolean;
167
+ headerPrimaryUpper?: boolean;
168
+ tableContainerStyles?: React.CSSProperties;
169
+ tableStyles?: React.CSSProperties;
170
+ thRowStyles?: React.CSSProperties;
171
+ thTitleStyles?: React.CSSProperties;
172
+ thSubTitleStyles?: React.CSSProperties;
173
+ thPrimaryTitleStyles?: React.CSSProperties;
174
+ trRowStyles?: React.CSSProperties;
175
+ trTitleStyles?: React.CSSProperties;
176
+ trSubTitleStyles?: React.CSSProperties;
177
+ trPrimaryTitleStyles?: React.CSSProperties;
178
+ tdStyles?: React.CSSProperties;
179
+ customHeaderRowIdValue?: string;
180
+ customDynamicHeaderTitleIdValue?: string;
181
+ customDynamicSubHeaderTitleIdValue?: string;
182
+ customRowDynamicIdValue?: string;
183
+ customRowHeaderDynamicIdValue?: string;
184
+ customTableDataDynamicIdValue?: string;
185
+ }
152
186
 
187
+ export interface TableDataProps {
188
+ data: {
189
+ id: number;
190
+ colour: string;
191
+ position: number;
192
+ matrix_id: number;
193
+ score_value: number;
194
+ description: string;
195
+ response: string;
196
+ likelihood_descriptor: string;
197
+ consequence_descriptor: number;
198
+ };
199
+ tdStyles?: React.CSSProperties;
200
+ hasInlineStyles?: boolean;
201
+ customTableDataDynamicIdValue?: string;
202
+ }
203
+ ```
204
+
205
+ ```ts
153
206
  defaultProps = {
207
+ matrixName: "",
208
+ matrixDescription: "",
154
209
  hasTableBorder: true,
155
210
  rowPrimaryUpper: true,
156
211
  hasInlineStyles: true,
@@ -159,6 +214,9 @@ defaultProps = {
159
214
  hasContainerStyles: true,
160
215
  reverseMatrixValues: true,
161
216
 
217
+ tableContainerStyles: {},
218
+ tableStyles: {},
219
+
162
220
  thRowStyles: {},
163
221
  thTitleStyles: {},
164
222
  thSubTitleStyles: {},
@@ -171,8 +229,6 @@ defaultProps = {
171
229
 
172
230
  tdStyles: {},
173
231
 
174
- matrixName: "",
175
- matrixDescription: "",
176
232
  customHeaderRowIdValue: "",
177
233
  customRowDynamicIdValue: "",
178
234
  customTableDataDynamicIdValue: "",
@@ -0,0 +1,90 @@
1
+ import React, { FC } from "react";
2
+ import {
3
+ getHeaderRowStyles,
4
+ getHeaderTitleStyles,
5
+ getHeaderSubTitleStyles,
6
+ getHeaderPrimaryTitleStyles,
7
+ } from "../helpers/getStyles";
8
+ import { capitaliseString } from "../utils/functions";
9
+ import { MatrixHeaderProps } from "../types";
10
+ // import "./styles/riskMatrix.scss";
11
+
12
+ const MatrixHeaders: FC<MatrixHeaderProps> = ({
13
+ data,
14
+ hasInlineStyles = true,
15
+ headerPrimaryUpper = true,
16
+ thRowStyles = {},
17
+ thTitleStyles = {},
18
+ thSubTitleStyles = {},
19
+ thPrimaryTitleStyles = {},
20
+ customHeaderRowIdValue = "",
21
+ customDynamicHeaderTitleIdValue = "",
22
+ customDynamicSubHeaderTitleIdValue = "",
23
+ }: MatrixHeaderProps) => {
24
+ const headerRowStyles = getHeaderRowStyles(hasInlineStyles, thRowStyles);
25
+ const headerTitleStyles = getHeaderTitleStyles(
26
+ hasInlineStyles,
27
+ thTitleStyles
28
+ );
29
+ const headerSubTitleStyles = getHeaderSubTitleStyles(
30
+ hasInlineStyles,
31
+ thSubTitleStyles
32
+ );
33
+ const headerPrimaryTitleStyles = getHeaderPrimaryTitleStyles(
34
+ hasInlineStyles,
35
+ thPrimaryTitleStyles
36
+ );
37
+
38
+ const headerPrimaryTitle = !headerPrimaryUpper
39
+ ? capitaliseString(data?.primary_header_title)
40
+ : data?.primary_header_title;
41
+
42
+ return (
43
+ <thead>
44
+ <tr id="react-matrix-blank-headers-primary-title-row">
45
+ <th headers="blank" colSpan={4}></th>
46
+ <th
47
+ style={headerPrimaryTitleStyles}
48
+ id="react-matrix-header-primary-title"
49
+ >
50
+ {headerPrimaryTitle}
51
+ </th>
52
+ <th headers="blank" colSpan={2}></th>
53
+ </tr>
54
+ <tr
55
+ style={headerRowStyles}
56
+ id={`react-matrix-dynamic-headers-row-${customHeaderRowIdValue}`}
57
+ >
58
+ <th headers="blank" colSpan={2}></th>
59
+ {data.matrix_details.slice(0, data.matrix_size).map((column, index) => {
60
+ return (
61
+ <th
62
+ scope="col"
63
+ style={headerTitleStyles}
64
+ id={`react-matrix-dynamic-column-header-title${
65
+ !customDynamicHeaderTitleIdValue
66
+ ? ""
67
+ : `-${customDynamicHeaderTitleIdValue}`
68
+ }`}
69
+ key={`${column.id}-${index}`}
70
+ >
71
+ {column.header_title}
72
+ <div
73
+ style={headerSubTitleStyles}
74
+ id={`react-matrix-dynamic-column-header-sub-title${
75
+ !customDynamicSubHeaderTitleIdValue
76
+ ? ""
77
+ : `-${customDynamicSubHeaderTitleIdValue}`
78
+ }`}
79
+ >
80
+ {column.header_sub_title}
81
+ </div>
82
+ </th>
83
+ );
84
+ })}
85
+ </tr>
86
+ </thead>
87
+ );
88
+ };
89
+
90
+ export default MatrixHeaders;
@@ -0,0 +1,115 @@
1
+ import React, { FC } from "react";
2
+ import {
3
+ getHeaderRowStyles,
4
+ getHeaderTitleStyles,
5
+ getHeaderSubTitleStyles,
6
+ getHeaderPrimaryTitleStyles,
7
+ } from "../helpers/getStyles";
8
+ import { groupObjectsByProp, capitaliseString } from "../utils/functions";
9
+ import TableData from "./TableData";
10
+ import { MatrixRowsProps, MatrixValue } from "../types";
11
+
12
+ const MatrixRows: FC<MatrixRowsProps> = ({
13
+ data,
14
+ rowPrimaryUpper = true,
15
+ hasInlineStyles = true,
16
+ reverseMatrixValues = true,
17
+ trRowStyles = {},
18
+ trTitleStyles = {},
19
+ trSubTitleStyles = {},
20
+ trPrimaryTitleStyles = {},
21
+ tdStyles = {},
22
+ customRowDynamicIdValue = "",
23
+ customRowHeaderDynamicIdValue = "",
24
+ customTableDataDynamicIdValue = "",
25
+ }: MatrixRowsProps) => {
26
+ const valuesArray = reverseMatrixValues
27
+ ? groupObjectsByProp(data.matrix_values, "likelihood_descriptor")
28
+ .reverse()
29
+ .slice(0, data.matrix_size)
30
+ : groupObjectsByProp(data.matrix_values, "likelihood_descriptor").slice(
31
+ 0,
32
+ data.matrix_size
33
+ );
34
+
35
+ const tableRowStyles = getHeaderRowStyles(hasInlineStyles, trRowStyles);
36
+ const tableRowHeaderTitleStyles = getHeaderTitleStyles(
37
+ hasInlineStyles,
38
+ trTitleStyles
39
+ );
40
+ const tableRowHeaderSubTitleStyles = getHeaderSubTitleStyles(
41
+ hasInlineStyles,
42
+ trSubTitleStyles
43
+ );
44
+ const rowHeaderPrimaryTitleStyles = getHeaderPrimaryTitleStyles(
45
+ hasInlineStyles,
46
+ trPrimaryTitleStyles
47
+ );
48
+
49
+ const rowPrimaryTitle = rowPrimaryUpper
50
+ ? capitaliseString(data.primary_row_header_title)
51
+ : data.primary_row_header_title;
52
+
53
+ return (
54
+ <tbody>
55
+ <tr id="react-matrix-row-primary-title">
56
+ <th scope="row" rowSpan={6} style={rowHeaderPrimaryTitleStyles}>
57
+ {rowPrimaryTitle}
58
+ </th>
59
+ </tr>
60
+ {valuesArray.map((row, index) => {
61
+ const rowHeaderOrder = reverseMatrixValues
62
+ ? data.matrix_size - (index + 1)
63
+ : index;
64
+
65
+ return (
66
+ <tr
67
+ style={tableRowStyles}
68
+ key={`row-${index}`}
69
+ id={`react-matrix-dynamic-rows-${
70
+ data.matrix_details[rowHeaderOrder]?.row_header_title
71
+ }-${data.matrix_details[rowHeaderOrder]?.row_header_sub_title}${
72
+ !customRowDynamicIdValue ? "" : `-${customRowDynamicIdValue}`
73
+ }`}
74
+ >
75
+ <th
76
+ scope="row"
77
+ style={tableRowHeaderTitleStyles}
78
+ id={`react-matrix-dynamic-rows-${
79
+ data.matrix_details[rowHeaderOrder]?.row_header_title
80
+ }-${data.matrix_details[rowHeaderOrder]?.row_header_sub_title}${
81
+ !customRowHeaderDynamicIdValue
82
+ ? ""
83
+ : `-${customRowHeaderDynamicIdValue}`
84
+ }`}
85
+ >
86
+ {data.matrix_details[rowHeaderOrder]?.row_header_title}
87
+ <div style={tableRowHeaderSubTitleStyles}>
88
+ {data.matrix_details[rowHeaderOrder]?.row_header_sub_title}
89
+ </div>
90
+ </th>
91
+ {row
92
+ .slice(0, data.matrix_size)
93
+ .map((item: MatrixValue, index: number) => {
94
+ return (
95
+ <TableData
96
+ data={item}
97
+ tdStyles={tdStyles}
98
+ key={`${item.id}-${index}`}
99
+ hasInlineStyles={hasInlineStyles}
100
+ customTableDataDynamicIdValue={
101
+ customTableDataDynamicIdValue
102
+ }
103
+ />
104
+ );
105
+ })}
106
+ </tr>
107
+ );
108
+ })}
109
+ </tbody>
110
+ );
111
+ };
112
+
113
+ MatrixRows.defaultProps = {};
114
+
115
+ export default MatrixRows;
@@ -0,0 +1,75 @@
1
+ import React, { FC, useContext } from "react";
2
+ import {
3
+ getTableStyles,
4
+ getTableBoarder,
5
+ getContainerStyles,
6
+ } from "../helpers/getStyles";
7
+ import MatrixHeaders from "./MatrixHeaders";
8
+ import MatrixRows from "./MatrixRows";
9
+ import { ReactMatrixProps } from "../types";
10
+
11
+ const ReactMatrix: FC<ReactMatrixProps> = ({
12
+ data,
13
+ matrixName,
14
+ tableStyles: contextTableStyles,
15
+ hasTableBorder: contextHasTableBorder,
16
+ hasInlineStyles: contextHasInlineStyles,
17
+ matrixDescription,
18
+ hasContainerStyles: contextHasContainerStyles,
19
+ tableContainerStyles: contextTableContainerStyles,
20
+
21
+ tableStyles = {},
22
+ }) => {
23
+ const tableBorder = getTableBoarder(
24
+ !!(contextHasInlineStyles && contextHasTableBorder)
25
+ );
26
+ const tableElmStyles = getTableStyles(
27
+ !!(contextHasInlineStyles && contextTableStyles),
28
+ tableStyles
29
+ );
30
+ const containerStyles = getContainerStyles(
31
+ !!(contextHasInlineStyles && contextHasContainerStyles),
32
+ contextTableContainerStyles ?? {}
33
+ );
34
+
35
+ return (
36
+ <div style={containerStyles}>
37
+ <h1>{matrixName}</h1>
38
+ <h4>{matrixDescription}</h4>
39
+ <table id="matrix-table" style={{ ...tableElmStyles, ...tableBorder }}>
40
+ <MatrixHeaders
41
+ {...{
42
+ data,
43
+ hasInlineStyles: true,
44
+ headerPrimaryUpper: true,
45
+ thRowStyles: {},
46
+ thTitleStyles: {},
47
+ thSubTitleStyles: {},
48
+ thPrimaryTitleStyles: {},
49
+ customHeaderRowIdValue: "",
50
+ customDynamicHeaderTitleIdValue: "",
51
+ customDynamicSubHeaderTitleIdValue: "",
52
+ }}
53
+ />
54
+ <MatrixRows
55
+ {...{
56
+ data,
57
+ rowPrimaryUpper: true,
58
+ hasInlineStyles: true,
59
+ reverseMatrixValues: true,
60
+ trRowStyles: {},
61
+ trTitleStyles: {},
62
+ trSubTitleStyles: {},
63
+ trPrimaryTitleStyles: {},
64
+ tdStyles: {},
65
+ customRowDynamicIdValue: "",
66
+ customRowHeaderDynamicIdValue: "",
67
+ customTableDataDynamicIdValue: "",
68
+ }}
69
+ />
70
+ </table>
71
+ </div>
72
+ );
73
+ };
74
+
75
+ export default ReactMatrix;
@@ -0,0 +1,48 @@
1
+ import React, { FC } from "react";
2
+ import { TableDataProps } from "../types";
3
+
4
+ const TableData: FC<TableDataProps> = ({
5
+ data,
6
+ tdStyles = {},
7
+ hasInlineStyles = true,
8
+ customTableDataDynamicIdValue = "",
9
+ }) => {
10
+ const handleCellClick = (tdSelected: TableDataProps["data"]) => {
11
+ alert(
12
+ `${tdSelected?.description}, ${tdSelected?.score_value} \n${tdSelected?.response}`
13
+ );
14
+ };
15
+
16
+ const customTdStyles = !tdStyles ? {} : tdStyles;
17
+ const tableDataStyles: React.CSSProperties = hasInlineStyles
18
+ ? {
19
+ cursor: "pointer",
20
+ textAlign: "center",
21
+ borderColor: "black",
22
+ borderStyle: "solid",
23
+ borderWidth: `${1}px`,
24
+ backgroundColor: data?.colour,
25
+ ...tdStyles,
26
+ }
27
+ : { ...customTdStyles };
28
+
29
+ return (
30
+ <>
31
+ <td
32
+ style={tableDataStyles}
33
+ onClick={() => handleCellClick(data)}
34
+ id={`react-matrix-dynamic-table-data${
35
+ !customTableDataDynamicIdValue
36
+ ? ""
37
+ : `-${customTableDataDynamicIdValue}`
38
+ }`}
39
+ >
40
+ {`${data?.description}`}
41
+ <br />
42
+ {`(${data?.score_value})`}
43
+ </td>
44
+ </>
45
+ );
46
+ };
47
+
48
+ export default TableData;
@@ -0,0 +1,77 @@
1
+ export const getCustomStyles = (hasStyle: boolean) =>
2
+ !hasStyle ? {} : hasStyle;
3
+
4
+ export const getContainerStyles = (
5
+ hasStyle: boolean,
6
+ styles: React.CSSProperties
7
+ ): React.CSSProperties =>
8
+ // if custom styles are passed remove default styles by returning a spread empty object
9
+ !hasStyle
10
+ ? { ...getCustomStyles(hasStyle) }
11
+ : {
12
+ top: `${50}%`,
13
+ left: `${50}%`,
14
+ height: `${100}%`,
15
+ textAlign: "center",
16
+ position: "absolute",
17
+ transform: `translate(${-50}%, ${-50}%)`,
18
+ ...styles,
19
+ };
20
+
21
+ export const getTableBoarder = (hasStyle: boolean) =>
22
+ !hasStyle ? {} : { border: `${1}px solid black` };
23
+
24
+ export const getTableStyles = (
25
+ hasStyle: boolean,
26
+ styles: React.CSSProperties
27
+ ): React.CSSProperties =>
28
+ !hasStyle
29
+ ? { ...getCustomStyles(hasStyle) }
30
+ : { width: `${70}rem`, ...styles };
31
+
32
+ export const getHeaderPrimaryTitleStyles = (
33
+ hasStyle: boolean,
34
+ styles: React.CSSProperties
35
+ ): React.CSSProperties =>
36
+ !hasStyle
37
+ ? { ...getCustomStyles(hasStyle) }
38
+ : {
39
+ borderWidth: `${0}`,
40
+ padding: `${1}rem ${0} ${1}rem ${0}`,
41
+ ...styles,
42
+ };
43
+
44
+ export const getHeaderRowStyles = (
45
+ hasStyle: boolean,
46
+ styles: React.CSSProperties
47
+ ): React.CSSProperties =>
48
+ !hasStyle
49
+ ? { ...getCustomStyles(hasStyle) }
50
+ : {
51
+ borderColor: "black",
52
+ borderStyle: "solid",
53
+ padding: `${10}rem ${0} ${0} ${0}`,
54
+ borderWidth: `${0} ${0} ${0} ${10}px`,
55
+ ...styles,
56
+ };
57
+
58
+ export const getHeaderTitleStyles = (
59
+ hasStyle: boolean,
60
+ styles: React.CSSProperties
61
+ ): React.CSSProperties =>
62
+ !hasStyle
63
+ ? { ...getCustomStyles(hasStyle) }
64
+ : {
65
+ padding: `${0} ${0.5}rem ${0} ${0.5}rem`,
66
+ backgroundColor: "light-grey",
67
+ border: `${1}px solid black`,
68
+ ...styles,
69
+ };
70
+
71
+ export const getHeaderSubTitleStyles = (
72
+ hasStyle: boolean,
73
+ styles: React.CSSProperties
74
+ ): React.CSSProperties =>
75
+ !hasStyle
76
+ ? { ...getCustomStyles(hasStyle) }
77
+ : { fontSize: `${0.9}em`, fontWeight: "normal", ...styles };
package/dist/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as ReactMatrix } from "./components/ReactMatrix";