@etsoo/react 1.4.20 → 1.4.24

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.
@@ -1,63 +1,104 @@
1
1
  import { Box, Stack } from '@mui/material';
2
2
  import React from 'react';
3
+ import { Labels } from '../app/Labels';
3
4
  import { GridDataGet } from '../components/GridLoader';
4
5
  import useCombinedRefs from '../uses/useCombinedRefs';
5
6
  import { useDimensions } from '../uses/useDimensions';
6
7
  import { DataGridEx, DataGridExCalColumns } from './DataGridEx';
8
+ import { MUGlobal } from './MUGlobal';
9
+ import { PullToRefreshUI } from './PullToRefreshUI';
7
10
  import { ScrollerListEx } from './ScrollerListEx';
8
11
  import { SearchBar } from './SearchBar';
12
+ /**
13
+ * Responsible container
14
+ * @param props Props
15
+ * @returns Layout
16
+ */
9
17
  export function ResponsibleContainer(props) {
10
18
  // Destruct
11
- const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, fieldTemplate, height, listBoxSx, loadData, mRef, searchBoxSx, sizeReadyMiliseconds = 0, ...rest } = props;
19
+ const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, fieldTemplate, height, listBoxSx, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, searchBoxSx = { marginBottom: MUGlobal.half(paddings) }, sizeReadyMiliseconds = 0, ...rest } = props;
20
+ // Labels
21
+ const labels = Labels.CommonPage;
12
22
  // Refs
13
23
  const refs = React.useRef({});
24
+ const state = refs.current;
14
25
  const mRefs = useCombinedRefs(mRef, (ref) => {
15
26
  if (ref == null)
16
27
  return;
17
- refs.current.ref = ref;
28
+ state.ref = ref;
18
29
  });
30
+ // Update mounted state
31
+ React.useEffect(() => {
32
+ return () => {
33
+ state.mounted = false;
34
+ };
35
+ }, []);
19
36
  // Has fields
20
37
  const hasFields = fields != null && fields.length > 0;
21
- // Watch container
22
- const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
23
- const rect = dimensions[0][2];
38
+ // Load data
24
39
  const localLoadData = (props) => {
40
+ state.mounted = true;
25
41
  const data = GridDataGet(props, fieldTemplate);
26
42
  return loadData(data);
27
43
  };
28
- const list = React.useMemo(() => {
29
- // No rect
30
- if (rect == null)
44
+ // On submit callback
45
+ const onSubmit = (data, _reset) => {
46
+ if (data == null || state.ref == null)
31
47
  return;
32
- // If height is the same
48
+ state.ref.reset({ data });
49
+ };
50
+ // Watch container
51
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds, (_preRect, rect) => {
52
+ // Check
53
+ if (rect == null)
54
+ return true;
55
+ // Last rect
56
+ const lastRect = state.rect;
57
+ // 32 = scroll bar width
58
+ if (lastRect != null &&
59
+ state.mounted !== true &&
60
+ Math.abs(rect.width - lastRect.width) <= 32 &&
61
+ Math.abs(rect.height - lastRect.height) <= 32)
62
+ return true;
63
+ // Hold the new rect
64
+ state.rect = rect;
65
+ return false;
66
+ });
67
+ // Rect
68
+ const rect = dimensions[0][2];
69
+ // Create list
70
+ const [list, showDataGrid] = (() => {
71
+ // No layout
72
+ if (rect == null)
73
+ return [null, false];
74
+ // Width
75
+ const width = rect.width;
76
+ // Show DataGrid or List dependng on width
77
+ const showDataGrid = width >= dataGridMinWidth;
78
+ // Height
33
79
  let heightLocal;
34
80
  if (height != null) {
35
81
  heightLocal = height;
36
82
  }
37
83
  else {
38
84
  // Auto calculation
39
- heightLocal =
40
- window.innerHeight - Math.round(rect.top + rect.height + 1);
85
+ heightLocal = window.innerHeight - Math.round(rect.bottom + 1);
41
86
  const style = window.getComputedStyle(dimensions[0][1]);
42
- const boxPadding = parseFloat(style.paddingLeft);
43
- if (!isNaN(boxPadding))
44
- heightLocal -= 2 * boxPadding;
87
+ const boxMargin = parseFloat(style.marginBottom);
88
+ if (!isNaN(boxMargin))
89
+ heightLocal -= 3 * boxMargin; // 1 - Box, 2 - Page bottom
45
90
  if (adjustHeight != null) {
46
91
  heightLocal -= adjustHeight(heightLocal);
47
92
  }
48
93
  }
49
- console.log(rect, heightLocal, refs.current.height);
50
- // Same height
51
- if (heightLocal === refs.current.height)
52
- return;
53
- refs.current.height = heightLocal;
54
- // Show DataGrid or List dependng on width
55
- const showDataGrid = rect.width >= dataGridMinWidth;
56
94
  if (showDataGrid) {
57
95
  // Delete
58
96
  delete rest.itemRenderer;
59
- return (React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(true) },
60
- React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, columns: columns, ...rest })));
97
+ return [
98
+ React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(true) },
99
+ React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, columns: columns, ...rest })),
100
+ true
101
+ ];
61
102
  }
