@teselagen/ui 0.5.23-beta.31 → 0.5.23-beta.33

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.
@@ -24,7 +24,6 @@ import { handleCopyColumn } from "./handleCopyColumn";
24
24
  import { isBottomRightCornerOfRectangle } from "./isBottomRightCornerOfRectangle";
25
25
  import { handleCopyTable } from "./handleCopyTable";
26
26
  import { PRIMARY_SELECTED_VAL } from "./primarySelectedValue";
27
- import { useDeepEqualMemo } from "./useDeepEqualMemo";
28
27
  import { useTableEntities } from "./useTableEntities";
29
28
 
30
29
  export {
@@ -52,6 +51,5 @@ export {
52
51
  PRIMARY_SELECTED_VAL,
53
52
  removeCleanRows,
54
53
  stripNumberAtEnd,
55
- useDeepEqualMemo,
56
54
  useTableEntities
57
55
  };
@@ -352,7 +352,6 @@ export default function useTableParams(
352
352
  reduxFormSearchInput,
353
353
  onlyShowRowsWErrors,
354
354
  reduxFormCellValidation,
355
- reduxFormEntities,
356
355
  reduxFormSelectedCells,
357
356
  reduxFormSelectedEntityIdMap,
358
357
  reduxFormQueryParams,
@@ -11,7 +11,7 @@ import {
11
11
  } from "./queryParams";
12
12
  import { withRouter } from "react-router-dom";
13
13
  import getTableConfigFromStorage from "./getTableConfigFromStorage";
14
- import { useDeepEqualMemo } from "./useDeepEqualMemo";
14
+ import { useDeepEqualMemo } from "../../utils/hooks/useDeepEqualMemo";
15
15
  import { branch, compose } from "recompose";
16
16
 
17
17
  /**
@@ -1,4 +1,10 @@
1
- import React, { useEffect, useMemo, useRef, useState } from "react";
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useMemo,
5
+ useRef,
6
+ useState
7
+ } from "react";
2
8
  import {
3
9
  Button,
4
10
  Callout,
@@ -42,6 +48,7 @@ import convertSchema from "../DataTable/utils/convertSchema";
42
48
  import { LoadingDots } from "./LoadingDots";
43
49
  import { useDispatch } from "react-redux";
44
50
  import { flushSync } from "react-dom";
51
+ import { useStableReference } from "../utils/hooks/useStableReference";
45
52
 
46
53
  const manualEnterMessage = "Build CSV File";
47
54
  const manualEnterSubMessage = "Paste or type data to build a CSV file";
@@ -208,6 +215,10 @@ const InnerDropZone = ({
208
215
  </section>
209
216
  );
210
217
 
218
+ const onFileSuccessDefault = async () => {
219
+ return;
220
+ };
221
+
211
222
  const Uploader = ({
212
223
  accept: __accept,
213
224
  action,
@@ -216,7 +227,7 @@ const Uploader = ({
216
227
  callout: _callout,
217
228
  className = "",
218
229
  contentOverride: maybeContentOverride,
219
- disabled: _disabled,
230
+ disabled,
220
231
  dropzoneProps = {},
221
232
  fileLimit,
222
233
  fileList, //list of files with options: {name, loading, error, url, originalName, downloadName}
@@ -230,9 +241,7 @@ const Uploader = ({
230
241
  onChange: _onChange = noop, //this is almost always getting passed by redux-form, no need to pass this handler manually
231
242
  onFieldSubmit = noop, //called when all files have successfully uploaded
232
243
  onFileClick, // called when a file link in the filelist is clicked
233
- onFileSuccess = async () => {
234
- return;
235
- }, //called each time a file is finished and before the file.loading gets set to false, needs to return a promise!
244
+ onFileSuccess = onFileSuccessDefault, //called each time a file is finished and before the file.loading gets set to false, needs to return a promise!
236
245
  onPreviewClick,
237
246
  onRemove = noop, //called when a file has been selected to be removed
238
247
  overflowList,
@@ -247,88 +256,95 @@ const Uploader = ({
247
256
  const [resolvedAccept, setResolvedAccept] = useState();
248
257
  const [loading, setLoading] = useState(false);
249
258
  const filesToClean = useRef([]);
259
+
260
+ // We do this because we don't want functions influencing on the dependencies
261
+ const stableOnChange = useStableReference(_onChange);
262
+ const stableBeforeUpload = useStableReference(beforeUpload);
250
263
  // onChange received from redux-form is not working anymore,
251
264
  // so we need to overwrite it for redux to works.
252
- const onChange = val => {
253
- flushSync(() => {
254
- if (noRedux) {
255
- return _onChange(val);
256
- }
257
- dispatch(touch(formName, name));
258
- dispatch(change(formName, name, val));
259
- });
260
- };
265
+ const onChange = useCallback(
266
+ val => {
267
+ flushSync(() => {
268
+ if (noRedux) {
269
+ return stableOnChange.current(val);
270
+ }
271
+ dispatch(touch(formName, name));
272
+ dispatch(change(formName, name, val));
273
+ });
274
+ },
275
+ [dispatch, formName, name, noRedux, stableOnChange]
276
+ );
261
277
 
262
- const handleSecondHalfOfUpload = async ({
263
- acceptedFiles,
264
- cleanedFileList
265
- }) => {
266
- // This onChange is not changing things, we need to check whether the error is here or later
267
- onChange(cleanedFileList); //tnw: this line is necessary, if you want to clear the file list in the beforeUpload, call onChange([])
268
- // beforeUpload is called, otherwise beforeUpload will not be able to truly cancel the upload
269
- const keepGoing = beforeUpload
270
- ? await beforeUpload(cleanedFileList, onChange)
271
- : true;
272
- if (!keepGoing) return;
278
+ const handleSecondHalfOfUpload = useCallback(
279
+ async ({ acceptedFiles, cleanedFileList }) => {
280
+ // This onChange is not changing things, we need to check whether the error is here or later
281
+ onChange(cleanedFileList); //tnw: this line is necessary, if you want to clear the file list in the beforeUpload, call onChange([])
282
+ // beforeUpload is called, otherwise beforeUpload will not be able to truly cancel the upload
283
+ const keepGoing = stableBeforeUpload.current
284
+ ? await stableBeforeUpload.current(cleanedFileList, onChange)
285
+ : true;
286
+ if (!keepGoing) return;
273
287
 
274
- if (action) {
275
- const responses = [];
276
- await Promise.all(
277
- acceptedFiles.map(async fileToUpload => {
278
- const data = new FormData();
279
- data.append("file", fileToUpload);
280
- try {
281
- const res = await (window.serverApi
282
- ? window.serverApi.post(action, data)
283
- : fetch(action, {
284
- method: "POST",
285
- body: data
286
- }));
287
- responses.push(res.data && res.data[0]);
288
- onFileSuccess(res.data[0]).then(() => {
288
+ if (action) {
289
+ const responses = [];
290
+ await Promise.all(
291
+ acceptedFiles.map(async fileToUpload => {
292
+ const data = new FormData();
293
+ data.append("file", fileToUpload);
294
+ try {
295
+ const res = await (window.serverApi
296
+ ? window.serverApi.post(action, data)
297
+ : fetch(action, {
298
+ method: "POST",
299
+ body: data
300
+ }));
301
+ responses.push(res.data && res.data[0]);
302
+ onFileSuccess(res.data[0]).then(() => {
303
+ cleanedFileList = cleanedFileList.map(file => {
304
+ const fileToReturn = {
305
+ ...file,
306
+ ...res.data[0]
307
+ };
308
+ if (fileToReturn.id === fileToUpload.id) {
309
+ fileToReturn.loading = false;
310
+ }
311
+ return fileToReturn;
312
+ });
313
+ onChange(cleanedFileList);
314
+ });
315
+ } catch (err) {
316
+ console.error("Error uploading file:", err);
317
+ responses.push({
318
+ ...fileToUpload,
319
+ error: err && err.msg ? err.msg : err
320
+ });
289
321
  cleanedFileList = cleanedFileList.map(file => {
290
- const fileToReturn = {
291
- ...file,
292
- ...res.data[0]
293
- };
322
+ const fileToReturn = { ...file };
294
323
  if (fileToReturn.id === fileToUpload.id) {
295
324
  fileToReturn.loading = false;
325
+ fileToReturn.error = true;
296
326
  }
297
327
  return fileToReturn;
298
328
  });
299
329
  onChange(cleanedFileList);
300
- });
301
- } catch (err) {
302
- console.error("Error uploading file:", err);
303
- responses.push({
304
- ...fileToUpload,
305
- error: err && err.msg ? err.msg : err
306
- });
307
- cleanedFileList = cleanedFileList.map(file => {
308
- const fileToReturn = { ...file };
309
- if (fileToReturn.id === fileToUpload.id) {
310
- fileToReturn.loading = false;
311
- fileToReturn.error = true;
312
- }
313
- return fileToReturn;
314
- });
315
- onChange(cleanedFileList);
316
- }
317
- })
318
- );
319
- onFieldSubmit(responses);
320
- } else {
321
- onChange(
322
- cleanedFileList.map(function (file) {
323
- return {
324
- ...file,
325
- loading: false
326
- };
327
- })
328
- );
329
- }
330
- setLoading(false);
331
- };
330
+ }
331
+ })
332
+ );
333
+ onFieldSubmit(responses);
334
+ } else {
335
+ onChange(
336
+ cleanedFileList.map(function (file) {
337
+ return {
338
+ ...file,
339
+ loading: false
340
+ };
341
+ })
342
+ );
343
+ }
344
+ setLoading(false);
345
+ },
346
+ [action, stableBeforeUpload, onChange, onFieldSubmit, onFileSuccess]
347
+ );
332
348
 
333
349
  const isAcceptPromise = useMemo(
334
350
  () =>
@@ -337,12 +353,15 @@ const Uploader = ({
337
353
  [__accept]
338
354
  );
339
355
 
340
- let dropzoneDisabled = _disabled;
341
- let _accept = __accept;
342
-
343
- if (resolvedAccept) {
344
- _accept = resolvedAccept;
345
- }
356
+ const _accept = useMemo(() => {
357
+ if (resolvedAccept) {
358
+ return resolvedAccept;
359
+ }
360
+ if (isAcceptPromise && !resolvedAccept) {
361
+ return [];
362
+ }
363
+ return __accept;
364
+ }, [__accept, isAcceptPromise, resolvedAccept]);
346
365
 
347
366
  useEffect(() => {
348
367
  if (isAcceptPromise) {
@@ -357,11 +376,9 @@ const Uploader = ({
357
376
  }
358
377
  }, [__accept, isAcceptPromise]);
359
378
 
360
- if (isAcceptPromise && !resolvedAccept) {
361
- _accept = [];
362
- }
363
-
379
+ let dropzoneDisabled = disabled;
364
380
  if (acceptLoading) dropzoneDisabled = true;
381
+
365
382
  const accept = useMemo(
366
383
  () =>
367
384
  !_accept
@@ -46,6 +46,7 @@ import Uploader from "./Uploader";
46
46
  import sortify from "./sortify";
47
47
  import { fieldRequired } from "./utils";
48
48
  import { useDispatch } from "react-redux";
49
+ import { useStableReference } from "../utils/hooks/useStableReference";
49
50
 
50
51
  export { fieldRequired };
51
52
 
@@ -147,8 +148,8 @@ const AbstractInput = ({
147
148
  noFillField,
148
149
  noMarginBottom,
149
150
  noOuterLabel,
150
- onDefaultValChanged,
151
- onFieldSubmit,
151
+ onDefaultValChanged: _onDefaultValChanged,
152
+ onFieldSubmit: _onFieldSubmit,
152
153
  rightEl,
153
154
  secondaryLabel,
154
155
  setAssignDefaultsMode,
@@ -160,13 +161,16 @@ const AbstractInput = ({
160
161
  tooltipProps
161
162
  }) => {
162
163
  const dispatch = useDispatch();
164
+ const onDefaultValChanged = useStableReference(_onDefaultValChanged);
165
+ const onFieldSubmit = useStableReference(_onFieldSubmit);
163
166
 
164
167
  // This only takes care that the default Value is changed when it is changed in the parent component
165
168
  useEffect(() => {
166
169
  if (defaultValue !== undefined) {
167
170
  dispatch(change(form, name, defaultValue));
168
- onDefaultValChanged && onDefaultValChanged(defaultValue, name, form);
169
- onFieldSubmit && onFieldSubmit(defaultValue);
171
+ onDefaultValChanged.current &&
172
+ onDefaultValChanged.current(defaultValue, name, form);
173
+ onFieldSubmit.current && onFieldSubmit.current(defaultValue);
170
174
  }
171
175
  }, [defaultValue, dispatch, form, name, onDefaultValChanged, onFieldSubmit]);
172
176
 
@@ -126,7 +126,7 @@ class TgSelect extends React.Component {
126
126
  e.preventDefault();
127
127
  let newValue = null;
128
128
  if (multi) {
129
- newValue = filter(value, obj => obj.disabled) || [];
129
+ newValue = filter(value, obj => obj?.disabled) || [];
130
130
  } else if (value && value.disabled) {
131
131
  newValue = value;
132
132
  }
@@ -11,7 +11,8 @@ import { some } from "lodash-es";
11
11
  import { times } from "lodash-es";
12
12
  import DialogFooter from "./DialogFooter";
13
13
  import DataTable from "./DataTable";
14
- import { removeCleanRows, useDeepEqualMemo } from "./DataTable/utils";
14
+ import { useDeepEqualMemo } from "./utils/hooks";
15
+ import { removeCleanRows } from "./DataTable/utils";
15
16
  import wrapDialog from "./wrapDialog";
16
17
  import { omit } from "lodash-es";
17
18
  import { useDispatch, useSelector } from "react-redux";
package/src/index.js CHANGED
@@ -22,7 +22,8 @@ export {
22
22
  } from "./DataTable";
23
23
  export { removeCleanRows, useTableEntities } from "./DataTable/utils";
24
24
 
25
- export { getIdOrCodeOrIndex, useDeepEqualMemo } from "./DataTable/utils";
25
+ export { useDeepEqualMemo } from "./utils/hooks";
26
+ export { getIdOrCodeOrIndex } from "./DataTable/utils";
26
27
  export { default as convertSchema } from "./DataTable/utils/convertSchema";
27
28
  export { default as Loading } from "./Loading";
28
29
  export { throwFormError } from "./throwFormError";
@@ -0,0 +1 @@
1
+ export { useDeepEqualMemo } from "./useDeepEqualMemo";
@@ -0,0 +1,10 @@
1
+ import { isEqual } from "lodash-es";
2
+ import { useRef } from "react";
3
+
4
+ export const useDeepEqualMemo = value => {
5
+ const ref = useRef();
6
+ if (!isEqual(value, ref.current)) {
7
+ ref.current = value;
8
+ }
9
+ return ref.current;
10
+ };
@@ -0,0 +1,9 @@
1
+ import { useEffect, useRef } from "react";
2
+
3
+ export const useStableReference = value => {
4
+ const ref = useRef();
5
+ useEffect(() => {
6
+ ref.current = value;
7
+ }, [value]);
8
+ return ref;
9
+ };
@@ -0,0 +1 @@
1
+ export { useDeepEqualMemo } from './useDeepEqualMemo';
@@ -0,0 +1 @@
1
+ export function useDeepEqualMemo(value: any): undefined;
@@ -0,0 +1 @@
1
+ export function useStableReference(value: any): import('../../../../../node_modules/react').MutableRefObject<undefined>;
@@ -1 +0,0 @@
1
- export function withAbstractWrapper(ComponentToWrap: any, opts?: {}): (props: any) => import("react/jsx-runtime").JSX.Element;