@fto-consult/expo-ui 6.26.3 → 6.26.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "6.26.3",
3
+ "version": "6.26.4",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -68,7 +68,7 @@
68
68
  "@expo/html-elements": "^0.5.1",
69
69
  "@expo/vector-icons": "^13.0.0",
70
70
  "@faker-js/faker": "^8.0.2",
71
- "@fto-consult/common": "^3.28.4",
71
+ "@fto-consult/common": "^3.29.1",
72
72
  "@gorhom/portal": "^1.0.14",
73
73
  "@pchmn/expo-material3-theme": "^1.3.1",
74
74
  "@react-native-async-storage/async-storage": "1.18.2",
@@ -2,7 +2,7 @@ import {Content} from "$ecomponents/BottomSheet";
2
2
  import Icon from "$ecomponents/Icon";
3
3
  import React from "$react";
4
4
  import {defaultStr,defaultBool,defaultObj} from "$cutils";
5
- import Filter, {canHandleFilter,getFilterStateValues} from "$ecomponents/Filter";
5
+ import Filter, {canHandleFilter} from "$ecomponents/Filter";
6
6
  import PropTypes from "prop-types";
7
7
  import { StyleSheet,View } from "react-native";
8
8
  import Menu from "$ecomponents/Menu";
@@ -18,16 +18,14 @@ const MIN_WIDTH = 250;
18
18
  let windowWidth = Dimensions.get("window").width;
19
19
 
20
20
  const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
21
- const {filters,isLoading,filteredColumns,children,label,filterTitle:customFilterTitle,visible:customVisible,orOperator,andOperator,onToggleFilters,context:customContext,...restProps} = props;
21
+ const {filters,isLoading,filteredColumns,children,label,testID:cTestID,filterTitle:customFilterTitle,visible:customVisible,orOperator,andOperator,onToggleFilters,context:customContext,...restProps} = props;
22
22
  const context = defaultObj(customContext);
23
- const [state,setState] = React.useState({
24
- visible : defaultBool(customVisible,false),
25
- visibleColumns : defaultObj(filteredColumns),
26
- });
23
+ const testID = defaultStr(testID,"RN_AccordionFilters");
24
+ const [visibleColumns,setVisibleColumns] = React.useState(filteredColumns);
25
+ const [visible,setVisible] = React.useState(defaultBool(customVisible,false));
27
26
  const valuesRefs = React.useRef({});
28
27
  windowWidth = Dimensions.get("window").width;
29
28
  const innerRef = React.useRef(null);
30
- const {visible,visibleColumns} = state;
31
29
  const rest = defaultObj(restProps);
32
30
  const filterTitle = defaultStr(customFilterTitle,'Filtres');
33
31
  const canHandlerFilterRef = React.useRef(0);
@@ -50,8 +48,8 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
50
48
  if(React.isValidElement(filter)){
51
49
  content.push(<Grid.Cell {...cellProps} key={index}>{filter}</Grid.Cell>)
52
50
  } else if(isObj(filter)){
53
- const {onChange} = filter;
54
- const key = defaultStr(filter.key,filter.field,filter.index,index+"");
51
+ const {onChange,visible:cVisible,...rest} = filter;
52
+ const key = defaultStr(filter.key,filter.field,filter.columnField,filter.index,index+"");
55
53
  const visible = !!visibleColumns[key];
56
54
  colMenus.push(<Menu.Item
57
55
  key = {key}
@@ -61,7 +59,7 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
61
59
  if(context.toggleFilterColumnVisibility){
62
60
  context.toggleFilterColumnVisibility(key,!visible);
63
61
  }
64
- setState({...state,visibleColumns:{...visibleColumns,[key]:!visible}})
62
+ setVisibleColumns({...visibleColumns,[key]:!visible});
65
63
  }}
66
64
  />)
67
65
  if(!visible) {
@@ -72,32 +70,32 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
72
70
  if(renderMenusOnly) return null;
73
71
  content.push(
74
72
  <Grid.Cell {...cellProps} key={key}>
75
- <Filter
76
- {...filter}
77
- {...(isObj(valuesRefs.current[key]) ? valuesRefs.current[key] : {})}
78
- dynamicRendered
79
- //isLoading = {isLoading && filteredRef.current[key] ? true : false}
80
- orOperator = {defaultBool(orOperator,filter.orOperator,true)}
81
- andOperator = {defaultBool(andOperator,filter.andOperator,true)}
82
- onChange = {(arg)=>{
83
- if(!arg.action && !arg.operator || !arg.field) return;
84
- const canHandle = canHandleFilter(arg);
85
- valuesRefs.current[key] = arg;
86
- if(filteredRef.current[key] !== canHandle){
87
- if(canHandle){
88
- canHandlerFilterRef.current++;
89
- } else {
90
- canHandlerFilterRef.current = Math.max(0,canHandlerFilterRef.current-1);
73
+ <Filter
74
+ {...rest}
75
+ {...(isObj(valuesRefs.current[key]) ? valuesRefs.current[key] : {})}
76
+ dynamicRendered
77
+ //isLoading = {isLoading && filteredRef.current[key] ? true : false}
78
+ orOperator = {defaultBool(orOperator,filter.orOperator,true)}
79
+ andOperator = {defaultBool(andOperator,filter.andOperator,true)}
80
+ onChange = {(arg)=>{
81
+ if(!arg.action && !arg.operator || !arg.field) return;
82
+ const canHandle = canHandleFilter(arg);
83
+ valuesRefs.current[key] = arg;
84
+ if(filteredRef.current[key] !== canHandle){
85
+ if(canHandle){
86
+ canHandlerFilterRef.current++;
87
+ } else {
88
+ canHandlerFilterRef.current = Math.max(0,canHandlerFilterRef.current-1);
89
+ }
91
90
  }
92
- }
93
- filteredRef.current[key] = canHandle;
94
- if(onChange){
95
- onChange(arg);
96
- }
97
- }}
98
- withBottomSheet
99
- containerProps = {{...containerProps}}
100
- inputProps = {{containerProps}}
91
+ filteredRef.current[key] = canHandle;
92
+ if(onChange){
93
+ onChange(arg);
94
+ }
95
+ }}
96
+ withBottomSheet
97
+ containerProps = {{...containerProps}}
98
+ inputProps = {{containerProps}}
101
99
  /></Grid.Cell>)
102
100
  }
103
101
  })