62
103
  // Delete
63
104
  delete rest.checkable;
@@ -68,18 +109,25 @@ export function ResponsibleContainer(props) {
68
109
  delete rest.hideFooter;
69
110
  delete rest.hoverColor;
70
111
  delete rest.selectable;
71
- return (React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(false) },
72
- React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, ...rest })));
73
- }, [rect, height]);
74
- // On submit callback
75
- const onSubmit = (data, _reset) => {
76
- if (data == null || rect == null || refs.current.ref == null)
77
- return;
78
- refs.current.ref.reset({ data });
79
- };
112
+ return [
113
+ React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(false) },
114
+ React.createElement(ScrollerListEx, { autoLoad: !hasFields, width: rect.width, height: heightLocal, loadData: localLoadData, mRef: mRefs, ...rest })),
115
+ false
116
+ ];
117
+ })();
118
+ // Pull container
119
+ const pullContainer = list
120
+ ? showDataGrid
121
+ ? '.DataGridEx-Body'
122
+ : '.ScrollerListEx-Body'
123
+ : undefined;
80
124
  // Layout
81
- return (React.createElement(Stack, { ref: hasFields ? undefined : dimensions[0][0] },
82
- hasFields && (React.createElement(Box, { ref: dimensions[0][0], sx: searchBoxSx },
83
- React.createElement(SearchBar, { fields: fields, onSubmit: onSubmit }))),
84
- list));
125
+ return (React.createElement(React.Fragment, null,
126
+ React.createElement(Stack, null,
127
+ React.createElement(Box, { ref: dimensions[0][0], sx: searchBoxSx }, hasFields && (React.createElement(SearchBar, { fields: fields, onSubmit: onSubmit }))),
128
+ list),
129
+ pullToRefresh && pullContainer && (React.createElement(PullToRefreshUI, { mainElement: pullContainer, triggerElement: pullContainer, instructionsPullToRefresh: labels.pullToRefresh, instructionsReleaseToRefresh: labels.releaseToRefresh, instructionsRefreshing: labels.refreshing, onRefresh: () => { var _a; return (_a = state.ref) === null || _a === void 0 ? void 0 : _a.reset(); }, shouldPullToRefresh: () => {
130
+ const container = document.querySelector(pullContainer);
131
+ return !(container === null || container === void 0 ? void 0 : container.scrollTop);
132
+ } }))));
85
133
  }
