@fto-consult/expo-ui 2.5.0 → 2.5.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/package.json +1 -1
- package/src/components/BottomSheet/Menu.js +4 -2
- package/src/components/Datagrid/Accordion/index.js +6 -5
- package/src/components/Datagrid/Common/Common.js +26 -11
- package/src/components/Datagrid/Footer/Footer.js +10 -12
- package/src/components/Datagrid/Table/index.js +29 -42
- package/src/components/Date/DatePickerInput/index.js +1 -1
- package/src/components/Date/DateTime.js +11 -6
- package/src/components/Date/Time.js +5 -1
- package/src/components/DragResize/Connector.js +132 -0
- package/src/components/DragResize/DragResizeBlock.js +809 -0
- package/src/components/DragResize/DragResizeContainer.js +52 -0
- package/src/components/DragResize/index.js +42 -0
- package/src/components/Dropdown/index.js +4 -5
- package/src/components/Filter/index.js +16 -8
- package/src/components/Resizable/index.js +7 -0
- package/src/components/Resizable/index.web.js +33 -0
- package/src/components/Table/AbsoluteScrollView.js +38 -10
- package/src/components/Table/index.js +78 -30
- package/src/components/TextField/index.js +2 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright 2022 @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
|
+
/***Fork of https://github.com/CaptainOmega/react-native-drag-resize components */
|
|
5
|
+
import React, {PureComponent} from 'react';
|
|
6
|
+
import {
|
|
7
|
+
View,
|
|
8
|
+
} from 'react-native';
|
|
9
|
+
import PropTypes from 'prop-types';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Drag resize container.
|
|
13
|
+
* Allow calculate limitation by container size.
|
|
14
|
+
*/
|
|
15
|
+
export class DragResizeContainer extends PureComponent {
|
|
16
|
+
|
|
17
|
+
render() {
|
|
18
|
+
const {
|
|
19
|
+
style,
|
|
20
|
+
onInit,
|
|
21
|
+
children,
|
|
22
|
+
} = this.props;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View
|
|
26
|
+
ref={view => {
|
|
27
|
+
this.canvas = view;
|
|
28
|
+
}}
|
|
29
|
+
style={style}
|
|
30
|
+
onLayout={() => {
|
|
31
|
+
this.canvas.measure(
|
|
32
|
+
(fx, fy, w, h, x, y) => {
|
|
33
|
+
onInit({
|
|
34
|
+
x: 0,
|
|
35
|
+
y: 0,
|
|
36
|
+
w,
|
|
37
|
+
h,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
</View>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
DragResizeContainer.propTypes = {
|
|
50
|
+
onInit: PropTypes.func.isRequired,
|
|
51
|
+
style: PropTypes.object,
|
|
52
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright 2022 @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
|
+
/***Fork of https://github.com/CaptainOmega/react-native-drag-resize components */
|
|
5
|
+
import {defaultNumber} from "$utils";
|
|
6
|
+
import React from "$react";
|
|
7
|
+
export default function DragResizeComponent ({x,y,width,height,onResize,...props}){
|
|
8
|
+
x = defaultNumber(x); y = defaultNumber(y);
|
|
9
|
+
const [resize, setResize] = React.useState([x, y]);
|
|
10
|
+
return <DragResizeBlock
|
|
11
|
+
w = {width}
|
|
12
|
+
h = {height}
|
|
13
|
+
{...props}
|
|
14
|
+
x={resize[0]}
|
|
15
|
+
y={resize[1]}
|
|
16
|
+
onResize={(value) => setResize(value)}
|
|
17
|
+
/>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
DragResizeBlock,
|
|
23
|
+
AXIS_X,
|
|
24
|
+
AXIS_Y,
|
|
25
|
+
AXIS_ALL,
|
|
26
|
+
} from './DragResizeBlock';
|
|
27
|
+
import {DragResizeBlock} from "./DragResizeBlock"
|
|
28
|
+
export {
|
|
29
|
+
DragResizeContainer,
|
|
30
|
+
} from './DragResizeContainer';
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
CONNECTOR_TOP_LEFT,
|
|
34
|
+
CONNECTOR_TOP_MIDDLE,
|
|
35
|
+
CONNECTOR_TOP_RIGHT,
|
|
36
|
+
CONNECTOR_MIDDLE_RIGHT,
|
|
37
|
+
CONNECTOR_BOTTOM_RIGHT,
|
|
38
|
+
CONNECTOR_BOTTOM_MIDDLE,
|
|
39
|
+
CONNECTOR_BOTTOM_LEFT,
|
|
40
|
+
CONNECTOR_MIDDLE_LEFT,
|
|
41
|
+
CONNECTOR_CENTER,
|
|
42
|
+
} from './Connector';
|
|
@@ -745,9 +745,10 @@ class DropdownComponent extends AppComponent {
|
|
|
745
745
|
const inputRest = {disabled,editable,label,error}
|
|
746
746
|
clearTimeout(this.doSearchFilter);
|
|
747
747
|
this.doSearchFilter = null;
|
|
748
|
-
|
|
748
|
+
mode = defaultStr(mode,inputProps.mode);
|
|
749
749
|
const textInputProps = {
|
|
750
750
|
...inputRest,
|
|
751
|
+
mode,
|
|
751
752
|
editable,disabled,
|
|
752
753
|
style : StyleSheet.flatten([styles.input,inputProps.style])
|
|
753
754
|
}
|
|
@@ -840,8 +841,7 @@ class DropdownComponent extends AppComponent {
|
|
|
840
841
|
}
|
|
841
842
|
helperText = <HelperText disabled = {disabled} error={error}>{helperText}</HelperText>
|
|
842
843
|
let labelTextField = defaultVal(label,text);
|
|
843
|
-
|
|
844
|
-
const isFlatMode = textInputProps.mode === flatMode;
|
|
844
|
+
const isFlatMode = textInputProps.mode === flatMode;
|
|
845
845
|
let backgroundColor = Colors.isValid(textInputProps.style.backgroundColor)?textInputProps.style.backgroundColor : Colors.isValid(flattenStyle.backgroundColor)? flattenStyle.backgroundColor : theme.colors.surface;
|
|
846
846
|
const tagLabelStyle = {backgroundColor,color:Colors.setAlpha(theme.colors.text,theme.ALPHA)}
|
|
847
847
|
if(!isFlatMode && backgroundColor ==='transparent'){
|
|
@@ -904,9 +904,9 @@ class DropdownComponent extends AppComponent {
|
|
|
904
904
|
defaultValue={selectedText}
|
|
905
905
|
autoHeight = {renderTag}
|
|
906
906
|
useReadOnlyOpacity = {false}
|
|
907
|
-
mode = {mode}
|
|
908
907
|
{...inputProps}
|
|
909
908
|
{...textInputProps}
|
|
909
|
+
mode = {mode}
|
|
910
910
|
enableCopy = {enableCopy}
|
|
911
911
|
label = {labelTextField}
|
|
912
912
|
pointerEvents = "none"
|
|
@@ -1270,7 +1270,6 @@ DropdownComponent.propTypes = {
|
|
|
1270
1270
|
onUnmount : PropTypes.func,
|
|
1271
1271
|
label : PropTypes.string,
|
|
1272
1272
|
placeholder : PropTypes.string,
|
|
1273
|
-
mode : PropTypes.oneOf(["outlined", "flat"]),
|
|
1274
1273
|
inputProps : PropTypes.object,
|
|
1275
1274
|
selectedColor:PropTypes.string,
|
|
1276
1275
|
accessibilityLabel : PropTypes.string,
|
|
@@ -24,6 +24,7 @@ export * from "./utils";
|
|
|
24
24
|
|
|
25
25
|
const _actions = {
|
|
26
26
|
'$eq' : 'Egal à',
|
|
27
|
+
"$ne" : 'Défférent de',
|
|
27
28
|
'$gt' : 'Supérieur à',
|
|
28
29
|
'$gte' : 'Supérieur ou égal',
|
|
29
30
|
'$lt' : 'Inférieur à',
|
|
@@ -135,6 +136,10 @@ export default class Filter extends AppComponent {
|
|
|
135
136
|
this.props.onValidate({...this.getStateValues(),field:this.props.name,...arg})
|
|
136
137
|
}
|
|
137
138
|
}
|
|
139
|
+
isDecimal(){
|
|
140
|
+
const t = defaultStr(this.type,this.props.type).toLowerCase();
|
|
141
|
+
return t =="number" || t =='decimal' ? true : false;
|
|
142
|
+
}
|
|
138
143
|
onFilterValidate(arg){
|
|
139
144
|
arg = defaultObj(arg);
|
|
140
145
|
if(JSON.stringify(this.state.defaultValue) === JSON.stringify(arg.value)){
|
|
@@ -190,11 +195,15 @@ export default class Filter extends AppComponent {
|
|
|
190
195
|
value = undefined;
|
|
191
196
|
}
|
|
192
197
|
let originValue = value;
|
|
193
|
-
const type = defaultStr(this.props.type).toLowerCase().trim();
|
|
194
|
-
value = parseDecimal(value,type);
|
|
195
198
|
if(action =="$today" || action =='$yesterday'){
|
|
196
199
|
force = true;
|
|
197
200
|
}
|
|
201
|
+
if(this.isDecimal()){
|
|
202
|
+
value = parseDecimal(value)
|
|
203
|
+
if(value == 0){
|
|
204
|
+
value = undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
198
207
|
const prev = JSON.stringify(defaultObj(this.previousRef.current)), current = {value,operator,action,ignoreCase};
|
|
199
208
|
let tV = isArray(value) && value.length <= 0 ? undefined : value;
|
|
200
209
|
this.isInitializedRef.current = this.props.dynamicRendered || this.isInitializedRef.current;
|
|
@@ -290,8 +299,7 @@ export default class Filter extends AppComponent {
|
|
|
290
299
|
if(data.start && data.end && data.start> data.end){
|
|
291
300
|
return notify.error("La date de fin doit être supérieure à la date de début");
|
|
292
301
|
}
|
|
293
|
-
|
|
294
|
-
if(isFunction(success)){
|
|
302
|
+
if(isFunction(success)){
|
|
295
303
|
success(data.start+"=>"+data.end);
|
|
296
304
|
}
|
|
297
305
|
DialogProvider.close();
|
|
@@ -325,7 +333,6 @@ export default class Filter extends AppComponent {
|
|
|
325
333
|
break;
|
|
326
334
|
case "$week":
|
|
327
335
|
diff = DateLib.currentWeekDaysLimits(currentDate);
|
|
328
|
-
console.log(diff," is diffffff");
|
|
329
336
|
break;
|
|
330
337
|
case "$prevWeek":
|
|
331
338
|
diff = DateLib.previousWeekDaysLimits(currentDate)
|
|
@@ -383,8 +390,8 @@ export default class Filter extends AppComponent {
|
|
|
383
390
|
field,
|
|
384
391
|
style,
|
|
385
392
|
anchorProps,
|
|
386
|
-
mode,
|
|
387
|
-
inputProps,
|
|
393
|
+
//mode,
|
|
394
|
+
//inputProps,
|
|
388
395
|
moreOptions,
|
|
389
396
|
isLoading,
|
|
390
397
|
searchIconTooltip,
|
|
@@ -472,6 +479,7 @@ export default class Filter extends AppComponent {
|
|
|
472
479
|
}
|
|
473
480
|
anchorProps = defaultObj(anchorProps);
|
|
474
481
|
rest.anchorProps = anchorProps;
|
|
482
|
+
rest.withLabel = withLabel;
|
|
475
483
|
rest.pointerEvents = "auto";
|
|
476
484
|
rest.right = isLoading ? <ActivityIndicator color={theme.colors.secondaryOnSurface} animating/> :<>
|
|
477
485
|
<Menu
|
|
@@ -557,7 +565,7 @@ export default class Filter extends AppComponent {
|
|
|
557
565
|
if(ignoreDefaultValue) {
|
|
558
566
|
rest.isPeriodAction = true;
|
|
559
567
|
}
|
|
560
|
-
return <View testID={testID+"_FilterContainer"} {...containerProps} style={[theme.styles.w100,containerProps.style]}>
|
|
568
|
+
return <View testID={testID+"_FilterContainer"} {...containerProps} style={StyleSheet.flatten([theme.styles.w100,containerProps.style])}>
|
|
561
569
|
<Component
|
|
562
570
|
{...rest}
|
|
563
571
|
readOnly = {ignoreDefaultValue}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright 2022 @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 { Resizable } from 'react-resizable';
|
|
6
|
+
import React from "$react";
|
|
7
|
+
import {defaultObj} from "$utils";
|
|
8
|
+
import PropTypes from "prop-types";
|
|
9
|
+
|
|
10
|
+
const ResizableComponent = React.forwardRef(({width,onResize,height,...props},ref)=>{
|
|
11
|
+
const [state,setState] = React.useState({
|
|
12
|
+
width,
|
|
13
|
+
height,
|
|
14
|
+
});
|
|
15
|
+
return <Resizable {...props} height={state.height} width={state.width} onResize={(event, {element, size, handle}) => {
|
|
16
|
+
setState({width: size.width, height: size.height});
|
|
17
|
+
if(onResize){
|
|
18
|
+
onResize({...size,element,handle,event});
|
|
19
|
+
}
|
|
20
|
+
}}>
|
|
21
|
+
|
|
22
|
+
</Resizable>
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
ResizableComponent.displayName ="ResizableComponent";
|
|
26
|
+
|
|
27
|
+
export default ResizableComponent;
|
|
28
|
+
|
|
29
|
+
ResizableComponent.propTypes = {
|
|
30
|
+
...defaultObj(Resizable.propTypes),
|
|
31
|
+
width : PropTypes.oneOfType([PropTypes.number,PropTypes.string]),
|
|
32
|
+
height : PropTypes.oneOfType([PropTypes.number,PropTypes.string])
|
|
33
|
+
}
|
|
@@ -4,31 +4,59 @@
|
|
|
4
4
|
|
|
5
5
|
import { ScrollView,StyleSheet,View,useWindowDimensions} from "react-native";
|
|
6
6
|
import React from "$react";
|
|
7
|
-
import {defaultStr,defaultObj,isObj} from "$utils";
|
|
7
|
+
import {defaultStr,defaultObj,isObj,isNumber} from "$utils";
|
|
8
8
|
import Portal from "$ecomponents/Portal";
|
|
9
|
+
import {isMobileNative,isTouchDevice} from "$platform";
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const isNative = isMobileNative() || isTouchDevice();
|
|
12
|
+
const AbsoluteScrollView = React.forwardRef(({testID,contentProps,listRef,containerProps,...props},ref)=>{
|
|
13
|
+
if(isNative) return null;
|
|
11
14
|
containerProps = defaultObj(containerProps);
|
|
12
15
|
contentProps = defaultObj(contentProps);
|
|
13
16
|
const win = useWindowDimensions();
|
|
14
17
|
const scrollViewRef = React.useRef(null);
|
|
15
18
|
testID = defaultStr(testID,"RN_TableAbsoluteScrollViewComponent");
|
|
16
|
-
const [
|
|
19
|
+
const [state,setState] = React.useState({
|
|
20
|
+
styles : {},
|
|
21
|
+
visible : true,
|
|
22
|
+
})
|
|
23
|
+
const {styles,visible} = state,setStyles = (s)=>{
|
|
24
|
+
if(isObj(s)){
|
|
25
|
+
setState({...state,styles:{...styles,...s}});
|
|
26
|
+
}
|
|
27
|
+
},toggleVisible = ()=>{
|
|
28
|
+
if(isObj(styles.content) && isObj(styles.container)){
|
|
29
|
+
const visible = isNumber(styles.content.height) && isNumber(styles.container.height) && (styles.content.height-20)> styles.container.height? true : false;
|
|
30
|
+
if(visible != state.visible){
|
|
31
|
+
setState({...state,visible});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
17
35
|
React.setRef(ref,{
|
|
18
|
-
setStyles
|
|
19
|
-
|
|
20
|
-
|
|
36
|
+
setStyles,
|
|
37
|
+
checkVisibility : (args)=>{
|
|
38
|
+
args = defaultObj(args);
|
|
39
|
+
if(isObj(args.contentOffset) && isObj(args.contentSize)){
|
|
40
|
+
const {x} = args.contentOffset;
|
|
41
|
+
const visible = x >=win.width ? false : true;
|
|
42
|
+
if(state.visible != visible){
|
|
43
|
+
return setState({...state,visible});
|
|
44
|
+
}
|
|
21
45
|
}
|
|
46
|
+
return toggleVisible();
|
|
22
47
|
},
|
|
23
48
|
scrollViewRef
|
|
24
|
-
})
|
|
49
|
+
});
|
|
25
50
|
React.useEffect(()=>{
|
|
26
51
|
return ()=>{
|
|
27
52
|
React.setRef(ref,null);
|
|
28
53
|
}
|
|
29
|
-
},[])
|
|
54
|
+
},[]);
|
|
55
|
+
React.useEffect(()=>{
|
|
56
|
+
toggleVisible();
|
|
57
|
+
},[styles])
|
|
30
58
|
return <Portal>
|
|
31
|
-
<View testID={testID+"_Containter"} {...containerProps} style={[mainStyles.container,containerProps.style,styles.container,{left:win.width-10}]}>
|
|
59
|
+
{<View testID={testID+"_Containter"} {...containerProps} style={[mainStyles.container,containerProps.style,styles.container,{left:win.width-10},!visible &&{display:'none',width:0,opacity:0}]}>
|
|
32
60
|
<ScrollView
|
|
33
61
|
{...props}
|
|
34
62
|
ref = {scrollViewRef}
|
|
@@ -42,7 +70,7 @@ const AbsoluteScrollView = React.forwardRef(({testID,contentProps,containerProps
|
|
|
42
70
|
style={[mainStyles.content,contentProps.style,styles.content]}
|
|
43
71
|
/>
|
|
44
72
|
</ScrollView>
|
|
45
|
-
</View>
|
|
73
|
+
</View>}
|
|
46
74
|
</Portal>
|
|
47
75
|
});
|
|
48
76
|
|
|
@@ -10,6 +10,7 @@ import { getRowStyle } from "$ecomponents/Datagrid/utils";
|
|
|
10
10
|
import {isMobileNative} from "$cplatform";
|
|
11
11
|
import theme from "$theme";
|
|
12
12
|
import AbsoluteScrollView from "./AbsoluteScrollView";
|
|
13
|
+
import DragResize,{CONNECTOR_MIDDLE_RIGHT} from "$ecomponents/DragResize";
|
|
13
14
|
|
|
14
15
|
const isSCrollingRef = React.createRef();
|
|
15
16
|
const scrollLists = (opts,refs)=>{
|
|
@@ -42,7 +43,7 @@ const getOnScrollCb = (refs,pos,cb2)=>{
|
|
|
42
43
|
return isMobileNative()? cb : debounce(cb,200);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScrollViewProps,footerScrollViewProps,scrollViewProps,showFooters,renderFooterCell,footerCellContainerProps,headerContainerProps,headerCellContainerProps,headerProps,rowProps:customRowProps,renderCell,cellContainerProps,hasFooters,renderHeaderCell,columnProps,getRowKey,columnsWidths,colsWidths,footerContainerProps,showFilters,columns,data,testID,...props},tableRef)=>{
|
|
46
|
+
const TableComponent = React.forwardRef(({containerProps,renderEmpty,isRowSelected,headerScrollViewProps,footerScrollViewProps,scrollViewProps,showFooters,renderFooterCell,footerCellContainerProps,filterCellContainerProps,headerContainerProps,headerCellContainerProps,headerProps,rowProps:customRowProps,renderCell,cellContainerProps,hasFooters,renderHeaderCell,renderFilterCell,columnProps,getRowKey,columnsWidths,colsWidths,footerContainerProps,showFilters,columns,data,testID,...props},tableRef)=>{
|
|
46
47
|
containerProps = defaultObj(containerProps);
|
|
47
48
|
testID = defaultStr(testID,"RN_TableComponent");
|
|
48
49
|
cellContainerProps = defaultObj(cellContainerProps);
|
|
@@ -53,13 +54,14 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
53
54
|
const getRowProps = typeof rowProps ==='function'? rowProps : undefined;
|
|
54
55
|
let rowProps = isObj(customRowProps)? customRowProps:{};
|
|
55
56
|
const prepareState = React.useCallback(()=>{
|
|
56
|
-
const cols = {},headers = {},footers = {},visibleColumns = [];
|
|
57
|
+
const cols = {},headers = {},footers = {},filters = {},visibleColumns = [];
|
|
57
58
|
let hasFooters = false;
|
|
58
59
|
columnProps = defaultObj(columnProps);
|
|
59
60
|
let columnIndex = 0;
|
|
60
61
|
const widths = defaultObj(columnsWidths,colsWidths);
|
|
61
62
|
headerCellContainerProps = defaultObj(headerCellContainerProps);
|
|
62
63
|
footerCellContainerProps = defaultObj(footerCellContainerProps);
|
|
64
|
+
filterCellContainerProps = defaultObj(filterCellContainerProps);
|
|
63
65
|
Object.map(columns,(columnDef,field)=>{
|
|
64
66
|
if(!isObj(columnDef) /*|| columnDef.visible === false*/) return;
|
|
65
67
|
const columnField = defaultStr(columnDef.field,field);
|
|
@@ -68,7 +70,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
68
70
|
type = defaultStr(type,"text").toLowerCase().trim();
|
|
69
71
|
colProps = defaultObj(colProps);
|
|
70
72
|
width = defaultDecimal(widths[columnField],width,DEFAULT_COLUMN_WIDTH);
|
|
71
|
-
const style = [colProps.style,{width}];
|
|
73
|
+
const style = StyleSheet.flatten([colProps.style,{width}]);
|
|
72
74
|
const colArgs = {width,type,style,columnDef,containerProps:{},columnField,index:columnIndex,columnIndex};
|
|
73
75
|
let content = typeof renderHeaderCell =='function'? renderHeaderCell(colArgs) : defaultVal(columnDef.text,columnDef.label,columnField);
|
|
74
76
|
let hContainerProps = {};
|
|
@@ -82,9 +84,16 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
82
84
|
console.error(content," is not valid element of header ",columnDef," it could not be render on table");
|
|
83
85
|
return null;
|
|
84
86
|
}
|
|
87
|
+
|
|
85
88
|
headers[columnField] = <View testID={testID+"_HeaderCell_"+columnField} {...headerCellContainerProps} {...hContainerProps} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,headerCellContainerProps.style,hContainerProps.style,style]}>
|
|
86
|
-
<Label textBold primary>{content}</Label>
|
|
89
|
+
<Label style={[theme.styles.w100,theme.styles.h100]} textBold primary>{content}</Label>
|
|
87
90
|
</View>;
|
|
91
|
+
if(typeof renderFilterCell =='function'){
|
|
92
|
+
const filterCell = renderFilterCell(colArgs);
|
|
93
|
+
filters[columnField] = <View testID={testID+"_Filter_Cell_"+columnField} {...filterCellContainerProps} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,styles.filterCell,filterCellContainerProps.style,style]}>
|
|
94
|
+
{React.isValidElement(filterCell)? filterCell : null}
|
|
95
|
+
</View>
|
|
96
|
+
}
|
|
88
97
|
if(typeof renderFooterCell ==='function') {
|
|
89
98
|
const footerProps = {...colArgs,containerProps:{}};
|
|
90
99
|
let cellFooter = renderFooterCell(footerProps);
|
|
@@ -99,7 +108,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
99
108
|
if(!hasFooters && cellFooter){
|
|
100
109
|
hasFooters = true;
|
|
101
110
|
}
|
|
102
|
-
footers[columnField] = <View testID={testID+"_Footer_Cell_"+columnField}
|
|
111
|
+
footers[columnField] = <View testID={testID+"_Footer_Cell_"+columnField} key={columnField} style={[styles.headerItem,styles.headerItemOrCell,footerCellContainerProps.style,style]}>
|
|
103
112
|
<Label primary children={cellFooter}/>
|
|
104
113
|
</View>
|
|
105
114
|
}
|
|
@@ -116,7 +125,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
116
125
|
}
|
|
117
126
|
columnIndex++;
|
|
118
127
|
});
|
|
119
|
-
return {columns:cols,visibleColumns,headers,hasFooters,footers};
|
|
128
|
+
return {columns:cols,visibleColumns,headers,hasFooters,footers,filters};
|
|
120
129
|
},[columns,data]);
|
|
121
130
|
const [state,setState] = React.useState({
|
|
122
131
|
headers : {},
|
|
@@ -129,11 +138,13 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
129
138
|
React.useEffect(()=>{
|
|
130
139
|
setState({...state,...prepareState()});
|
|
131
140
|
},[data,columns]);
|
|
132
|
-
const
|
|
141
|
+
const emptyData = typeof renderEmpty =='function' && !Object.size(data,true)? renderEmpty() : null;
|
|
142
|
+
const hasEmptyData = emptyData && React.isValidElement(emptyData);
|
|
143
|
+
const {visibleColumns,columns:cols,headers,footers,filters} = state;
|
|
133
144
|
headerContainerProps = defaultObj(headerContainerProps);
|
|
134
145
|
footerContainerProps = defaultObj(footerContainerProps);
|
|
135
146
|
let hProps = typeof headerProps =='function'? hProps({columns:col,visibleColumns}) : {};
|
|
136
|
-
const h = [],f = [];
|
|
147
|
+
const h = [],f = [],fFilters = [];
|
|
137
148
|
let totalWidths = 0;
|
|
138
149
|
visibleColumns.map((i)=>{
|
|
139
150
|
if(!isObj(cols[i])) return;
|
|
@@ -142,6 +153,9 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
142
153
|
if(showFooters && state.hasFooters){
|
|
143
154
|
f.push(footers[i]);
|
|
144
155
|
}
|
|
156
|
+
if(showFilters && filters[i]){
|
|
157
|
+
fFilters.push(filters[i]);
|
|
158
|
+
}
|
|
145
159
|
});
|
|
146
160
|
const scrollContentContainerStyle = {flex:1,width:listWidth,minWidth:totalWidths,height:'100%'};
|
|
147
161
|
const scrollEventThrottle = isMobileNative()?200:50;
|
|
@@ -150,7 +164,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
150
164
|
scrollEventThrottle,
|
|
151
165
|
horizontal : true,
|
|
152
166
|
...scrollViewProps,
|
|
153
|
-
style : [
|
|
167
|
+
style : [scrollViewProps.style],
|
|
154
168
|
contentContainerStyle : [styles.scrollView,scrollViewProps.contentContainerStyle,scrollViewFlexGrow,scrollContentContainerStyle]
|
|
155
169
|
}
|
|
156
170
|
const listWidth = '100%';
|
|
@@ -187,15 +201,19 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
187
201
|
const hContent = h.length ? <View testID={testID+"_Header"}{...hProps} {...headerContainerProps} style={[styles.header,headerContainerProps.style,hProps.style,f.length]}>
|
|
188
202
|
{h}
|
|
189
203
|
</View> : null,
|
|
190
|
-
|
|
204
|
+
fContent = f.length ? <View testID={testID+"_Footer"} {...footerContainerProps} style={[styles.header,styles.footers,footerContainerProps.style,theme.styles.pt0,theme.styles.pb0,theme.styles.ml0,theme.styles.mr0]}>
|
|
191
205
|
{f}
|
|
192
|
-
</View> : null
|
|
206
|
+
</View> : null,
|
|
207
|
+
filtersContent = fFilters.length ? <View testID={testID+"_Filters"} style={[styles.header,styles.footers,theme.styles.pt0,theme.styles.pb0,theme.styles.ml0,theme.styles.mr0]}>
|
|
208
|
+
{fFilters}
|
|
209
|
+
</View> : null
|
|
210
|
+
|
|
193
211
|
const absoluteScrollViewRefCanScroll = React.useRef(true);
|
|
194
212
|
React.setRef(tableRef,context);
|
|
195
213
|
const cStyle = {width:listWidth}
|
|
196
214
|
const absoluteScrollViewRef = React.useRef(null);
|
|
197
|
-
return <View testID= {testID+"_Container"} {...containerProps} style={[styles.container,{alignItems:'stretch'},containerProps.style]}>
|
|
198
|
-
<
|
|
215
|
+
return <View testID= {testID+"_Container"} {...containerProps} style={[styles.container,{alignItems:'stretch'},containerProps.style,theme.styles.pl0,theme.styles.pr0]}>
|
|
216
|
+
<RNView style={[cStyle]} testID={testID+"_Headers_ScrollViewContainer"}>
|
|
199
217
|
<ScrollView
|
|
200
218
|
testID={testID+"_HeaderScrollView"}
|
|
201
219
|
{...headerScrollViewProps}
|
|
@@ -205,12 +223,22 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
205
223
|
onScroll = {getOnScrollCb([scrollViewRef,footerScrollViewRef])}
|
|
206
224
|
showsHorizontalScrollIndicator
|
|
207
225
|
>
|
|
208
|
-
{
|
|
226
|
+
<View testID={testID+"Header2FootersWrapper"} style={[theme.styles.w100]}>
|
|
227
|
+
{hContent}
|
|
228
|
+
{filtersContent}
|
|
229
|
+
{fContent}
|
|
230
|
+
</View>
|
|
209
231
|
</ScrollView>
|
|
210
|
-
</
|
|
211
|
-
|
|
232
|
+
</RNView>
|
|
233
|
+
{hasEmptyData ? <View testID={testID+"_Empty"} style={styles.hasNotData}>
|
|
234
|
+
{emptyData}
|
|
235
|
+
</View> : <ScrollView {...scrollViewProps} scrollEventThrottle = {scrollEventThrottle} horizontal contentContainerStyle={[scrollContentContainerStyle,scrollViewProps.contentContainerStyle]} showsVerticalScrollIndicator={false}
|
|
212
236
|
onScroll = {getOnScrollCb([headerScrollViewRef,footerScrollViewRef],null,(args)=>{
|
|
213
|
-
|
|
237
|
+
const nativeEvent = args.nativeEvent;
|
|
238
|
+
if(absoluteScrollViewRef.current && absoluteScrollViewRef.current.checkVisibility){
|
|
239
|
+
absoluteScrollViewRef.current.checkVisibility(nativeEvent);
|
|
240
|
+
}
|
|
241
|
+
})} ref={scrollViewRef} testID={testID+"_ScrollView"}>
|
|
214
242
|
<FlashList
|
|
215
243
|
containerProps = {{style:[cStyle]}}
|
|
216
244
|
//prepareItems = {Array.isArray(items)? false : undefined}
|
|
@@ -222,7 +250,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
222
250
|
}
|
|
223
251
|
if(!absoluteScrollViewRef.current) return;
|
|
224
252
|
absoluteScrollViewRef.current.setStyles({
|
|
225
|
-
content : {height}
|
|
253
|
+
content : {height,width}
|
|
226
254
|
});
|
|
227
255
|
}}
|
|
228
256
|
onLayout = {(args)=>{
|
|
@@ -248,6 +276,7 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
248
276
|
keyExtractor = {typeof getRowKey =='function'? getRowKey : React.getKey}
|
|
249
277
|
//stickyHeaderIndices={[0]}
|
|
250
278
|
onScroll = {getOnScrollCb([absoluteScrollViewRef],(args)=>{
|
|
279
|
+
if(!absoluteScrollViewRef.current) return;
|
|
251
280
|
const offset = args?.nativeEvent?.contentOffset.y;
|
|
252
281
|
const scrollViewRef = absoluteScrollViewRef.current?.scrollViewRef;
|
|
253
282
|
if(typeof offset =='number' && scrollViewRef.current && scrollViewRef.current.scrollTo){
|
|
@@ -286,18 +315,20 @@ const TableComponent = React.forwardRef(({containerProps,isRowSelected,headerScr
|
|
|
286
315
|
</View>;
|
|
287
316
|
}}
|
|
288
317
|
/>
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
listRef.current.scrollToOffset
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
318
|
+
<AbsoluteScrollView
|
|
319
|
+
ref={absoluteScrollViewRef}
|
|
320
|
+
listRef = {listRef}
|
|
321
|
+
scrollEventThrottle = {scrollEventThrottle}
|
|
322
|
+
onScroll = {(args)=>{
|
|
323
|
+
if(!absoluteScrollViewRefCanScroll.current) return;
|
|
324
|
+
const offset = args?.nativeEvent?.contentOffset.y;
|
|
325
|
+
if(typeof offset =='number' && listRef.current && listRef.current.scrollToOffset){
|
|
326
|
+
listRef.current.scrollToOffset({animated:true,offset});
|
|
327
|
+
}
|
|
328
|
+
}}
|
|
329
|
+
/>
|
|
330
|
+
</ScrollView>}
|
|
331
|
+
|
|
301
332
|
</View>
|
|
302
333
|
});
|
|
303
334
|
|
|
@@ -358,6 +389,15 @@ const styles = StyleSheet.create({
|
|
|
358
389
|
paddingHorizontal:5,
|
|
359
390
|
paddingVertical : 0,
|
|
360
391
|
},
|
|
392
|
+
filterCell : {
|
|
393
|
+
alignSelf : "flex-start",
|
|
394
|
+
textAlign : "left",
|
|
395
|
+
paddingHorizontal : 2,
|
|
396
|
+
paddingVertical : 0,
|
|
397
|
+
marginVertical : 0,
|
|
398
|
+
marginHorizontal : 0,
|
|
399
|
+
justifyContent : 'flex-start',
|
|
400
|
+
},
|
|
361
401
|
headerItem: {
|
|
362
402
|
minHeight: 30,
|
|
363
403
|
},
|
|
@@ -377,14 +417,22 @@ const styles = StyleSheet.create({
|
|
|
377
417
|
marginHorizontal : 0,
|
|
378
418
|
marginVertical : 0,
|
|
379
419
|
},
|
|
420
|
+
hasNotData : {
|
|
421
|
+
flexDirection : 'column',
|
|
422
|
+
width : '100%',
|
|
423
|
+
justifyContent : 'center',
|
|
424
|
+
alignItems : 'center'
|
|
425
|
+
}
|
|
380
426
|
})
|
|
381
427
|
TableComponent.popTypes = {
|
|
382
428
|
containerProps : PropTypes.object,
|
|
383
429
|
renderHeaderCell : PropTypes.func,
|
|
430
|
+
renderFilterCell : PropTypes.func,
|
|
384
431
|
renderRow : PropTypes.func,
|
|
385
432
|
renderCell : PropTypes.func,
|
|
386
433
|
renderFooterCell : PropTypes.func,///la fonction appelée pour le rendu des entêtes du footer
|
|
387
434
|
footerCellContainerProps : PropTypes.object,
|
|
435
|
+
filterCellContainerProps : PropTypes.object,
|
|
388
436
|
footerContainerProps : PropTypes.object,
|
|
389
437
|
showFilters : PropTypes.bool,
|
|
390
438
|
showFooters : PropTypes.bool,
|
|
@@ -244,12 +244,12 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
244
244
|
if(isFocused || error){
|
|
245
245
|
placeholderColor = labelColor;
|
|
246
246
|
}
|
|
247
|
+
let labelText = React.isValidElement(label,true)?React.getTextContent(label):"";
|
|
247
248
|
const defaultBackgroundColor = theme.surfaceBackgroundColor;
|
|
248
249
|
let backgroundColor = Colors.isValid(flattenStyle.backgroundColor)? flattenStyle.backgroundColor : defaultBackgroundColor;
|
|
249
|
-
if(backgroundColor ==='transparent' && dynamicBackgroundColor !== false){
|
|
250
|
+
if(labelText && (backgroundColor ==='transparent' && dynamicBackgroundColor !== false)){
|
|
250
251
|
backgroundColor = defaultBackgroundColor;
|
|
251
252
|
}
|
|
252
|
-
let labelText = React.isValidElement(label,true)?React.getTextContent(label):"";
|
|
253
253
|
placeholder = defaultStr(placeholder,labelText);
|
|
254
254
|
const parsedValue = canValueBeDecimal ? parseValueToDecimal(text):text;
|
|
255
255
|
const formattedValue = formatValue(text);
|