@itcase/forms 1.1.46 → 1.1.48

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.
@@ -1019,10 +1019,10 @@ const defaultDropzoneProps = {
1019
1019
 
1020
1020
  const FileInputDropzone = /*#__PURE__*/React__default.default.memo(function FileInputDropzone(props) {
1021
1021
  const {
1022
- className,
1022
+ // className, unused
1023
1023
  maxFiles,
1024
1024
  maxSize,
1025
- size,
1025
+ // size, unused
1026
1026
  fileErrorText,
1027
1027
  dropzoneProps = {},
1028
1028
  hintDescription,
@@ -1043,7 +1043,28 @@ const FileInputDropzone = /*#__PURE__*/React__default.default.memo(function File
1043
1043
  } = reactFinalForm.useForm();
1044
1044
  const [fileError, setFileError] = React.useState('');
1045
1045
  const [fileIsLoading, setFileIsLoading] = React.useState(false);
1046
- const filesList = React.useMemo(() => inputValue ? castArray__default.default(inputValue) : [], [inputValue]);
1046
+ const prevFilesListRef = React.useRef(null);
1047
+ const filesList = React.useMemo(() => {
1048
+ const newFilesList = inputValue ? castArray__default.default(inputValue) : [];
1049
+ if (prevFilesListRef.current === null) {
1050
+ prevFilesListRef.current = newFilesList;
1051
+ return newFilesList;
1052
+ }
1053
+ // keep track of previous state and revoke unused object urls
1054
+ prevFilesListRef.current.forEach(prevFile => {
1055
+ if (!prevFile.preview) {
1056
+ return;
1057
+ }
1058
+ const isFileDeleted = !newFilesList.some(newFile => {
1059
+ return newFile.preview === prevFile.preview;
1060
+ });
1061
+ if (isFileDeleted) {
1062
+ URL.revokeObjectURL(prevFile.preview);
1063
+ }
1064
+ });
1065
+ prevFilesListRef.current = newFilesList;
1066
+ return newFilesList;
1067
+ }, [inputValue]);
1047
1068
  const changeFormState = React.useCallback(newFiles => {
1048
1069
  // If max files in dropzone is 1 - return file as it self, else as array of files
1049
1070
  // ps: for old projects compatibility
@@ -1109,7 +1130,7 @@ const FileInputDropzone = /*#__PURE__*/React__default.default.memo(function File
1109
1130
  if (isPreviews) {
1110
1131
  // Add preview to every file
1111
1132
  acceptedFiles.forEach(file => {
1112
- if (!file.error) {
1133
+ if (!file.error && !file.preview) {
1113
1134
  file.preview = URL.createObjectURL(file);
1114
1135
  }
1115
1136
  });
@@ -1156,17 +1177,18 @@ const FileInputDropzone = /*#__PURE__*/React__default.default.memo(function File
1156
1177
  // First time convert value to Files and save to local and form state
1157
1178
  convertFiledValueAndSaveAsFiles(currentFilesList);
1158
1179
  }
1159
-
1180
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1181
+ }, [inputValue]);
1182
+ React.useEffect(() => {
1160
1183
  // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
1161
1184
  return () => {
1162
- filesList.forEach(file => {
1163
- if (file?.preview) {
1185
+ prevFilesListRef.current.forEach(file => {
1186
+ if (file.preview) {
1164
1187
  URL.revokeObjectURL(file.preview);
1165
1188
  }
1166
1189
  });
1167
1190
  };
1168
- // eslint-disable-next-line react-hooks/exhaustive-deps
1169
- }, [inputValue]);
1191
+ }, []);
1170
1192
  const propsGenerator = useDevicePropsGenerator.useDevicePropsGenerator(props);
1171
1193
  const {
1172
1194
  fillClass,
@@ -1218,10 +1240,6 @@ const FileInputDropzone = /*#__PURE__*/React__default.default.memo(function File
1218
1240
  src: file.preview || file.image,
1219
1241
  onClick: event => {
1220
1242
  onClickPreview && onClickPreview(file, event);
1221
- },
1222
- onLoad: () => {
1223
- // Revoke data uri after image is loaded
1224
- URL.revokeObjectURL(file.preview);
1225
1243
  }
1226
1244
  })), file.error && /*#__PURE__*/React__default.default.createElement("div", null, /*#__PURE__*/React__default.default.createElement(Text.Text, {
1227
1245
  size: thumbNameTextSize,
@@ -2883,10 +2901,9 @@ const FinalForm = /*#__PURE__*/React__default.default.forwardRef(function FinalF
2883
2901
  }, desc), submitError && !modifiedSinceLastSubmit && /*#__PURE__*/React__default.default.createElement("div", {
2884
2902
  className: clsx__default.default('notification', 'form-notification', notificationType ? `form-notification_${notificationType}` : 'form-notification_global')
2885
2903
  }, /*#__PURE__*/React__default.default.createElement(Notification.Notification, {
2886
- appearance: "errorPrimary",
2887
- className: "form-notification__item",
2904
+ appearance: "errorPrimary sizeM solid rounded",
2905
+ type: "global",
2888
2906
  title: form.getState().submitError,
2889
- titleTextSize: "h6",
2890
2907
  status: "error",
2891
2908
  closeButton: notificationCloseButton
2892
2909
  })), onChangeFormValues && /*#__PURE__*/React__default.default.createElement(reactFinalForm.FormSpy, {
@@ -1,5 +1,5 @@
1
1
  import { isPossiblePhoneNumber } from 'libphonenumber-js';
2
- import React, { useMemo, useEffect, useCallback, useState } from 'react';
2
+ import React, { useMemo, useEffect, useCallback, useState, useRef } from 'react';
3
3
  import { setIn, FORM_ERROR, getIn } from 'final-form';
4
4
  import { useForm, Field, Form, FormSpy } from 'react-final-form';
5
5
  export { Field, useForm, useFormState } from 'react-final-form';
@@ -1008,10 +1008,10 @@ const defaultDropzoneProps = {
1008
1008
 
1009
1009
  const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(props) {
1010
1010
  const {
1011
- className,
1011
+ // className, unused
1012
1012
  maxFiles,
1013
1013
  maxSize,
1014
- size,
1014
+ // size, unused
1015
1015
  fileErrorText,
1016
1016
  dropzoneProps = {},
1017
1017
  hintDescription,
@@ -1032,7 +1032,28 @@ const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(pro
1032
1032
  } = useForm();
1033
1033
  const [fileError, setFileError] = useState('');
1034
1034
  const [fileIsLoading, setFileIsLoading] = useState(false);
1035
- const filesList = useMemo(() => inputValue ? castArray(inputValue) : [], [inputValue]);
1035
+ const prevFilesListRef = useRef(null);
1036
+ const filesList = useMemo(() => {
1037
+ const newFilesList = inputValue ? castArray(inputValue) : [];
1038
+ if (prevFilesListRef.current === null) {
1039
+ prevFilesListRef.current = newFilesList;
1040
+ return newFilesList;
1041
+ }
1042
+ // keep track of previous state and revoke unused object urls
1043
+ prevFilesListRef.current.forEach(prevFile => {
1044
+ if (!prevFile.preview) {
1045
+ return;
1046
+ }
1047
+ const isFileDeleted = !newFilesList.some(newFile => {
1048
+ return newFile.preview === prevFile.preview;
1049
+ });
1050
+ if (isFileDeleted) {
1051
+ URL.revokeObjectURL(prevFile.preview);
1052
+ }
1053
+ });
1054
+ prevFilesListRef.current = newFilesList;
1055
+ return newFilesList;
1056
+ }, [inputValue]);
1036
1057
  const changeFormState = useCallback(newFiles => {
1037
1058
  // If max files in dropzone is 1 - return file as it self, else as array of files
1038
1059
  // ps: for old projects compatibility
@@ -1098,7 +1119,7 @@ const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(pro
1098
1119
  if (isPreviews) {
1099
1120
  // Add preview to every file
1100
1121
  acceptedFiles.forEach(file => {
1101
- if (!file.error) {
1122
+ if (!file.error && !file.preview) {
1102
1123
  file.preview = URL.createObjectURL(file);
1103
1124
  }
1104
1125
  });
@@ -1145,17 +1166,18 @@ const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(pro
1145
1166
  // First time convert value to Files and save to local and form state
1146
1167
  convertFiledValueAndSaveAsFiles(currentFilesList);
1147
1168
  }
1148
-
1169
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1170
+ }, [inputValue]);
1171
+ useEffect(() => {
1149
1172
  // Make sure to revoke the data uris to avoid memory leaks, will run on unmount
1150
1173
  return () => {
1151
- filesList.forEach(file => {
1152
- if (file?.preview) {
1174
+ prevFilesListRef.current.forEach(file => {
1175
+ if (file.preview) {
1153
1176
  URL.revokeObjectURL(file.preview);
1154
1177
  }
1155
1178
  });
1156
1179
  };
1157
- // eslint-disable-next-line react-hooks/exhaustive-deps
1158
- }, [inputValue]);
1180
+ }, []);
1159
1181
  const propsGenerator = useDevicePropsGenerator(props);
1160
1182
  const {
1161
1183
  fillClass,
@@ -1207,10 +1229,6 @@ const FileInputDropzone = /*#__PURE__*/React.memo(function FileInputDropzone(pro
1207
1229
  src: file.preview || file.image,
1208
1230
  onClick: event => {
1209
1231
  onClickPreview && onClickPreview(file, event);
1210
- },
1211
- onLoad: () => {
1212
- // Revoke data uri after image is loaded
1213
- URL.revokeObjectURL(file.preview);
1214
1232
  }
1215
1233
  })), file.error && /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Text, {
1216
1234
  size: thumbNameTextSize,
@@ -2872,10 +2890,9 @@ const FinalForm = /*#__PURE__*/React.forwardRef(function FinalForm(props, ref) {
2872
2890
  }, desc), submitError && !modifiedSinceLastSubmit && /*#__PURE__*/React.createElement("div", {
2873
2891
  className: clsx('notification', 'form-notification', notificationType ? `form-notification_${notificationType}` : 'form-notification_global')
2874
2892
  }, /*#__PURE__*/React.createElement(Notification, {
2875
- appearance: "errorPrimary",
2876
- className: "form-notification__item",
2893
+ appearance: "errorPrimary sizeM solid rounded",
2894
+ type: "global",
2877
2895
  title: form.getState().submitError,
2878
- titleTextSize: "h6",
2879
2896
  status: "error",
2880
2897
  closeButton: notificationCloseButton
2881
2898
  })), onChangeFormValues && /*#__PURE__*/React.createElement(FormSpy, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itcase/forms",
3
- "version": "1.1.46",
3
+ "version": "1.1.48",
4
4
  "description": "Forms fields, inputs, etc.",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -38,7 +38,7 @@
38
38
  "@itcase/storybook-config": "^1.2.13",
39
39
  "@itcase/tokens-am": "^1.1.20",
40
40
  "@itcase/tokens-baikal": "^1.1.17",
41
- "@itcase/ui": "^1.8.145",
41
+ "@itcase/ui": "^1.8.147",
42
42
  "axios": "^1.12.2",
43
43
  "clsx": "^2.1.1",
44
44
  "final-form": "4.20.10",