@@ -66,8 +66,7 @@ export function ScrollerListEx(props) {
66
66
  const [selectedDiv, selectedData] = (_a = selectedItem.current) !== null && _a !== void 0 ? _a : [];
67
67
  if (selectedData != null && selectedData[idField] === data[idField])
68
68
  return;
69
- if (selectedDiv != null)
70
- selectedDiv.classList.remove(selectedClassName);
69
+ selectedDiv === null || selectedDiv === void 0 ? void 0 : selectedDiv.classList.remove(selectedClassName);
71
70
  div.classList.add(selectedClassName);
72
71
  selectedItem.current = [div, data];
73
72
  if (onSelectChange)
@@ -201,12 +201,12 @@ export function SearchBar(props) {
201
201
  handleSubmitInstant(true);
202
202
  };
203
203
  // Submit
204
- const handleSubmit = () => {
204
+ const handleSubmit = (delay = 480) => {
205
205
  if (forms.submitSeed != null) {
206
206
  clearTimeout(forms.submitSeed);
207
207
  }
208
208
  // Delay the change
209
- forms.submitSeed = window.setTimeout(handleSubmitInstant, 480);
209
+ forms.submitSeed = window.setTimeout(handleSubmitInstant, delay);
210
210
  };
211
211
  // Submit at once
212
212
  const handleSubmitInstant = (reset = false) => {
@@ -222,7 +222,7 @@ export function SearchBar(props) {
222
222
  // First loading
223
223
  React.useEffect(() => {
224
224
  // Delayed way
225
- handleSubmit();
225
+ handleSubmit(100);
226
226
  return () => {
227
227
  // Clear the seeds
228
228
  if (forms.submitSeed != null)
package/lib/mu/TableEx.js CHANGED
@@ -34,35 +34,39 @@ export function TableEx(props) {
34
34
  else {
35
35
  rowsPerPageLocal = 10;
36
36
  }
37
+ // Rows
38
+ const [rows, updateRows] = React.useState([]);
39
+ const setRows = (rows) => {
40
+ state.loadedItems = rows.length;
41
+ updateRows(rows);
42
+ };
37
43
  // States
38
- const [state, stateUpdate] = React.useReducer((currentState, newState) => {
39
- return { ...currentState, ...newState };
40
- }, {
44
+ const stateRefs = React.useRef({
41
45
  autoLoad,
42
46
  currentPage: 0,
47
+ loadedItems: 0,
43
48
  hasNextPage: true,
44
49
  isNextPageLoading: false,
45
50
  orderBy: defaultOrderBy,
46
51
  orderByAsc: defaultOrderBy
47
52
  ? (_a = columns.find((column) => column.field === defaultOrderBy)) === null || _a === void 0 ? void 0 : _a.sortAsc
48
53
  : undefined,
49
- rows: [],
50
54
  batchSize: rowsPerPageLocal,
51
55
  selectedItems: []
52
56
  });
53
- const isMounted = React.useRef(true);
57
+ const state = stateRefs.current;
54
58
  // Reset the state and load again
55
59
  const reset = (add) => {
56
- const state = {
60
+ const resetState = {
57
61
  autoLoad: true,
58
62
  currentPage: 0,
63
+ loadedItems: 0,
59
64
  hasNextPage: true,
60
65
  isNextPageLoading: false,
61
66
  lastLoadedItems: undefined,
62
- rows: [],
63
67
  ...add
64
68
  };
65
- stateUpdate(state);
69
+ Object.assign(state, resetState);
66
70
  };
67
71
  React.useImperativeHandle(mRef, () => ({
68
72
  /**
@@ -84,7 +88,7 @@ export function TableEx(props) {
84
88
  // Update state
85
89
  state.isNextPageLoading = true;
86
90
  // Parameters
87
- const { currentPage, batchSize, orderBy, orderByAsc, data } = state;
91
+ const { currentPage, batchSize, orderBy, orderByAsc, data, isMounted } = state;
88
92
  const loadProps = {
89
93
  currentPage,
90
94
  batchSize,
@@ -93,16 +97,16 @@ export function TableEx(props) {
93
97
  data
94
98
  };
95
99
  loadData(loadProps).then((result) => {
96
- if (!isMounted.current || result == null) {
100
+ state.isMounted = true;
101
+ if (result == null || isMounted === false) {
97
102
  return;
98
103
  }
99
104
  const newItems = result.length;
100
- stateUpdate({
101
- rows: result,
102
- lastLoadedItems: newItems,
103
- hasNextPage: newItems >= batchSize,
104
- isNextPageLoading: false
105
- });
105
+ state.lastLoadedItems = newItems;
106
+ state.hasNextPage = newItems >= batchSize;
107
+ state.isNextPageLoading = false;
108
+ // Update rows
109
+ setRows(result);
106
110
  });
107
111
  };
108
112
  const handleChangePage = (_event, newPage) => {
@@ -111,11 +115,11 @@ export function TableEx(props) {
111
115
  loadDataLocal();
112
116
  };
113
117
  const handleChangeRowsPerPage = (event) => {
114
- const rowsPerPage = parseInt(event.target.value);
115
- reset({ rowsPerPage });
118
+ const batchSize = parseInt(event.target.value);
119
+ reset({ batchSize });
116
120
  };
117
121
  const handleSelect = (item, checked) => {
118
- const selectedItems = [...state.selectedItems];
122
+ const selectedItems = state.selectedItems;
119
123
  const index = selectedItems.findIndex((selectedItem) => selectedItem[idField] === item[idField]);
120
124
  if (checked) {
121
125
  if (index === -1)
@@ -128,11 +132,10 @@ export function TableEx(props) {
128
132
  if (onSelectChange != null) {
129
133
  onSelectChange(selectedItems);
130
134
  }
131
- stateUpdate({ selectedItems });
132
135
  };
133
136
  const handleSelectAll = (checked) => {
134
- const selectedItems = [...state.selectedItems];
135
- state.rows.forEach((row) => {
137
+ const selectedItems = state.selectedItems;
138
+ rows.forEach((row) => {
136
139
  const index = selectedItems.findIndex((selectedItem) => selectedItem[idField] === row[idField]);
137
140
  if (checked) {
138
141
  if (index === -1)
@@ -145,14 +148,13 @@ export function TableEx(props) {
145
148
  if (onSelectChange != null) {
146
149
  onSelectChange(selectedItems);
147
150
  }
148
- stateUpdate({ selectedItems });
149
151
  };
150
152
  // New sort
151
153
  const handleSort = (field, asc) => {
152
154
  reset({ orderBy: field, orderByAsc: asc });
153
155
  };
154
156
  // Destruct states
155
- const { autoLoad: stateAutoLoad, currentPage, hasNextPage, lastLoadedItems, orderBy, rows, batchSize, selectedItems } = state;
157
+ const { autoLoad: stateAutoLoad, currentPage, hasNextPage, lastLoadedItems, orderBy, batchSize, selectedItems } = state;
156
158
  // Current page selected items
157
159
  const pageSelectedItems = selectable
158
160
  ? rows.reduce((previousValue, currentItem) => {
@@ -170,7 +172,7 @@ export function TableEx(props) {
170
172
  loadDataLocal();
171
173
  React.useEffect(() => {
172
174
  return () => {
173
- isMounted.current = false;
175
+ state.isMounted = false;
174
176
  };
175
177
  }, []);
176
178
  // Layout
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  /// <reference types="react" />
3
2
  import { CommonPageProps } from './CommonPageProps';
4
3
  /**
@@ -8,7 +7,7 @@ export declare const CommonPagePullContainer = "#page-container";
8
7
  /**
9
8
  * Default scroll container
10
9
  */
11
- export declare const CommonPageScrollContainer: NodeJS.Global & typeof globalThis;
10
+ export declare const CommonPageScrollContainer: typeof globalThis;
12
11
  /**
13
12
  * Common page
14
13
  * @param props Props
@@ -1,13 +1,5 @@
1
1
  import { DomUtils } from '@etsoo/shared';
2
2
  import React from 'react';
3
- const createRef = (source, index) => {
4
- return [
5
- (instance) => {
6
- if (instance != null)
7
- source[index][1] = instance;
8
- }
9
- ];
10
- };
11
3
  /**
12
4
  * Calculate element(s) dimensions
13
5
  * @param elements Observed elments count
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.4.20",
3
+ "version": "1.4.24",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,11 +50,11 @@
50
50
  "@emotion/react": "^11.7.1",
51
51
  "@emotion/style": "^0.8.0",
52
52
  "@emotion/styled": "^11.6.0",
53
- "@etsoo/appscript": "^1.2.21",
53
+ "@etsoo/appscript": "^1.2.22",
54
54
  "@etsoo/notificationbase": "^1.1.0",
55
55
  "@etsoo/shared": "^1.1.3",
56
56
  "@mui/icons-material": "^5.2.5",
57
- "@mui/material": "^5.2.7",
57
+ "@mui/material": "^5.2.8",
58
58
  "@reach/router": "^1.3.4",
59
59
  "@types/pica": "^5.1.3",
60
60
  "@types/pulltorefreshjs": "^0.1.5",
@@ -76,15 +76,15 @@
76
76
  "react-window": "^1.8.6"
77
77
  },
78
78
  "devDependencies": {
79
- "@babel/cli": "^7.16.7",
79
+ "@babel/cli": "^7.16.8",
80
80
  "@babel/core": "^7.16.7",
81
- "@babel/plugin-transform-runtime": "^7.16.7",
82
- "@babel/preset-env": "^7.16.7",
83
- "@babel/runtime-corejs3": "^7.16.7",
81
+ "@babel/plugin-transform-runtime": "^7.16.8",
82
+ "@babel/preset-env": "^7.16.8",
83
+ "@babel/runtime-corejs3": "^7.16.8",
84
84
  "@types/jest": "^27.4.0",
85
85
  "@types/react-test-renderer": "^17.0.1",
86
- "@typescript-eslint/eslint-plugin": "^5.9.0",
87
- "@typescript-eslint/parser": "^5.9.0",
86
+ "@typescript-eslint/eslint-plugin": "^5.9.1",
87
+ "@typescript-eslint/parser": "^5.9.1",
88
88
  "eslint": "^8.6.0",
89
89
  "eslint-config-airbnb-base": "^15.0.0",
90
90
  "eslint-plugin-import": "^2.25.4",
@@ -126,6 +126,11 @@ export interface GridLoaderStates<T> extends GridLoadDataProps {
126
126
  */
127
127
  lastLoadedItems?: number;
128
128
 
129
+ /**
130
+ * All loaded items count
131
+ */
132
+ loadedItems: number;
133
+
129
134
  /**
130
135
  * Has next page?
131
136
  */
@@ -137,9 +142,9 @@ export interface GridLoaderStates<T> extends GridLoadDataProps {
137
142
  isNextPageLoading: boolean;
138
143
 
139
144
  /**
140
- * Current rows
145
+ * Is mounted
141
146
  */
142
- rows: T[];
147
+ isMounted?: boolean;
143
148
 
144
149
  /**
145
150
  * Selected items of id