@fto-consult/expo-ui 2.37.8 → 2.38.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/metro.config.js +1 -0
- package/package.json +7 -6
- package/src/components/AutoResizer/index.js +104 -0
- package/src/components/Chart/appexChart/index.native.js +1 -1
- package/src/components/Chart/index.js +2 -1
- package/src/components/Datagrid/Accordion/Filters.js +0 -1
- package/src/components/Datagrid/Accordion/index.js +8 -13
- package/src/components/Datagrid/Common/Common.js +135 -51
- package/src/components/Datagrid/Common/utils.js +4 -1
- package/src/components/Datagrid/IndexComponent.js +1 -4
- package/src/components/Datagrid/SWRDatagrid.js +2 -16
- package/src/components/Datagrid/Table/index.js +10 -39
- package/src/components/Dialog/Dialog.js +0 -1
- package/src/components/Form/FormData/Dialog.js +1 -6
- package/src/components/Form/FormData/FormData.js +1 -2
- package/src/components/Form/FormData/FormDataActions.js +6 -9
- package/src/components/Hashtag/index.js +2 -2
- package/src/components/List/Common.js +0 -1
- package/src/components/Table/AbsoluteScrollView.js +3 -2
- package/src/components/Table/Cell.js +24 -0
- package/src/components/Table/Header.js +25 -0
- package/src/components/Table/List.js +196 -0
- package/src/components/Table/List.native.js +5 -0
- package/src/components/{Datagrid/Common → Table}/ProgressBar.js +0 -0
- package/src/components/Table/Row.js +21 -0
- package/src/components/Table/Test.js +0 -0
- package/src/components/Table/index.js +218 -202
- package/src/layouts/Screen/FormData/FormData.js +6 -15
- package/src/layouts/Screen/FormData/List.js +7 -8
- package/src/layouts/Screen/ScreenWithOrWithoutAuthContainer.js +4 -4
- package/src/layouts/Screen/TableData.js +6 -13
- package/src/media/file-system/utils/write.js +1 -1
- package/src/screens/Auth/Profile.js +2 -3
- package/src/screens/Auth/SignIn.js +1 -3
- package/src/screens/Help/PrivacyPolicy/index.js +1 -3
- package/src/screens/Help/TermsOfUses/index.js +1 -3
- package/src/screens/ScreenWrapper.js +82 -0
- package/src/screens/index.js +10 -68
- package/src/screens/utils.js +2 -0
- package/webpack.config.js +9 -1
- package/src/components/Datagrid/Table/Cell.js +0 -45
|
@@ -7,12 +7,9 @@ import {isWeb} from "$cplatform";
|
|
|
7
7
|
|
|
8
8
|
export default class FormDataActionComponent extends FormData {
|
|
9
9
|
isFullScreen(){
|
|
10
|
-
const mainProps = this.
|
|
10
|
+
const mainProps = this.props;
|
|
11
11
|
return typeof mainProps.fullScreen =='boolean'? mainProps.fullScreen : typeof mainProps.fullPage =='boolean'? mainProps.fullPage : mainProps.responsive !== false ? Dimensions.isMobileOrTabletMedia() : false;
|
|
12
12
|
}
|
|
13
|
-
getMainProps (){
|
|
14
|
-
return this.props;
|
|
15
|
-
}
|
|
16
13
|
getConfirmTitle(){
|
|
17
14
|
const {title,subtitle,isEditing} = this.getAppBarProps();
|
|
18
15
|
if(title){
|
|
@@ -22,13 +19,13 @@ export default class FormDataActionComponent extends FormData {
|
|
|
22
19
|
}
|
|
23
20
|
close (){}
|
|
24
21
|
getNewElementLabel(){
|
|
25
|
-
return defaultStr(this.
|
|
22
|
+
return defaultStr(this.props.newElementLabel,this.props.newElementLabel,'Nouveau');
|
|
26
23
|
}
|
|
27
24
|
getIndexFieldProps(){
|
|
28
|
-
return defaultVal(this.
|
|
25
|
+
return defaultVal(this.props.indexField,this.props.indexField);
|
|
29
26
|
}
|
|
30
27
|
getAppBarProps(){
|
|
31
|
-
const mainProps = this.
|
|
28
|
+
const mainProps = this.props;
|
|
32
29
|
const data = this.getDataProp();
|
|
33
30
|
const appBarProps = Object.assign({},mainProps.appBarProps);
|
|
34
31
|
const isEditing = this.isDocEditing(data);
|
|
@@ -57,7 +54,7 @@ export default class FormDataActionComponent extends FormData {
|
|
|
57
54
|
}
|
|
58
55
|
onBackActionPress(args,callback){
|
|
59
56
|
args = defaultObj(args);
|
|
60
|
-
const mainProps = this.
|
|
57
|
+
const mainProps = this.props;
|
|
61
58
|
const hasP = mainProps !== this.props;
|
|
62
59
|
const cb = ()=>{
|
|
63
60
|
if(typeof mainProps.onBackActionPress =='function' && mainProps.onBackActionPress(args) === false) return
|
|
@@ -89,7 +86,7 @@ export default class FormDataActionComponent extends FormData {
|
|
|
89
86
|
return isNonNullString(indexField) && isNonNullString(data[indexField])? data[indexField] : isNonNullString(data.code)? data.code : undefined;
|
|
90
87
|
}
|
|
91
88
|
getAppBarActionsProps(props){
|
|
92
|
-
props = defaultObj(props,this.
|
|
89
|
+
props = defaultObj(props,this.props);
|
|
93
90
|
let {actions,save2NewAction,save2printAction,save2closeAction,saveAction,newAction} = props;
|
|
94
91
|
const sArg = {context:this};
|
|
95
92
|
save2NewAction = typeof save2NewAction =='function' ? save2NewAction (sArg) : save2NewAction;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {isNonNullString,defaultObj} from "$utils";
|
|
2
|
-
//import dataFileManager from "$database/dataFileManager";
|
|
3
2
|
import {open as showPreloader,close as hidePreloader} from "$epreloader";
|
|
4
3
|
import Label from "$ecomponents/Label";
|
|
5
4
|
import templates from "$ecomponents/Form/Fields/sprintfSelectors";
|
|
6
5
|
import Tooltip from "$ecomponents/Tooltip";
|
|
7
6
|
import { Pressable } from "react-native";
|
|
7
|
+
import React from "$react";
|
|
8
8
|
|
|
9
9
|
/***
|
|
10
10
|
* API The component ReactHashtag is actually pretty generic. Is not something that someone can't do in half an hour. But, this one has some generic API that could make you turn.
|
|
@@ -65,7 +65,7 @@ const defaultRenderText = ({text,code,value,dbName,table,hashtag})=>{
|
|
|
65
65
|
title +=( (title)? "\n":"") +" Table : [" + table.toUpperCase()+"]";
|
|
66
66
|
}
|
|
67
67
|
if(dbName){
|
|
68
|
-
title +=( (title)? "\n":"") + dataFileManager.dataFileText +" : ["+dbName+"]";
|
|
68
|
+
//title +=( (title)? "\n":"") + dataFileManager.dataFileText +" : ["+dbName+"]";
|
|
69
69
|
}
|
|
70
70
|
return <Tooltip Component={Label} cursorPointer primary style={[{textDecorationLine:'underline'}]} title={title}>
|
|
71
71
|
{"#"+text}
|
|
@@ -171,7 +171,6 @@ const CommonListComponent = React.forwardRef((props,ref)=>{
|
|
|
171
171
|
ref = {listRef}
|
|
172
172
|
onScroll={context.onScroll}
|
|
173
173
|
data = {context.items}
|
|
174
|
-
//key = {isFlatList ? 'common-list-'+numColumns:"normal-list"}
|
|
175
174
|
numColumns={numColumns}
|
|
176
175
|
keyExtractor = {context.keyExtractor}
|
|
177
176
|
renderItem = {context.renderItem}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
4
|
|
|
5
|
-
import { ScrollView,StyleSheet,View,useWindowDimensions} from "react-native";
|
|
5
|
+
import { ScrollView,StyleSheet,View,useWindowDimensions,Dimensions} from "react-native";
|
|
6
6
|
import React from "$react";
|
|
7
7
|
import {defaultStr,defaultObj,isObj,isNumber} from "$utils";
|
|
8
8
|
import Portal from "$ecomponents/Portal";
|
|
@@ -49,7 +49,8 @@ const AbsoluteScrollView = React.forwardRef(({testID,contentProps,listRef,contai
|
|
|
49
49
|
args = defaultObj(args);
|
|
50
50
|
if(isObj(args.contentOffset) && isObj(args.contentSize)){
|
|
51
51
|
const {x} = args.contentOffset;
|
|
52
|
-
const
|
|
52
|
+
const {width} = Dimensions.get("window");
|
|
53
|
+
const visible = x >= width-10 ? false : true;
|
|
53
54
|
if(state.visible != visible){
|
|
54
55
|
return setState({...state,visible});
|
|
55
56
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
import React from "react";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import {defaultObj} from "$utils";
|
|
7
|
+
import Label from "$ecomponents/Label";
|
|
8
|
+
|
|
9
|
+
function TableCellComponent({cellArgs,rowArgs,children,renderCell,rowIndex,style,...rest}){
|
|
10
|
+
const {content,containerProps} = React.useCallback(()=>{
|
|
11
|
+
const rArgs = {...cellArgs,...rowArgs,containerProps : {}};
|
|
12
|
+
const r = typeof renderCell =='function' && renderCell (rArgs) || children;
|
|
13
|
+
return {
|
|
14
|
+
content : typeof r =='string' || typeof r =='number'? <Label children={r}/> : React.isValidElement(r)? r : null,
|
|
15
|
+
containerProps : defaultObj(rArgs.containerProps)
|
|
16
|
+
}
|
|
17
|
+
},[children])();
|
|
18
|
+
return (<View {...containerProps} {...rest} style={[style,containerProps.style]} >
|
|
19
|
+
{content}
|
|
20
|
+
</View>);
|
|
21
|
+
}
|
|
22
|
+
//const TableCellComponent = React.memo(TableCellComponent);;
|
|
23
|
+
export default TableCellComponent;
|
|
24
|
+
TableCellComponent.displayName = "TableCellComponent";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved.
|
|
6
|
+
// Use of this source code is governed by a BSD-style
|
|
7
|
+
// license that can be found in the LICENSE file.
|
|
8
|
+
import React from "$react";
|
|
9
|
+
import { View } from "react-native";
|
|
10
|
+
import PropTypes from "prop-types";
|
|
11
|
+
export default function TableHeaderComponent({cells,columns,...rest}){
|
|
12
|
+
const children = React.useCallback(()=>{
|
|
13
|
+
if(Array.isArray(cells)){
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return cells;
|
|
17
|
+
},[cells,columns])();
|
|
18
|
+
return <View {...rest}>
|
|
19
|
+
{children}
|
|
20
|
+
</View>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
TableHeaderComponent.propTypes = {
|
|
24
|
+
columns : PropTypes.arrayOf(PropTypes.bool)
|
|
25
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import {Virtuoso} from "react-virtuoso/dist/index.mjs";
|
|
6
|
+
import React from "$react";
|
|
7
|
+
import PropTypes from "prop-types";
|
|
8
|
+
import {defaultObj,defaultNumber,isDOMElement,isNumber,uniqid,isNonNullString,defaultStr} from "$utils";
|
|
9
|
+
import { View } from "react-native";
|
|
10
|
+
|
|
11
|
+
const propTypes = {
|
|
12
|
+
...defaultObj(Virtuoso.propTypes),
|
|
13
|
+
items : PropTypes.array.isRequired,
|
|
14
|
+
alignToBottom : PropTypes.bool,
|
|
15
|
+
/**Called with true / false when the list has reached the bottom / gets scrolled up. Can be used to load newer items, like tail -f. */
|
|
16
|
+
atBottomStateChange : PropTypes.func,
|
|
17
|
+
/***alias : onEndReachedThreshold */
|
|
18
|
+
atBottomThreshold : PropTypes.number,
|
|
19
|
+
atTopStateChange : PropTypes.func,
|
|
20
|
+
atTopThreshold : PropTypes.number,
|
|
21
|
+
defaultItemHeight : PropTypes.number,
|
|
22
|
+
/***(index: number) => void; Gets called when the user scrolls to the end of the list. Receives the last item index as an argument. Can be used to implement endless scrolling. */
|
|
23
|
+
endReached : PropTypes.func,
|
|
24
|
+
firstItemIndex : PropTypes.number,
|
|
25
|
+
/**(isScrolling: boolean) => void */
|
|
26
|
+
isScrolling : PropTypes.func,
|
|
27
|
+
};
|
|
28
|
+
/***@see : https://virtuoso.dev/virtuoso-api-reference/ */
|
|
29
|
+
const VirtuosoListComponent = React.forwardRef(({items,testID,renderItem,onEndReached,onLayout,onContentSizeChange,onScroll,isScrolling,estimatedItemSize,onEndReachedThreshold,containerProps,style,...props},ref)=>{
|
|
30
|
+
const r2 = {};
|
|
31
|
+
for(let i in propTypes){
|
|
32
|
+
if(i in props){
|
|
33
|
+
r2[i] = props[i];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
containerProps = defaultObj(containerProps);
|
|
37
|
+
testID = defaultStr(testID,containerProps.testID,"RN_VirtuosoListComponent");
|
|
38
|
+
const listIdRef = React.useRef(uniqid("virtuoso-list-id"));
|
|
39
|
+
const listId = listIdRef.current;
|
|
40
|
+
const listRef = React.useRef(null);
|
|
41
|
+
const sizeRef = React.useRef({width:0,height:0});
|
|
42
|
+
const listSize = sizeRef.current;
|
|
43
|
+
const isValid = ()=> listRef.current;
|
|
44
|
+
const listStyle = {height:'100%',width:"100%",overflowX:'hidden'};
|
|
45
|
+
r2["data-test-id"] = testID+"_ListContent";
|
|
46
|
+
if(isObj(estimatedItemSize)){
|
|
47
|
+
if(isNumber(estimatedItemSize.width)){
|
|
48
|
+
listStyle.width = estimatedItemSize.width+"px";
|
|
49
|
+
}
|
|
50
|
+
if(isNumber(estimatedItemSize.height)){
|
|
51
|
+
listStyle.height = estimatedItemSize.height+"px";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
React.setRef(ref,{
|
|
55
|
+
scrollToEnd : ()=>{
|
|
56
|
+
return isValid() && listRef.current.scrollToIndex && listRef.current.scrollToIndex({index:"LAST"});
|
|
57
|
+
},
|
|
58
|
+
scrollToTop : ()=>{
|
|
59
|
+
return isValid() && listRef.current.scrollToIndex && listRef.current.scrollToIndex({index:0});
|
|
60
|
+
},
|
|
61
|
+
scrollToIndex : (opts)=>{
|
|
62
|
+
opts = defaultObj(opts);
|
|
63
|
+
opts.index = defaultNumber(opts.index);
|
|
64
|
+
return isValid() && listRef.current.scrollToIndex && listRef.current.scrollToIndex(opts);
|
|
65
|
+
},
|
|
66
|
+
scrollToItem : ()=>null,
|
|
67
|
+
scrollToOffset : (opts)=>{
|
|
68
|
+
opts = defaultObj(opts);
|
|
69
|
+
opts.top = defaultNumber(opts.top,opts.offset);
|
|
70
|
+
return isValid() && listRef.current.scrollTo && listRef.current.scrollTo(opts);
|
|
71
|
+
},
|
|
72
|
+
scrollToLeft : ()=>{
|
|
73
|
+
return isValid() && listRef.current.scrollTo && listRef.current.scrollTo({left:0});
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
const checkSize = ()=>{
|
|
77
|
+
const element = document.getElementById(listId);
|
|
78
|
+
if(!element) return;
|
|
79
|
+
const target = element.firstChild?.firstChild;
|
|
80
|
+
if(isDOMElement(target) && onContentSizeChange){
|
|
81
|
+
const {nativeEvent:{contentSize}} = normalizeEvent({target});
|
|
82
|
+
setTimeout(()=>{
|
|
83
|
+
if(contentSize.width !== listSize.width || contentSize.height != listSize.height){
|
|
84
|
+
sizeRef.current = contentSize;
|
|
85
|
+
onContentSizeChange(contentSize.width,contentSize.height);
|
|
86
|
+
}
|
|
87
|
+
},100)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
React.useEffect(()=>{
|
|
91
|
+
checkSize();
|
|
92
|
+
},[props])
|
|
93
|
+
React.useEffect(()=>{
|
|
94
|
+
return ()=>{
|
|
95
|
+
React.setRef(ref,null);
|
|
96
|
+
}
|
|
97
|
+
},[]);
|
|
98
|
+
return <View {...containerProps} {...props} style={[{flex:1},containerProps.style,style,{minWidth:'100%',maxWidth:'100%'}]} onLayout={onLayout} testID={testID}>
|
|
99
|
+
<Virtuoso
|
|
100
|
+
{...r2}
|
|
101
|
+
style = {listStyle}
|
|
102
|
+
ref = {listRef}
|
|
103
|
+
data = {items}
|
|
104
|
+
id = {listId}
|
|
105
|
+
useWindowScroll = {false}
|
|
106
|
+
totalCount = {items.length}
|
|
107
|
+
itemContent = {(index)=>{
|
|
108
|
+
return renderItem({index,item:items[index],items})
|
|
109
|
+
}}
|
|
110
|
+
atBottomThreshold = {typeof onEndReachedThreshold =='number'? onEndReachedThreshold : undefined}
|
|
111
|
+
atBottomStateChange = {()=>{
|
|
112
|
+
if(typeof onEndReached =='function'){
|
|
113
|
+
onEndReached();
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
116
|
+
onScroll={(e) => onScroll && onScroll(normalizeEvent(e))}
|
|
117
|
+
isScrolling = {(isC,a)=>{
|
|
118
|
+
if(typeof isScrolling =='function'){
|
|
119
|
+
return isScrolling(isC);
|
|
120
|
+
}
|
|
121
|
+
}}
|
|
122
|
+
defaultItemHeight = {typeof estimatedItemSize=='number' && estimatedItemSize || undefined}
|
|
123
|
+
/>
|
|
124
|
+
</View>
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
VirtuosoListComponent.propTypes = {
|
|
128
|
+
...propTypes
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
VirtuosoListComponent.displayName = "VirtuosoListComponent";
|
|
132
|
+
|
|
133
|
+
export default VirtuosoListComponent;
|
|
134
|
+
|
|
135
|
+
function isScrollable (node){
|
|
136
|
+
if(!node) return false;
|
|
137
|
+
const dim = dimensions(node);
|
|
138
|
+
if(!dim) return false;
|
|
139
|
+
if(dim.scrollHeight>dim.clientHeight) return true;
|
|
140
|
+
if(dim.totalHeight > (dim.clientHeight+dim.scrollHeight+100)) return true;
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
function lookupForContent (node,level){
|
|
144
|
+
if(!node || !isDOMElement(node) || level>=5) return null;
|
|
145
|
+
if(typeof level !='number'){
|
|
146
|
+
level = 0;
|
|
147
|
+
}
|
|
148
|
+
console.log("looking for ",node,level,dimensions(node));
|
|
149
|
+
if(isScrollable(node)){
|
|
150
|
+
return node;
|
|
151
|
+
}
|
|
152
|
+
return lookupForContent(node.querySelector("div:first-child"),level+1)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function dimensions(el) {
|
|
156
|
+
if(!isDOMElement(el)) return null;
|
|
157
|
+
var elHeight = el.offsetHeight;
|
|
158
|
+
const marginBottom = parseInt(window.getComputedStyle(el).getPropertyValue('margin-bottom'));
|
|
159
|
+
const paddingBottom = parseInt(window.getComputedStyle(el).getPropertyValue('padding-bottom'));
|
|
160
|
+
return {
|
|
161
|
+
height:elHeight,marginBottom,paddingBottom,totalHeight : elHeight+marginBottom+paddingBottom,
|
|
162
|
+
width : el.offsetWidth,scrollHeight : el.scrollHeight,clientHeight : el.clientHeight,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const normalizeEvent = (e)=>{
|
|
167
|
+
return {
|
|
168
|
+
nativeEvent: {
|
|
169
|
+
contentOffset: {
|
|
170
|
+
get x() {
|
|
171
|
+
return e.target.scrollLeft;
|
|
172
|
+
},
|
|
173
|
+
get y() {
|
|
174
|
+
return e.target.scrollTop;
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
contentSize: {
|
|
178
|
+
get height() {
|
|
179
|
+
return e.target.scrollHeight;
|
|
180
|
+
},
|
|
181
|
+
get width() {
|
|
182
|
+
return e.target.scrollWidth;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
layoutMeasurement: {
|
|
186
|
+
get height() {
|
|
187
|
+
return e.target.offsetHeight;
|
|
188
|
+
},
|
|
189
|
+
get width() {
|
|
190
|
+
return e.target.offsetWidth;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
timeStamp: Date.now()
|
|
195
|
+
};
|
|
196
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
import React from "$react";
|
|
5
|
+
import { View } from "react-native";
|
|
6
|
+
import PropTypes from "prop-types";
|
|
7
|
+
export default function TableRowComponent({cells,columns,...rest}){
|
|
8
|
+
const children = React.useCallback(()=>{
|
|
9
|
+
if(Array.isArray(cells)){
|
|
10
|
+
return cells.map((cell,index)=>columns[index]? <React.Fragment key={index}>{cell}</React.Fragment> : null )
|
|
11
|
+
}
|
|
12
|
+
return cells;
|
|
13
|
+
},[cells,columns])();
|
|
14
|
+
return <View {...rest}>
|
|
15
|
+
{children}
|
|
16
|
+
</View>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
TableRowComponent.propTypes = {
|
|
20
|
+
columns : PropTypes.arrayOf(PropTypes.bool)
|
|
21
|
+
}
|
|
File without changes
|