@@ -115,7 +113,7 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
115
113
  title = {null}
116
114
  visible = {visible}
117
115
  onDissmiss = {()=>{
118
- setState({...state,visible:false})
116
+ setVisible(false);
119
117
  }}
120
118
  anchor = {(props)=><Tooltip title = {mainFilterTitle}Component={Pressable} {...props} style={[theme.styles.row]}>
121
119
  <Icon
@@ -132,8 +130,8 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
132
130
  >
133
131
  {({open,close})=>{
134
132
  const {content,colMenus} = prepareContent(filters);
135
- return <View style={[styles.wrapper]}>
136
- <View style = {[styles.menuWrapper]}>
133
+ return <View style={[styles.wrapper]} testID={testID+"_AccordionFiltersWrapper"}>
134
+ <View style = {[styles.menuWrapper]} testID={testID+"_AccordionFilterWraperContent"}>
137
135
  <Expandable
138
136
  left = {(props)=><Icon {...props} icon={content.length?'filter-plus':'filter-menu'}/>}
139
137
  style = {styles.expandable}
@@ -2560,7 +2560,6 @@ export default class CommonDatagridComponent extends AppComponent {
2560
2560
  sortedProps,
2561
2561
  width,
2562
2562
  columnField : field,
2563
- //columnDef : header,
2564
2563
  index : headerIndex,
2565
2564
  visible,
2566
2565
  key : header.field,
@@ -3617,9 +3616,13 @@ export default class CommonDatagridComponent extends AppComponent {
3617
3616
  return false;
3618
3617
  }
3619
3618
  UNSAFE_componentWillReceiveProps(nextProps){
3620
- if(React.areEquals(nextProps.data,this.props.data) || (stableHash(nextProps.data) === stableHash(this.props.data))) {
3619
+ if(nextProps.data === this.props.data || React.areEquals(nextProps.data,this.props.data)) {
3621
3620
  return false;
3622
3621
  }
3622
+ const newStableHash = stableHash(nextProps.data);
3623
+ this.prevStableDataHash = this.prevStableDataHash !== undefined ? this.prevStableDataHash : stableHash(this.props.data);
3624
+ if(newStableHash == this.prevStableDataHash) return false;
3625
+ this.prevStableDataHash = newStableHash;
3623
3626
  this.setIsLoading(true,true);
3624
3627
  this.prepareData({...nextProps,force:true},(state)=>{
3625
3628
  this.setState(state)
@@ -151,7 +151,6 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
151
151
  title
152
152
  },rest.exportTableProps.pdf);
153
153
  const fetchOptionsRef = React.useRef(defaultObj(customFetchOptions));
154
- const refreshCBRef = React.useRef(null);
155
154
  const fPathRef = React.useRef(defaultStr(fetchPathKey,uniqid("fetchPath")));
156
155
  fetchPath = defaultStr(fetchPath,table.queryPath,tableName.toLowerCase()).trim();
157
156
  if(fetchPath){
@@ -160,23 +159,16 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
160
159
  const sortRef = React.useRef({});
161
160
  const innerRef = React.useRef(null);
162
161
  const showProgressRef = React.useRef(true);
163
- const dataRef = React.useRef([]);
164
- const hasResultRef = React.useRef(false);
165
- const totalRef = React.useRef(0);
166
- const isFetchingRef = React.useRef(false);
167
162
  const pageRef = React.useRef(1);
168
163
  const canHandlePagination = handlePagination !== false ? true : false;
169
164
  const canHandleLimit = handleQueryLimit !== false && canHandlePagination ? true : false;
170
165
  const limitRef = React.useRef(!canHandleLimit ?0 : defaultNumber(getSessionData("limit"),500));
171
166
  const isInitializedRef = React.useRef(false);
172
167
  testID = defaultStr(testID,"RNSWRDatagridComponent");
173
- const isLoadingRef = React.useRef(true);
174
- const {error, isValidating,isLoading:customIsLoading,refresh} = useSWR(fetchPath,{
168
+ const {error, isValidating,isLoading,data:result,refresh} = useSWR(fetchPath,{
175
169
  fetcher : (url,opts)=>{
176
170
  if(!isInitializedRef.current) {
177
- isFetchingRef.current = false;
178
- isLoadingRef.current = false;
179
- return;
171
+ return Promise.resolve({data:[],total:0});
180
172
  }
181
173
  opts = defaultObj(opts);
182
174
  opts.fetchOptions = isObj(opts.fetchOptions)? Object.clone(opts.fetchOptions) : {};
@@ -195,35 +187,14 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
195
187
  delete opts.page;
196
188
  delete opts.offset;
197
189
  }
198
- const fetchCB = (fArgs)=>{
199
- let {data,total} = (Array.isArray(fArgs) ? {data:fArgs,total:fArgs.length} : isObj(fArgs)? fArgs : {data:[],total:0});
200
- totalRef.current = total;
201
- dataRef.current = data;
202
- const dd = Object.size(data);
203
- if(dd>total){
204
- total = dd;
205
- }
206
- hasResultRef.current = true;
207
- if(onFetchData && typeof onFetchData =='function'){
208
- onFetchData({allData:data,total,data,context:innerRef.current})
209
- }
210
- return data;
211
- };
212
- hasResultRef.current = false;
213
- isFetchingRef.current = true;
214
190
  if(typeof fetcher =='function'){
215
- return fetcher(url,opts).then(fetchCB).finally(()=>{
216
- isFetchingRef.current = false;
217
- isLoadingRef.current = false;
218
- });
191
+ return fetcher(url,opts);
219
192
  }
220
193
  const {url:fUrl,fetcher:cFetcher,...rest} = getFetcherOptions(url,opts);
221
194
  if(showProgressRef.current ===false){
222
195
  rest.showError = false;
223
196
  }
224
- return cFetcher(fUrl,rest).then(fetchCB).finally(()=>{
225
- isFetchingRef.current = false;
226
- }).catch((e)=>{
197
+ return cFetcher(fUrl,rest).catch((e)=>{
227
198
  console.log(e," is swr fetching data");
228
199
  throw e;
229
200
  });
@@ -231,39 +202,38 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
231
202
  showError : false,
232
203
  swrOptions : getSWROptions(swrConfig.refreshTimeout)
233
204
  });
234
- const isLoading = isLoadingRef.current && customIsLoading || false;
235
- /*React.useEffect(()=>{
236
- innerRef.current && innerRef.current.setIsLoading && innerRef.current.setIsLoading(isLoading);
237
- },[isLoading])*/
238
- React.useEffect(()=>{
239
- const cb = refreshCBRef.current;
240
- refreshCBRef.current = null;
241
- if(!isValidating && !customIsLoading && typeof cb =='function'){
242
- cb();
205
+ const {data,total} = React.useMemo(()=>{
206
+ const {data,total} = (Array.isArray(result) ? {data:result,total:result.length} : isObj(result)? result : {data:[],total:0});
207
+ const dd = Object.size(data);
208
+ if(dd>total){
209
+ total = dd;
210
+ }
211
+ if(onFetchData && typeof onFetchData =='function'){
212
+ onFetchData({allData:data,total,data,context:innerRef.current})
243
213
  }
244
- },[isValidating,customIsLoading])
214
+ return {data,total};
215
+ },[result])
216
+ const loading = (isLoading || isValidating);
245
217
  React.useEffect(()=>{
246
218
  setTimeout(x=>{
247
219
  if(error && innerRef.current && innerRef.current.isLoading && innerRef.current.isLoading()){
248
220
  innerRef.current.setIsLoading(false,false);
249
221
  }
250
- },500)
251
- },[error])
222
+ },500);
223
+ },[error]);
252
224
  const doRefresh = (showProgress)=>{
253
225
  showProgressRef.current = showProgress ? typeof showProgress ==='boolean' : false;
254
- if(isFetchingRef.current) return;
255
- isLoadingRef.current = true;
256
226
  refresh();
257
227
  }
258
228
  const canPaginate = ()=>{
259
229
  if(!canHandlePagination) return false;
260
- if(canHandleLimit && typeof totalRef.current !=='number' || typeof pageRef.current !='number' || typeof limitRef.current !='number') return false;
230
+ if(canHandleLimit && typeof total !=='number' || typeof pageRef.current !='number' || typeof limitRef.current !='number') return false;
261
231
  if(limitRef.current <= 0) return false;
262
232
  return true;
263
233
  }
264
234
  const getTotalPages = ()=>{
265
235
  if(!canPaginate()) return false;
266
- return Math.ceil(totalRef.current / limitRef.current);;
236
+ return Math.ceil(total / limitRef.current);;
267
237
  };
268
238
  const getNextPage = ()=>{
269
239
  if(!canPaginate()) return false;
@@ -289,9 +259,8 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
289
259
  }, canSortRemotely = ()=>{
290
260
  if(!canPaginate() || autoSort === true) return false;
291
261
  ///si le nombre total d'élements est inférieur au nombre limite alors le trie peut être fait localement
292
- return totalRef.current > limitRef.current && true || false;
262
+ return total > limitRef.current && true || false;
293
263
  }
294
- const loading = (isLoadingRef.current && (isLoading|| isValidating));
295
264
  const pointerEvents = loading ?"node" : "auto";
296
265
  const itLimits = [{
297
266
  text : "Limite nbre elts par page",
@@ -378,7 +347,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
378
347
  />
379
348
  <View testID={testID+"_PaginationLabel"}>
380
349
  <Label style={{fontSize:15}}>
381
- {(totalRef.current?page:0).formatNumber()}-{totalPages.formatNumber()}{" / "}{totalRef.current.formatNumber()}
350
+ {(total?page:0).formatNumber()}-{totalPages.formatNumber()}{" / "}{total.formatNumber()}
382
351
  </Label>
383
352
  </View>
384
353
  <Icon
@@ -433,7 +402,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
433
402
  isSWRDatagrid
434
403
  isTableData
435
404
  fetchData = {undefined}
436
- data = {dataRef.current}
405
+ data = {data}
437
406
  canMakePhoneCall={canMakePhoneCall}
438
407
  key={tableName}
439
408
  sessionName={defaultStr(sessionName,'list-data')}
@@ -425,6 +425,7 @@ export default class Filter extends AppComponent {
425
425
  dynamicRendered,
426
426
  tooltipLabel,
427
427
  andOperator,
428
+ orOperator,
428
429
  searchIcon,
429
430
  field,
430
431
  style,
@@ -245,6 +245,7 @@ export default class Field extends AppComponent {
245
245
  return false;
246
246
  }
247
247
  callOnChange(args){
248
+ args.isFilter = this.isFilter();
248
249
  if(typeof this.props.onChange === "function" && this.hasValueChanged(args.value)){
249
250
  this.props.onChange(args);
250
251
  }
@@ -278,7 +279,7 @@ export default class Field extends AppComponent {
278
279
  actions[k][action]();
279
280
  }
280
281
  let form = Forms.getForm(this.formName);
281
- this.INITIAL_STATE.onValidate.call(this,{...defaultObj(rest),props:this.props,formName:this.formName,form,name:this.name,field:this.name,value,event,context:this});
282
+ this.INITIAL_STATE.onValidate.call(this,{...defaultObj(rest),isFilter:this.isFilter(),props:this.props,formName:this.formName,form,name:this.name,field:this.name,value,event,context:this});
282
283
  this.callOnChange({value,event,isValid:true,...rest});
283
284
  if(form && form.props){
284
285
  if(canEnable){
@@ -351,7 +352,7 @@ export default class Field extends AppComponent {
351
352
  for(var k in actions){
352
353
  actions[k].disable();
353
354
  }
354
- this.INITIAL_STATE.onNoValidate.call(this,{...defaultObj(rest),props:this.props,msg,value,formName:this.formName,field:this.name,name:this.name,context:this,event,validRule,validType:validRule,validParams,context:this});
355
+ this.INITIAL_STATE.onNoValidate.call(this,{...defaultObj(rest),isFilter:this.isFilter(),props:this.props,msg,value,formName:this.formName,field:this.name,name:this.name,context:this,event,validRule,validType:validRule,validParams,context:this});
355
356
  let form = Forms.getForm(this.formName);
356
357
  this.callOnChange({value,validRule,validParams,event,isValid:false,...rest});
357
358
  if(form){
@@ -29,6 +29,9 @@ export default class FormIDField extends TextField {
29
29
 
30
30
  /*** met à jour la données du numéro de piece */
31
31
  fetchNewId(focus){
32
+ if(this.isFilter()){
33
+ return Promise.resolve("");
34
+ }
32
35
  const data = defaultObj(this.props.data);
33
36
  if(!isNonNullString(this.name)) return undefined;
34
37
  const cb = (value)=>{
@@ -66,41 +69,48 @@ export default class FormIDField extends TextField {
66
69
  return false;
67
70
  }
68
71
  componentDidUpdate(){
69
- if(!isNonNullString(this.newFieldIdValue)){
72
+ if(!this.isFilter() && !isNonNullString(this.newFieldIdValue)){
70
73
  this.fetchNewId();
71
74
  }
72
75
  }
73
76
  _render(props,setRef){
74
77
  delete props.validType;
75
- const upper = props.upper !== false ? UPPER_CASE : "";
76
- if(isNonNullString(this.name) && isObj(props.data) && isNonNullString(props.data[this.name])){
77
- props.disabled = true;
78
- props.validType = upper;
79
- props.defaultValue = props.data[this.name];
80
- } else {
81
- props.validType = 'required|'+upper;
82
- }
83
- if(typeof props.minLength !=='number'){
84
- props.minLength = 2;
85
- }
86
- const defValue = props.defaultValue = isNonNullString(props.defaultValue)? props.defaultValue : isNonNullString(this.newFieldIdValue)? this.newFieldIdValue : undefined;
87
- props.validRule = props.validType;
88
- props.contentContainerProps = Object.assign({},props.contentContainerProps)
89
- props.contentContainerProps.pointerEvents = defaultStr(props.contentContainerProps.pointerEvents,"auto");
90
- props.enableCopy = typeof props.enableCopy ==='boolean'? props.enableCopy : (props.defaultValue || this.newFieldIdValue ? true : false);
91
- const {right} = props;
92
- props.readOnly = typeof props.disabled ==='boolean' ? !!!props.disabled : typeof props.readOnly =="boolean"? !!!props.disabled : false;
93
- props.right = (props)=>{
94
- const r = typeof right =='function'? right (props) : React.isValidElement(right)? right : null;
95
- if(!defValue){
96
- return <>{r}<ActivityIndicator
97
- {...props}
98
- style = {[props.style,{marginRight:10}]}
99
- /></>
78
+ if(!this.isFilter()){
79
+ const upper = props.upper !== false ? UPPER_CASE : "";
80
+ if(isNonNullString(this.name) && isObj(props.data) && isNonNullString(props.data[this.name])){
81
+ props.disabled = true;
82
+ props.validType = upper;
83
+ props.defaultValue = props.data[this.name];
84
+ } else {
85
+ props.validType = 'required|'+upper;
100
86
  }
101
- return r;
87
+ if(typeof props.minLength !=='number'){
88
+ props.minLength = 2;
89
+ }
90
+ const defValue = props.defaultValue = isNonNullString(props.defaultValue)? props.defaultValue : isNonNullString(this.newFieldIdValue)? this.newFieldIdValue : undefined;
91
+ props.validRule = props.validType;
92
+ props.contentContainerProps = Object.assign({},props.contentContainerProps)
93
+ props.contentContainerProps.pointerEvents = defaultStr(props.contentContainerProps.pointerEvents,"auto");
94
+ props.enableCopy = typeof props.enableCopy ==='boolean'? props.enableCopy : (props.defaultValue || this.newFieldIdValue ? true : false);
95
+ props.readOnly = typeof props.disabled ==='boolean' ? !!!props.disabled : typeof props.readOnly =="boolean"? !!!props.disabled : false;
96
+
97
+ const {right} = props;
98
+ props.right = (props)=>{
99
+ const r = typeof right =='function'? right (props) : React.isValidElement(right)? right : null;
100
+ if(!defValue){
101
+ return <>{r}<ActivityIndicator
102
+ {...props}
103
+ style = {[props.style,{marginRight:10}]}
104
+ /></>
105
+ }
106
+ return r;
107
+ }
108
+
109
+ this.setValidRule(props.validType);
110
+ } else {
111
+ props.enableCopy = false;
112
+ props.disabled = props.readOnly = false;
102
113
  }
103
- this.setValidRule(props.validType);
104
114
  return super._render(props,setRef);
105
115
  }
106
116
  }
@@ -70,13 +70,19 @@ export const getFilterComponentProps = (_props)=>{
70
70
  errorText,
71
71
  label,text,
72
72
  primary,
73
- onValidate,
74
73
  checkPiece,
75
74
  check,
76
75
  width,
77
76
  type,
77
+ visible,
78
78
  jsType,
79
79
  filterType,
80
+ getValidValue,
81
+ validate,
82
+ onValidate,
83
+ onValidatorValid,///il s'agit de la fonction de rappel appelée immédiatement après que le validateur ait réuissie la validation
84
+ onValidateField,
85
+ onNoValidate,
80
86
  ...props
81
87
  } = _props;
82
88
  props = defaultObj(props);
@@ -86,13 +92,13 @@ export const getFilterComponentProps = (_props)=>{
86
92
  const sanitizedType = type.replaceAll("_","").toLowerCase().trim();
87
93
  props = defaultObj(props);
88
94
  props.label = defaultStr(label,text);
89
- if(type.startsWith("select")){
95
+ if(sanitizedType.startsWith("select")){
90
96
  props.inputProps = Object.assign({},props.inputProps);
91
97
  props.inputProps.placeholder = defaultStr(props.inputProps.placeholder,i18n.lang("search.."))
92
98
  component = componentTypes.SelectField;
93
- if(type =='select_country' || type =='selectcountry'){
99
+ if(sanitizedType ==='selectcountry'){
94
100
  component = componentTypes.SelectCountry;
95
- } else if(type =='select_tabledata' || type =='selecttabledata'){
101
+ } else if(sanitizedType ==='selecttabledata'){
96
102
  component = componentTypes.SelectTableData;
97
103
  } else if(React.isComponent(componentTypes[type])){
98
104
  component = componentTypes[type];
@@ -133,6 +139,7 @@ export const getFilterComponentProps = (_props)=>{
133
139
  props.multiple = true;
134
140
  }
135
141
  props.renderFilter = true;
142
+ props.isFilter = true;
136
143
  if(type.contains("date") || type.contains("time")){
137
144
  delete props.right;
138
145
  }
@@ -125,9 +125,9 @@ const TableComponent = React.forwardRef(({containerProps,listContainerStyle,onRe
125
125
  }
126
126
  }
127
127
  }
128
- const onComponentRender = (a,b,c)=>{
128
+ const onComponentRender = (...args)=>{
129
129
  if(onRender){
130
- onRender(a,b,c);
130
+ onRender(...args);
131
131
  }
132
132
  //au paravant il était possible de faire scroller le composant Table lorsque les données sont raffraichies, ce qui n'avait pas un bon impact sur le rendu de la table de données
133
133
  if(false && itemsChanged){
@@ -424,6 +424,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
424
424
  {valueToCopy?<Icon
425
425
  {...iconProps}
426
426
  title = {"Copier la valeur ["+valueToCopy+"] dans le presse papier"}
427
+ style = {[iconProps.style,{pointerEvents:"auto"}]}
427
428
  icon = {COPY_ICON}
428
429
  onPress = {(e)=>{
429
430
  /*if(selectFieldToCopy){
@@ -5,7 +5,6 @@ import useStableMemo from "$react/useStableMemo";
5
5
  import { useWindowDimensions } from "$cdimensions";
6
6
  import {isObj,isNonNullString} from "$cutils";
7
7
  import { StyleSheet } from "react-native";
8
-
9
8
  import { createContext,useContext as useReactContext } from "react";
10
9
 
11
10
  export const ExpoUIContext = createContext(null);
@@ -63,4 +62,4 @@ export function useMediaQueryUpdateStyle({useCurrentMedia,target,mediaQueryUpdat
63
62
  if(isObj(nStyle) || Array.isArray(nStyle)) return StyleSheet.flatten([props.style,nStyle]);
64
63
  return StyleSheet.flatten(props.style)||{};
65
64
  },[handleProps,useCurrentMedia,dimensions,props.style]);
66
- }
65
+ }
@@ -0,0 +1,92 @@
1
+ import {isNonNullString,isObj,extendObj,defaultObj,defaultStr} from "$utils";
2
+ import { useQuery as useRQuery, useMutation as RQUseMutation, useQueryClient } from "@tanstack/react-query";
3
+ import { getFetcherOptions as apiGetFetcherOptions } from '$capi';
4
+
5
+ export const RETRY_OPTIONS = { cacheTime: 2000,refetchInterval:5000};
6
+
7
+ export const RETRY_LIST_OPTIONS = {cacheTime:5000,refetchInterval:20000};
8
+
9
+ const isValidNetworkMode = (nMode)=>isNonNullString(nMode) && ['online','always','offlineFirst'].includes(nMode.toLowerCase().trim());
10
+ const isValidRetryDelay = (retryDelay) => typeof retryDelay =='number' || typeof retryDelay ==='function'? true : false;
11
+
12
+ const queries403Cached = {};
13
+
14
+ /***** override of useQuery
15
+ @see : https://tanstack.com/query/v4/docs/react/guides/migrating-to-react-query-4
16
+ @see : https://tanstack.com/query/v4/docs/react/reference/useQuery for useQuery options
17
+ @param {boolean} handle403, pour la prise en compte du 403
18
+ @param {Array} key, array of key string, The query key to use for this query.The query key will be hashed into a stable hash. See Query Keys for more information. The query will automatically update when this key changes (as long as enabled is not set to false).
19
+ @param {function} queryFn, query function (context: QueryFunctionContext) => Promise<TData>
20
+ @param {boolean} enabled Set this to false to disable this query from automatically running.
21
+ @param {string} networkMode 'online' | 'always' | 'offlineFirst
22
+ @param {boolean| number | (failureCount: number, error: TError) => boolean} retry If false, failed queries will not retry by default.If true, failed queries will retry infinitely. If set to a number, e.g. 3, failed queries will retry until the failed query count meets that number.
23
+ @param {boolean} retryOnMount If set to false, the query will not be retried on mount if it contains an error. Defaults to true.
24
+ @param {number | (retryAttempt: number, error: TError) => number} retryDelay This function receives a retryAttempt integer and the actual Error and returns the delay to apply before he next attempt in milliseconds. A function like attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000) applies exponential backoff., A function like attempt => attempt * 1000 applies linear backoff.
25
+ */
26
+ export const useQuery = (key,queryFn,enabled,networkMode,retry,retryOnMount,retryDelay,...args)=>{
27
+ const options = isObj(key)? Object.assign({},key) : isNonNullString(key)? {queryKey:key.split(",")} : Array.isArray(key)? {queryKey:key} : {};
28
+ key = isNonNullString(key)? key.split(",") : Array.isArray(key)? key : [];
29
+ options.queryKey = Array.isArray(options.queryKey) && options.queryKey.length && options.queryKey || key;
30
+ options.queryFn = typeof queryFn =='function' ? queryFn : typeof options.queryFn =='function'? options.queryFn : undefined;
31
+ options.enabled = typeof enabled === "boolean" ? enabled : typeof options.enabled =='boolean' ? options.enabled : true;
32
+ options.networkMode = isValidNetworkMode(networkMode) ? networkMode.toLowerCase().trim() : isValidNetworkMode(options.networkMode) ? options.networkMode.toLowerCase().trim() : "online";
33
+ options.retry = typeof retry =='boolean' || typeof retry ==='number' ? retry : typeof options.retry ==='boolean' || typeof options.retry =='number' ? options.retry : undefined;
34
+ options.retryOnMount = typeof retryOnMount ==='boolean'? retryOnMount : typeof options.retryOnMount =='boolean' ? options.retryOnMount : undefined;
35
+ options.retryDelay = isValidRetryDelay(retryDelay)? retryDelay : isValidRetryDelay(options.retryDelay) ? options.retryDelay : undefined;
36
+ [queryFn,enabled,networkMode,retry,retryOnMount,retryDelay].map((a)=>{
37
+ isObj(a) && extendObj(true,options,a);
38
+ });
39
+ args.map((a)=>{
40
+ isObj(a) && extendObj(true,options,a);
41
+ });
42
+ options.enabled = !options.queryKey?.length ? false : options.enabled;
43
+ //if not enabled, we have to disabled retry option
44
+ options.retry = !options.enabled ? false : options.retry;
45
+ const {onError} = options;
46
+ const keyString = key.join(",");
47
+ if(keyString && queries403Cached[keyString]){
48
+ options.retry = false;
49
+ }
50
+ const {handle403} = options;
51
+ delete options.handle403;
52
+ options.onError = (e,...args)=>{
53
+ if(handle403){
54
+ const {response} = isObj(e)? e : {};
55
+ if(isObj(response) && response.status === 403){
56
+ keyString ? queries403Cached[keyString] = true : null;
57
+ setTimeout(()=>{
58
+ keyString && delete queries403Cached[keyString];
59
+ },100);
60
+ }
61
+ }
62
+ if(typeof onError ==='function' && (onError(e,options) === false)) return;
63
+ }
64
+ //const r = !options.enabled ? console.error("unable to get query for options",options) : null;
65
+ return useRQuery(options);
66
+ }
67
+
68
+ /****
69
+ @see : https://tanstack.com/query/v4/docs/react/reference/useMutation
70
+ */
71
+ export const useMutation = (mutationFn,cacheTime,mutationKey,...args)=>{
72
+ const options = isObj(mutationFn)? Object.assign({},mutationFn) : typeof(mutationFn) =='function'? {mutationFn} : {};
73
+ mutationFn = typeof mutationFn ==='function' ? mutationFn : undefined;
74
+ mutationFn = mutationFn || typeof options.mutationFn == 'function' ? options.mutationFn : undefined;
75
+ options.cacheTime = typeof cacheTime =='number' ? cacheTime : typeof options.cacheTime =='number'? options.cacheTime : undefined;
76
+ options.mutationKey = isNonNullString(mutationKey) && mutationKey || isNonNullString(options.mutationKey) ? options.mutationKey : undefined;
77
+ [cacheTime,mutationKey].map((a)=>{
78
+ isObj(a) && extendObj(true,options,a);
79
+ });
80
+ args.map((a)=>{
81
+ isObj(a) && extendObj(true,options,a);
82
+ });
83
+ options.mutationFn = async (params,...rest) => {
84
+ return await mutationFn(params,...rest);
85
+ }
86
+ return RQUseMutation(options);
87
+ }
88
+
89
+
90
+ export const getFetcherOptions = (path,opts)=>{
91
+ return apiGetFetcherOptions(path,opts);
92
+ }
@@ -1 +1 @@
1
- module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.26.2","repository":{"type":"git","url":"git+https://github.com/borispipo/expo-ui.git"},"homepage":"https://github.com/borispipo/expo-ui#readme"},"@emotion/native":{"version":"11.11.0","url":"https://emotion.sh","license":"MIT"},"@emotion/react":{"version":"11.11.1","url":"https://github.com/emotion-js/emotion/tree/main/packages/react","license":"MIT"},"@expo/html-elements":{"version":"0.5.1","url":"https://github.com/expo/expo/tree/main/packages/html-elements","license":"MIT"},"@expo/metro-config":{"version":"0.10.7","url":"https://github.com/expo/expo.git","license":"MIT"},"@expo/vector-icons":{"version":"13.0.0","url":"https://expo.github.io/vector-icons","license":"MIT"},"@expo/webpack-config":{"version":"18.1.2","url":"https://github.com/expo/expo-cli.git","license":"MIT"},"@faker-js/faker":{"version":"8.0.2","url":"https://github.com/faker-js/faker.git","license":"MIT"},"@fto-consult/common":{"version":"3.28.4","url":"https://github.com/borispipo/common#readme","license":"ISC"},"@gorhom/portal":{"version":"1.0.14","url":"https://github.com/gorhom/react-native-portal#readme","license":"MIT"},"@pchmn/expo-material3-theme":{"version":"1.3.1","url":"https://github.com/pchmn/expo-material3-theme#readme","license":"MIT"},"@react-native-async-storage/async-storage":{"version":"1.18.2","url":"https://github.com/react-native-async-storage/async-storage#readme","license":"MIT"},"@react-native-community/datetimepicker":{"version":"7.2.0","url":"https://github.com/react-native-community/datetimepicker#readme","license":"MIT"},"@react-native-community/netinfo":{"version":"9.3.10","url":"https://github.com/react-native-netinfo/react-native-netinfo#readme","license":"MIT"},"@react-native/assets-registry":{"version":"0.72.0","url":"git@github.com:facebook/react-native.git","license":"MIT"},"@react-navigation/native":{"version":"6.1.7","url":"https://reactnavigation.org","license":"MIT"},"@react-navigation/native-stack":{"version":"6.9.13","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"@shopify/flash-list":{"version":"1.4.3","url":"https://shopify.github.io/flash-list/","license":"MIT"},"apexcharts":{"version":"3.41.1","url":"https://apexcharts.com","license":"MIT"},"babel-plugin-inline-dotenv":{"version":"1.7.0","url":"https://github.com/brysgo/babel-plugin-inline-dotenv#readme","license":"ISC"},"babel-plugin-module-resolver":{"version":"5.0.0","url":"https://github.com/tleunen/babel-plugin-module-resolver.git","license":"MIT"},"expo":{"version":"49.0.7","url":"https://github.com/expo/expo/tree/main/packages/expo","license":"MIT"},"expo-camera":{"version":"13.4.2","url":"https://docs.expo.dev/versions/latest/sdk/camera/","license":"MIT"},"expo-clipboard":{"version":"4.3.1","url":"https://docs.expo.dev/versions/latest/sdk/clipboard","license":"MIT"},"expo-font":{"version":"11.4.0","url":"https://docs.expo.dev/versions/latest/sdk/font/","license":"MIT"},"expo-image-picker":{"version":"14.3.2","url":"https://docs.expo.dev/versions/latest/sdk/imagepicker/","license":"MIT"},"expo-linking":{"version":"5.0.2","url":"https://docs.expo.dev/versions/latest/sdk/linking","license":"MIT"},"expo-sqlite":{"version":"11.3.2","url":"https://docs.expo.dev/versions/latest/sdk/sqlite/","license":"MIT"},"expo-status-bar":{"version":"1.6.0","url":"https://docs.expo.dev/versions/latest/sdk/status-bar/","license":"MIT"},"expo-system-ui":{"version":"2.4.0","url":"https://docs.expo.dev/versions/latest/sdk/system-ui","license":"MIT"},"expo-web-browser":{"version":"12.3.2","url":"https://docs.expo.dev/versions/latest/sdk/webbrowser/","license":"MIT"},"file-saver":{"version":"2.0.5","url":"https://github.com/eligrey/FileSaver.js#readme","license":"MIT"},"fs-extra":{"version":"11.1.1","url":"https://github.com/jprichardson/node-fs-extra","license":"MIT"},"google-libphonenumber":{"version":"3.2.33","url":"https://ruimarinho.github.io/google-libphonenumber/","license":"(MIT AND Apache-2.0)"},"htmlparser2-without-node-native":{"version":"3.9.2","url":"git://github.com/fb55/htmlparser2.git","license":"MIT"},"pdfmake":{"version":"0.2.7","url":"http://pdfmake.org","license":"MIT"},"process":{"version":"0.11.10","url":"git://github.com/shtylman/node-process.git","license":"MIT"},"prop-types":{"version":"15.8.1","url":"https://facebook.github.io/react/","license":"MIT"},"react":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-content-loader":{"version":"6.2.1","url":"https://github.com/danilowoz/react-content-loader","license":"MIT"},"react-dom":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-native":{"version":"0.72.3","license":"MIT"},"react-native-big-list":{"version":"1.6.1","url":"https://marcocesarato.github.io/react-native-big-list-docs/","license":"GPL-3.0-or-later"},"react-native-blob-util":{"version":"0.18.6","url":"https://github.com/RonRadtke/react-native-blob-util","license":"MIT"},"react-native-gesture-handler":{"version":"2.12.1","url":"https://github.com/software-mansion/react-native-gesture-handler#readme","license":"MIT"},"react-native-iphone-x-helper":{"version":"1.3.1","url":"https://github.com/ptelad/react-native-iphone-x-helper#readme","license":"MIT"},"react-native-mime-types":{"version":"2.4.0","license":"MIT"},"react-native-paper":{"version":"5.10.1","url":"https://callstack.github.io/react-native-paper","license":"MIT"},"react-native-paper-dates":{"version":"0.18.14","url":"https://github.com/web-ridge/react-native-paper-dates#readme","license":"MIT"},"react-native-reanimated":{"version":"3.3.0","url":"https://github.com/software-mansion/react-native-reanimated#readme","license":"MIT"},"react-native-safe-area-context":{"version":"4.6.3","url":"https://github.com/th3rdwave/react-native-safe-area-context#readme","license":"MIT"},"react-native-screens":{"version":"3.22.1","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"react-native-svg":{"version":"13.9.0","url":"https://github.com/react-native-community/react-native-svg","license":"MIT"},"react-native-web":{"version":"0.19.7","url":"git://github.com/necolas/react-native-web.git","license":"MIT"},"react-native-webview":{"version":"13.2.2","url":"https://github.com/react-native-webview/react-native-webview#readme","license":"MIT"},"react-virtuoso":{"version":"4.5.0","url":"https://virtuoso.dev/","license":"MIT"},"sharp-cli":{"version":"4.1.1","url":"https://github.com/vseventer/sharp-cli","license":"MIT"},"tippy.js":{"version":"6.3.7","url":"https://atomiks.github.io/tippyjs/","license":"MIT"},"uninstall":{"version":"0.0.0","license":"MIT"},"websql":{"version":"2.0.3","url":"git://github.com/nolanlawson/node-websql.git","license":"Apache-2.0"},"xlsx":{"version":"0.18.5","url":"https://sheetjs.com/","license":"Apache-2.0"}};
1
+ module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.26.3","repository":{"type":"git","url":"git+https://github.com/borispipo/expo-ui.git"},"homepage":"https://github.com/borispipo/expo-ui#readme"},"@emotion/native":{"version":"11.11.0","url":"https://emotion.sh","license":"MIT"},"@emotion/react":{"version":"11.11.1","url":"https://github.com/emotion-js/emotion/tree/main/packages/react","license":"MIT"},"@expo/html-elements":{"version":"0.5.1","url":"https://github.com/expo/expo/tree/main/packages/html-elements","license":"MIT"},"@expo/metro-config":{"version":"0.10.7","url":"https://github.com/expo/expo.git","license":"MIT"},"@expo/vector-icons":{"version":"13.0.0","url":"https://expo.github.io/vector-icons","license":"MIT"},"@expo/webpack-config":{"version":"18.1.2","url":"https://github.com/expo/expo-cli.git","license":"MIT"},"@faker-js/faker":{"version":"8.0.2","url":"https://github.com/faker-js/faker.git","license":"MIT"},"@fto-consult/common":{"version":"3.29.0","url":"https://github.com/borispipo/common#readme","license":"ISC"},"@gorhom/portal":{"version":"1.0.14","url":"https://github.com/gorhom/react-native-portal#readme","license":"MIT"},"@pchmn/expo-material3-theme":{"version":"1.3.1","url":"https://github.com/pchmn/expo-material3-theme#readme","license":"MIT"},"@react-native-async-storage/async-storage":{"version":"1.18.2","url":"https://github.com/react-native-async-storage/async-storage#readme","license":"MIT"},"@react-native-community/datetimepicker":{"version":"7.2.0","url":"https://github.com/react-native-community/datetimepicker#readme","license":"MIT"},"@react-native-community/netinfo":{"version":"9.3.10","url":"https://github.com/react-native-netinfo/react-native-netinfo#readme","license":"MIT"},"@react-native/assets-registry":{"version":"0.72.0","url":"git@github.com:facebook/react-native.git","license":"MIT"},"@react-navigation/native":{"version":"6.1.7","url":"https://reactnavigation.org","license":"MIT"},"@react-navigation/native-stack":{"version":"6.9.13","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"@shopify/flash-list":{"version":"1.4.3","url":"https://shopify.github.io/flash-list/","license":"MIT"},"apexcharts":{"version":"3.41.1","url":"https://apexcharts.com","license":"MIT"},"babel-plugin-inline-dotenv":{"version":"1.7.0","url":"https://github.com/brysgo/babel-plugin-inline-dotenv#readme","license":"ISC"},"babel-plugin-module-resolver":{"version":"5.0.0","url":"https://github.com/tleunen/babel-plugin-module-resolver.git","license":"MIT"},"expo":{"version":"49.0.7","url":"https://github.com/expo/expo/tree/main/packages/expo","license":"MIT"},"expo-camera":{"version":"13.4.2","url":"https://docs.expo.dev/versions/latest/sdk/camera/","license":"MIT"},"expo-clipboard":{"version":"4.3.1","url":"https://docs.expo.dev/versions/latest/sdk/clipboard","license":"MIT"},"expo-font":{"version":"11.4.0","url":"https://docs.expo.dev/versions/latest/sdk/font/","license":"MIT"},"expo-image-picker":{"version":"14.3.2","url":"https://docs.expo.dev/versions/latest/sdk/imagepicker/","license":"MIT"},"expo-linking":{"version":"5.0.2","url":"https://docs.expo.dev/versions/latest/sdk/linking","license":"MIT"},"expo-sqlite":{"version":"11.3.2","url":"https://docs.expo.dev/versions/latest/sdk/sqlite/","license":"MIT"},"expo-status-bar":{"version":"1.6.0","url":"https://docs.expo.dev/versions/latest/sdk/status-bar/","license":"MIT"},"expo-system-ui":{"version":"2.4.0","url":"https://docs.expo.dev/versions/latest/sdk/system-ui","license":"MIT"},"expo-web-browser":{"version":"12.3.2","url":"https://docs.expo.dev/versions/latest/sdk/webbrowser/","license":"MIT"},"file-saver":{"version":"2.0.5","url":"https://github.com/eligrey/FileSaver.js#readme","license":"MIT"},"fs-extra":{"version":"11.1.1","url":"https://github.com/jprichardson/node-fs-extra","license":"MIT"},"google-libphonenumber":{"version":"3.2.33","url":"https://ruimarinho.github.io/google-libphonenumber/","license":"(MIT AND Apache-2.0)"},"htmlparser2-without-node-native":{"version":"3.9.2","url":"git://github.com/fb55/htmlparser2.git","license":"MIT"},"pdfmake":{"version":"0.2.7","url":"http://pdfmake.org","license":"MIT"},"process":{"version":"0.11.10","url":"git://github.com/shtylman/node-process.git","license":"MIT"},"prop-types":{"version":"15.8.1","url":"https://facebook.github.io/react/","license":"MIT"},"react":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-content-loader":{"version":"6.2.1","url":"https://github.com/danilowoz/react-content-loader","license":"MIT"},"react-dom":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-native":{"version":"0.72.3","license":"MIT"},"react-native-big-list":{"version":"1.6.1","url":"https://marcocesarato.github.io/react-native-big-list-docs/","license":"GPL-3.0-or-later"},"react-native-blob-util":{"version":"0.18.6","url":"https://github.com/RonRadtke/react-native-blob-util","license":"MIT"},"react-native-gesture-handler":{"version":"2.12.1","url":"https://github.com/software-mansion/react-native-gesture-handler#readme","license":"MIT"},"react-native-iphone-x-helper":{"version":"1.3.1","url":"https://github.com/ptelad/react-native-iphone-x-helper#readme","license":"MIT"},"react-native-mime-types":{"version":"2.4.0","license":"MIT"},"react-native-paper":{"version":"5.10.1","url":"https://callstack.github.io/react-native-paper","license":"MIT"},"react-native-paper-dates":{"version":"0.18.14","url":"https://github.com/web-ridge/react-native-paper-dates#readme","license":"MIT"},"react-native-reanimated":{"version":"3.3.0","url":"https://github.com/software-mansion/react-native-reanimated#readme","license":"MIT"},"react-native-safe-area-context":{"version":"4.6.3","url":"https://github.com/th3rdwave/react-native-safe-area-context#readme","license":"MIT"},"react-native-screens":{"version":"3.22.1","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"react-native-svg":{"version":"13.9.0","url":"https://github.com/react-native-community/react-native-svg","license":"MIT"},"react-native-web":{"version":"0.19.7","url":"git://github.com/necolas/react-native-web.git","license":"MIT"},"react-native-webview":{"version":"13.2.2","url":"https://github.com/react-native-webview/react-native-webview#readme","license":"MIT"},"react-virtuoso":{"version":"4.5.0","url":"https://virtuoso.dev/","license":"MIT"},"sharp-cli":{"version":"4.1.1","url":"https://github.com/vseventer/sharp-cli","license":"MIT"},"tippy.js":{"version":"6.3.7","url":"https://atomiks.github.io/tippyjs/","license":"MIT"},"uninstall":{"version":"0.0.0","license":"MIT"},"websql":{"version":"2.0.3","url":"git://github.com/nolanlawson/node-websql.git","license":"Apache-2.0"},"xlsx":{"version":"0.18.5","url":"https://sheetjs.com/","license":"Apache-2.0"}};