@fctc/widget-logic 3.10.5 → 3.10.6
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/dist/index.js +77 -52
- package/dist/index.mjs +77 -52
- package/dist/types.d.mts +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/widget.d.mts +10 -7
- package/dist/widget.d.ts +10 -7
- package/dist/widget.js +77 -52
- package/dist/widget.mjs +77 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6194,12 +6194,33 @@ var colorFieldController = (props) => {
|
|
|
6194
6194
|
// src/widget/basic/binary-field/controller.ts
|
|
6195
6195
|
var import_react22 = require("react");
|
|
6196
6196
|
var import_utils16 = require("@fctc/interface-logic/utils");
|
|
6197
|
+
var ALLOWED_TYPES = [
|
|
6198
|
+
"image/jpeg",
|
|
6199
|
+
"image/png",
|
|
6200
|
+
"application/pdf",
|
|
6201
|
+
"video/mp4",
|
|
6202
|
+
"application/zip",
|
|
6203
|
+
"application/x-zip-compressed",
|
|
6204
|
+
"application/vnd.ms-excel",
|
|
6205
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
6206
|
+
"application/json"
|
|
6207
|
+
];
|
|
6208
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
6209
|
+
var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
|
|
6197
6210
|
var binaryFieldController = (props) => {
|
|
6198
|
-
const {
|
|
6211
|
+
const {
|
|
6212
|
+
name,
|
|
6213
|
+
methods,
|
|
6214
|
+
readonly = false,
|
|
6215
|
+
value,
|
|
6216
|
+
filename,
|
|
6217
|
+
rootField,
|
|
6218
|
+
index
|
|
6219
|
+
} = props;
|
|
6199
6220
|
const inputId = (0, import_react22.useId)();
|
|
6200
|
-
const [
|
|
6201
|
-
const [
|
|
6202
|
-
const [
|
|
6221
|
+
const [selectedFile, setSelectedFile] = (0, import_react22.useState)(null);
|
|
6222
|
+
const [selectedPreview, setSelectedPreview] = (0, import_react22.useState)(null);
|
|
6223
|
+
const [initialFile, setInitialFile] = (0, import_react22.useState)(value || null);
|
|
6203
6224
|
const { setValue } = methods;
|
|
6204
6225
|
const binaryRef = (0, import_react22.useRef)(null);
|
|
6205
6226
|
const convertUrlToBase64 = async (url) => {
|
|
@@ -6208,9 +6229,7 @@ var binaryFieldController = (props) => {
|
|
|
6208
6229
|
const blob = await response.blob();
|
|
6209
6230
|
return new Promise((resolve, reject) => {
|
|
6210
6231
|
const reader = new FileReader();
|
|
6211
|
-
reader.onloadend = () =>
|
|
6212
|
-
resolve(reader.result);
|
|
6213
|
-
};
|
|
6232
|
+
reader.onloadend = () => resolve(reader.result);
|
|
6214
6233
|
reader.onerror = reject;
|
|
6215
6234
|
reader.readAsDataURL(blob);
|
|
6216
6235
|
});
|
|
@@ -6219,40 +6238,13 @@ var binaryFieldController = (props) => {
|
|
|
6219
6238
|
throw error;
|
|
6220
6239
|
}
|
|
6221
6240
|
};
|
|
6222
|
-
const extractBase64Data = (base64Url) =>
|
|
6223
|
-
|
|
6224
|
-
return base64Url.split("base64,")[1];
|
|
6225
|
-
}
|
|
6226
|
-
return base64Url;
|
|
6227
|
-
};
|
|
6228
|
-
const handleImageChange = async (e, onChange) => {
|
|
6229
|
-
if (readonly) return;
|
|
6230
|
-
const file = e?.target?.files?.[0];
|
|
6231
|
-
if (file) {
|
|
6232
|
-
const imageUrl = URL.createObjectURL(file);
|
|
6233
|
-
setSelectedImage(imageUrl);
|
|
6234
|
-
setInitialImage(null);
|
|
6235
|
-
onChange(file);
|
|
6236
|
-
const compressedBase64 = await convertUrlToBase64(imageUrl);
|
|
6237
|
-
const base64Data = extractBase64Data(compressedBase64);
|
|
6238
|
-
setValue(name, base64Data, {
|
|
6239
|
-
shouldDirty: true
|
|
6240
|
-
});
|
|
6241
|
-
}
|
|
6242
|
-
};
|
|
6243
|
-
const handleRemoveImage = (onChange) => {
|
|
6244
|
-
setSelectedImage(null);
|
|
6245
|
-
setInitialImage(null);
|
|
6246
|
-
onChange(null);
|
|
6247
|
-
};
|
|
6248
|
-
const isBlobUrl = (url) => {
|
|
6249
|
-
return /^blob:/.test(url);
|
|
6250
|
-
};
|
|
6241
|
+
const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
|
|
6242
|
+
const isBlobUrl = (url) => /^blob:/.test(url);
|
|
6251
6243
|
const checkIsImageLink = (url) => {
|
|
6252
6244
|
const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
|
|
6253
6245
|
return imageExtensions.test(url) || (0, import_utils16.isBase64Image)(url) || isBlobUrl(url);
|
|
6254
6246
|
};
|
|
6255
|
-
const
|
|
6247
|
+
const getBase64WithMimeType = (base64) => {
|
|
6256
6248
|
if (typeof base64 !== "string" || base64.length < 10) return null;
|
|
6257
6249
|
if ((0, import_utils16.isBase64Image)(base64)) return base64;
|
|
6258
6250
|
let mimeType = null;
|
|
@@ -6263,29 +6255,62 @@ var binaryFieldController = (props) => {
|
|
|
6263
6255
|
else if (base64.startsWith("UklGR")) mimeType = "image/webp";
|
|
6264
6256
|
return mimeType ? `data:${mimeType};base64,${base64}` : null;
|
|
6265
6257
|
};
|
|
6258
|
+
const handleFileChange = async (e, onChange) => {
|
|
6259
|
+
if (readonly) return;
|
|
6260
|
+
const file = e?.target?.files?.[0];
|
|
6261
|
+
if (!file) return;
|
|
6262
|
+
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
6263
|
+
alert(`File type not allowed: ${file.type}`);
|
|
6264
|
+
return;
|
|
6265
|
+
}
|
|
6266
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
6267
|
+
alert(`File exceeds 10MB limit.`);
|
|
6268
|
+
return;
|
|
6269
|
+
}
|
|
6270
|
+
const fileUrl = URL.createObjectURL(file);
|
|
6271
|
+
setSelectedFile(file);
|
|
6272
|
+
setInitialFile(null);
|
|
6273
|
+
setSelectedPreview(fileUrl);
|
|
6274
|
+
onChange(file);
|
|
6275
|
+
if (file.type.startsWith("image/") || file.type === "application/json") {
|
|
6276
|
+
const base64 = await convertUrlToBase64(fileUrl);
|
|
6277
|
+
const base64Data = extractBase64Data(base64);
|
|
6278
|
+
setValue(name, base64Data, { shouldDirty: true });
|
|
6279
|
+
} else {
|
|
6280
|
+
setValue(name, file, { shouldDirty: true });
|
|
6281
|
+
}
|
|
6282
|
+
if (filename) {
|
|
6283
|
+
setValue(
|
|
6284
|
+
rootField ? `${rootField?.name}.${index}.${filename}` : filename,
|
|
6285
|
+
file?.name,
|
|
6286
|
+
{ shouldDirty: true }
|
|
6287
|
+
);
|
|
6288
|
+
}
|
|
6289
|
+
};
|
|
6290
|
+
const handleRemoveFile = (onChange) => {
|
|
6291
|
+
if (selectedPreview) URL.revokeObjectURL(selectedPreview);
|
|
6292
|
+
setSelectedFile(null);
|
|
6293
|
+
setSelectedPreview(null);
|
|
6294
|
+
setInitialFile(null);
|
|
6295
|
+
onChange(null);
|
|
6296
|
+
};
|
|
6266
6297
|
(0, import_react22.useEffect)(() => {
|
|
6267
6298
|
return () => {
|
|
6268
|
-
if (
|
|
6269
|
-
URL.revokeObjectURL(
|
|
6299
|
+
if (selectedPreview) {
|
|
6300
|
+
URL.revokeObjectURL(selectedPreview);
|
|
6270
6301
|
}
|
|
6271
6302
|
};
|
|
6272
|
-
}, [
|
|
6273
|
-
(0, import_react22.useEffect)(() => {
|
|
6274
|
-
if (binaryRef.current) {
|
|
6275
|
-
const isInsideTable2 = !!binaryRef.current.closest("table");
|
|
6276
|
-
setIsInsideTable(isInsideTable2);
|
|
6277
|
-
}
|
|
6278
|
-
}, []);
|
|
6303
|
+
}, [selectedPreview]);
|
|
6279
6304
|
return {
|
|
6280
6305
|
inputId,
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6306
|
+
selectedFile,
|
|
6307
|
+
selectedPreview,
|
|
6308
|
+
initialFile,
|
|
6284
6309
|
binaryRef,
|
|
6285
|
-
|
|
6286
|
-
|
|
6310
|
+
handleFileChange,
|
|
6311
|
+
handleRemoveFile,
|
|
6287
6312
|
checkIsImageLink,
|
|
6288
|
-
|
|
6313
|
+
getBase64WithMimeType
|
|
6289
6314
|
};
|
|
6290
6315
|
};
|
|
6291
6316
|
|
package/dist/index.mjs
CHANGED
|
@@ -6274,12 +6274,33 @@ var colorFieldController = (props) => {
|
|
|
6274
6274
|
// src/widget/basic/binary-field/controller.ts
|
|
6275
6275
|
import { useEffect as useEffect13, useId as useId2, useRef as useRef4, useState as useState12 } from "react";
|
|
6276
6276
|
import { isBase64Image } from "@fctc/interface-logic/utils";
|
|
6277
|
+
var ALLOWED_TYPES = [
|
|
6278
|
+
"image/jpeg",
|
|
6279
|
+
"image/png",
|
|
6280
|
+
"application/pdf",
|
|
6281
|
+
"video/mp4",
|
|
6282
|
+
"application/zip",
|
|
6283
|
+
"application/x-zip-compressed",
|
|
6284
|
+
"application/vnd.ms-excel",
|
|
6285
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
6286
|
+
"application/json"
|
|
6287
|
+
];
|
|
6288
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
6289
|
+
var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
|
|
6277
6290
|
var binaryFieldController = (props) => {
|
|
6278
|
-
const {
|
|
6291
|
+
const {
|
|
6292
|
+
name,
|
|
6293
|
+
methods,
|
|
6294
|
+
readonly = false,
|
|
6295
|
+
value,
|
|
6296
|
+
filename,
|
|
6297
|
+
rootField,
|
|
6298
|
+
index
|
|
6299
|
+
} = props;
|
|
6279
6300
|
const inputId = useId2();
|
|
6280
|
-
const [
|
|
6281
|
-
const [
|
|
6282
|
-
const [
|
|
6301
|
+
const [selectedFile, setSelectedFile] = useState12(null);
|
|
6302
|
+
const [selectedPreview, setSelectedPreview] = useState12(null);
|
|
6303
|
+
const [initialFile, setInitialFile] = useState12(value || null);
|
|
6283
6304
|
const { setValue } = methods;
|
|
6284
6305
|
const binaryRef = useRef4(null);
|
|
6285
6306
|
const convertUrlToBase64 = async (url) => {
|
|
@@ -6288,9 +6309,7 @@ var binaryFieldController = (props) => {
|
|
|
6288
6309
|
const blob = await response.blob();
|
|
6289
6310
|
return new Promise((resolve, reject) => {
|
|
6290
6311
|
const reader = new FileReader();
|
|
6291
|
-
reader.onloadend = () =>
|
|
6292
|
-
resolve(reader.result);
|
|
6293
|
-
};
|
|
6312
|
+
reader.onloadend = () => resolve(reader.result);
|
|
6294
6313
|
reader.onerror = reject;
|
|
6295
6314
|
reader.readAsDataURL(blob);
|
|
6296
6315
|
});
|
|
@@ -6299,40 +6318,13 @@ var binaryFieldController = (props) => {
|
|
|
6299
6318
|
throw error;
|
|
6300
6319
|
}
|
|
6301
6320
|
};
|
|
6302
|
-
const extractBase64Data = (base64Url) =>
|
|
6303
|
-
|
|
6304
|
-
return base64Url.split("base64,")[1];
|
|
6305
|
-
}
|
|
6306
|
-
return base64Url;
|
|
6307
|
-
};
|
|
6308
|
-
const handleImageChange = async (e, onChange) => {
|
|
6309
|
-
if (readonly) return;
|
|
6310
|
-
const file = e?.target?.files?.[0];
|
|
6311
|
-
if (file) {
|
|
6312
|
-
const imageUrl = URL.createObjectURL(file);
|
|
6313
|
-
setSelectedImage(imageUrl);
|
|
6314
|
-
setInitialImage(null);
|
|
6315
|
-
onChange(file);
|
|
6316
|
-
const compressedBase64 = await convertUrlToBase64(imageUrl);
|
|
6317
|
-
const base64Data = extractBase64Data(compressedBase64);
|
|
6318
|
-
setValue(name, base64Data, {
|
|
6319
|
-
shouldDirty: true
|
|
6320
|
-
});
|
|
6321
|
-
}
|
|
6322
|
-
};
|
|
6323
|
-
const handleRemoveImage = (onChange) => {
|
|
6324
|
-
setSelectedImage(null);
|
|
6325
|
-
setInitialImage(null);
|
|
6326
|
-
onChange(null);
|
|
6327
|
-
};
|
|
6328
|
-
const isBlobUrl = (url) => {
|
|
6329
|
-
return /^blob:/.test(url);
|
|
6330
|
-
};
|
|
6321
|
+
const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
|
|
6322
|
+
const isBlobUrl = (url) => /^blob:/.test(url);
|
|
6331
6323
|
const checkIsImageLink = (url) => {
|
|
6332
6324
|
const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
|
|
6333
6325
|
return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
|
|
6334
6326
|
};
|
|
6335
|
-
const
|
|
6327
|
+
const getBase64WithMimeType = (base64) => {
|
|
6336
6328
|
if (typeof base64 !== "string" || base64.length < 10) return null;
|
|
6337
6329
|
if (isBase64Image(base64)) return base64;
|
|
6338
6330
|
let mimeType = null;
|
|
@@ -6343,29 +6335,62 @@ var binaryFieldController = (props) => {
|
|
|
6343
6335
|
else if (base64.startsWith("UklGR")) mimeType = "image/webp";
|
|
6344
6336
|
return mimeType ? `data:${mimeType};base64,${base64}` : null;
|
|
6345
6337
|
};
|
|
6338
|
+
const handleFileChange = async (e, onChange) => {
|
|
6339
|
+
if (readonly) return;
|
|
6340
|
+
const file = e?.target?.files?.[0];
|
|
6341
|
+
if (!file) return;
|
|
6342
|
+
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
6343
|
+
alert(`File type not allowed: ${file.type}`);
|
|
6344
|
+
return;
|
|
6345
|
+
}
|
|
6346
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
6347
|
+
alert(`File exceeds 10MB limit.`);
|
|
6348
|
+
return;
|
|
6349
|
+
}
|
|
6350
|
+
const fileUrl = URL.createObjectURL(file);
|
|
6351
|
+
setSelectedFile(file);
|
|
6352
|
+
setInitialFile(null);
|
|
6353
|
+
setSelectedPreview(fileUrl);
|
|
6354
|
+
onChange(file);
|
|
6355
|
+
if (file.type.startsWith("image/") || file.type === "application/json") {
|
|
6356
|
+
const base64 = await convertUrlToBase64(fileUrl);
|
|
6357
|
+
const base64Data = extractBase64Data(base64);
|
|
6358
|
+
setValue(name, base64Data, { shouldDirty: true });
|
|
6359
|
+
} else {
|
|
6360
|
+
setValue(name, file, { shouldDirty: true });
|
|
6361
|
+
}
|
|
6362
|
+
if (filename) {
|
|
6363
|
+
setValue(
|
|
6364
|
+
rootField ? `${rootField?.name}.${index}.${filename}` : filename,
|
|
6365
|
+
file?.name,
|
|
6366
|
+
{ shouldDirty: true }
|
|
6367
|
+
);
|
|
6368
|
+
}
|
|
6369
|
+
};
|
|
6370
|
+
const handleRemoveFile = (onChange) => {
|
|
6371
|
+
if (selectedPreview) URL.revokeObjectURL(selectedPreview);
|
|
6372
|
+
setSelectedFile(null);
|
|
6373
|
+
setSelectedPreview(null);
|
|
6374
|
+
setInitialFile(null);
|
|
6375
|
+
onChange(null);
|
|
6376
|
+
};
|
|
6346
6377
|
useEffect13(() => {
|
|
6347
6378
|
return () => {
|
|
6348
|
-
if (
|
|
6349
|
-
URL.revokeObjectURL(
|
|
6379
|
+
if (selectedPreview) {
|
|
6380
|
+
URL.revokeObjectURL(selectedPreview);
|
|
6350
6381
|
}
|
|
6351
6382
|
};
|
|
6352
|
-
}, [
|
|
6353
|
-
useEffect13(() => {
|
|
6354
|
-
if (binaryRef.current) {
|
|
6355
|
-
const isInsideTable2 = !!binaryRef.current.closest("table");
|
|
6356
|
-
setIsInsideTable(isInsideTable2);
|
|
6357
|
-
}
|
|
6358
|
-
}, []);
|
|
6383
|
+
}, [selectedPreview]);
|
|
6359
6384
|
return {
|
|
6360
6385
|
inputId,
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6386
|
+
selectedFile,
|
|
6387
|
+
selectedPreview,
|
|
6388
|
+
initialFile,
|
|
6364
6389
|
binaryRef,
|
|
6365
|
-
|
|
6366
|
-
|
|
6390
|
+
handleFileChange,
|
|
6391
|
+
handleRemoveFile,
|
|
6367
6392
|
checkIsImageLink,
|
|
6368
|
-
|
|
6393
|
+
getBase64WithMimeType
|
|
6369
6394
|
};
|
|
6370
6395
|
};
|
|
6371
6396
|
|
package/dist/types.d.mts
CHANGED
package/dist/types.d.ts
CHANGED
package/dist/widget.d.mts
CHANGED
|
@@ -208,16 +208,19 @@ declare const colorFieldController: (props: IColorFieldProps) => {
|
|
|
208
208
|
savePickColor: (colorObject: any) => Promise<void>;
|
|
209
209
|
};
|
|
210
210
|
|
|
211
|
-
declare const binaryFieldController: (props: IInputFieldProps
|
|
211
|
+
declare const binaryFieldController: (props: IInputFieldProps & {
|
|
212
|
+
rootField?: any;
|
|
213
|
+
index?: number;
|
|
214
|
+
}) => {
|
|
212
215
|
inputId: string;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
+
selectedFile: File | null;
|
|
217
|
+
selectedPreview: string | null;
|
|
218
|
+
initialFile: any;
|
|
216
219
|
binaryRef: react.RefObject<HTMLDivElement>;
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
handleFileChange: (e: ChangeEvent<HTMLInputElement>, onChange: (file: File | null) => void) => Promise<void>;
|
|
221
|
+
handleRemoveFile: (onChange: (file: File | null) => void) => void;
|
|
219
222
|
checkIsImageLink: (url: string) => boolean;
|
|
220
|
-
|
|
223
|
+
getBase64WithMimeType: (base64: string) => string | null;
|
|
221
224
|
};
|
|
222
225
|
|
|
223
226
|
declare const tableHeadController: (props: any) => {
|
package/dist/widget.d.ts
CHANGED
|
@@ -208,16 +208,19 @@ declare const colorFieldController: (props: IColorFieldProps) => {
|
|
|
208
208
|
savePickColor: (colorObject: any) => Promise<void>;
|
|
209
209
|
};
|
|
210
210
|
|
|
211
|
-
declare const binaryFieldController: (props: IInputFieldProps
|
|
211
|
+
declare const binaryFieldController: (props: IInputFieldProps & {
|
|
212
|
+
rootField?: any;
|
|
213
|
+
index?: number;
|
|
214
|
+
}) => {
|
|
212
215
|
inputId: string;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
+
selectedFile: File | null;
|
|
217
|
+
selectedPreview: string | null;
|
|
218
|
+
initialFile: any;
|
|
216
219
|
binaryRef: react.RefObject<HTMLDivElement>;
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
handleFileChange: (e: ChangeEvent<HTMLInputElement>, onChange: (file: File | null) => void) => Promise<void>;
|
|
221
|
+
handleRemoveFile: (onChange: (file: File | null) => void) => void;
|
|
219
222
|
checkIsImageLink: (url: string) => boolean;
|
|
220
|
-
|
|
223
|
+
getBase64WithMimeType: (base64: string) => string | null;
|
|
221
224
|
};
|
|
222
225
|
|
|
223
226
|
declare const tableHeadController: (props: any) => {
|
package/dist/widget.js
CHANGED
|
@@ -5431,12 +5431,33 @@ var colorFieldController = (props) => {
|
|
|
5431
5431
|
// src/widget/basic/binary-field/controller.ts
|
|
5432
5432
|
var import_react22 = require("react");
|
|
5433
5433
|
var import_utils16 = require("@fctc/interface-logic/utils");
|
|
5434
|
+
var ALLOWED_TYPES = [
|
|
5435
|
+
"image/jpeg",
|
|
5436
|
+
"image/png",
|
|
5437
|
+
"application/pdf",
|
|
5438
|
+
"video/mp4",
|
|
5439
|
+
"application/zip",
|
|
5440
|
+
"application/x-zip-compressed",
|
|
5441
|
+
"application/vnd.ms-excel",
|
|
5442
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
5443
|
+
"application/json"
|
|
5444
|
+
];
|
|
5445
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
5446
|
+
var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
|
|
5434
5447
|
var binaryFieldController = (props) => {
|
|
5435
|
-
const {
|
|
5448
|
+
const {
|
|
5449
|
+
name,
|
|
5450
|
+
methods,
|
|
5451
|
+
readonly = false,
|
|
5452
|
+
value,
|
|
5453
|
+
filename,
|
|
5454
|
+
rootField,
|
|
5455
|
+
index
|
|
5456
|
+
} = props;
|
|
5436
5457
|
const inputId = (0, import_react22.useId)();
|
|
5437
|
-
const [
|
|
5438
|
-
const [
|
|
5439
|
-
const [
|
|
5458
|
+
const [selectedFile, setSelectedFile] = (0, import_react22.useState)(null);
|
|
5459
|
+
const [selectedPreview, setSelectedPreview] = (0, import_react22.useState)(null);
|
|
5460
|
+
const [initialFile, setInitialFile] = (0, import_react22.useState)(value || null);
|
|
5440
5461
|
const { setValue } = methods;
|
|
5441
5462
|
const binaryRef = (0, import_react22.useRef)(null);
|
|
5442
5463
|
const convertUrlToBase64 = async (url) => {
|
|
@@ -5445,9 +5466,7 @@ var binaryFieldController = (props) => {
|
|
|
5445
5466
|
const blob = await response.blob();
|
|
5446
5467
|
return new Promise((resolve, reject) => {
|
|
5447
5468
|
const reader = new FileReader();
|
|
5448
|
-
reader.onloadend = () =>
|
|
5449
|
-
resolve(reader.result);
|
|
5450
|
-
};
|
|
5469
|
+
reader.onloadend = () => resolve(reader.result);
|
|
5451
5470
|
reader.onerror = reject;
|
|
5452
5471
|
reader.readAsDataURL(blob);
|
|
5453
5472
|
});
|
|
@@ -5456,40 +5475,13 @@ var binaryFieldController = (props) => {
|
|
|
5456
5475
|
throw error;
|
|
5457
5476
|
}
|
|
5458
5477
|
};
|
|
5459
|
-
const extractBase64Data = (base64Url) =>
|
|
5460
|
-
|
|
5461
|
-
return base64Url.split("base64,")[1];
|
|
5462
|
-
}
|
|
5463
|
-
return base64Url;
|
|
5464
|
-
};
|
|
5465
|
-
const handleImageChange = async (e, onChange) => {
|
|
5466
|
-
if (readonly) return;
|
|
5467
|
-
const file = e?.target?.files?.[0];
|
|
5468
|
-
if (file) {
|
|
5469
|
-
const imageUrl = URL.createObjectURL(file);
|
|
5470
|
-
setSelectedImage(imageUrl);
|
|
5471
|
-
setInitialImage(null);
|
|
5472
|
-
onChange(file);
|
|
5473
|
-
const compressedBase64 = await convertUrlToBase64(imageUrl);
|
|
5474
|
-
const base64Data = extractBase64Data(compressedBase64);
|
|
5475
|
-
setValue(name, base64Data, {
|
|
5476
|
-
shouldDirty: true
|
|
5477
|
-
});
|
|
5478
|
-
}
|
|
5479
|
-
};
|
|
5480
|
-
const handleRemoveImage = (onChange) => {
|
|
5481
|
-
setSelectedImage(null);
|
|
5482
|
-
setInitialImage(null);
|
|
5483
|
-
onChange(null);
|
|
5484
|
-
};
|
|
5485
|
-
const isBlobUrl = (url) => {
|
|
5486
|
-
return /^blob:/.test(url);
|
|
5487
|
-
};
|
|
5478
|
+
const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
|
|
5479
|
+
const isBlobUrl = (url) => /^blob:/.test(url);
|
|
5488
5480
|
const checkIsImageLink = (url) => {
|
|
5489
5481
|
const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
|
|
5490
5482
|
return imageExtensions.test(url) || (0, import_utils16.isBase64Image)(url) || isBlobUrl(url);
|
|
5491
5483
|
};
|
|
5492
|
-
const
|
|
5484
|
+
const getBase64WithMimeType = (base64) => {
|
|
5493
5485
|
if (typeof base64 !== "string" || base64.length < 10) return null;
|
|
5494
5486
|
if ((0, import_utils16.isBase64Image)(base64)) return base64;
|
|
5495
5487
|
let mimeType = null;
|
|
@@ -5500,29 +5492,62 @@ var binaryFieldController = (props) => {
|
|
|
5500
5492
|
else if (base64.startsWith("UklGR")) mimeType = "image/webp";
|
|
5501
5493
|
return mimeType ? `data:${mimeType};base64,${base64}` : null;
|
|
5502
5494
|
};
|
|
5495
|
+
const handleFileChange = async (e, onChange) => {
|
|
5496
|
+
if (readonly) return;
|
|
5497
|
+
const file = e?.target?.files?.[0];
|
|
5498
|
+
if (!file) return;
|
|
5499
|
+
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
5500
|
+
alert(`File type not allowed: ${file.type}`);
|
|
5501
|
+
return;
|
|
5502
|
+
}
|
|
5503
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
5504
|
+
alert(`File exceeds 10MB limit.`);
|
|
5505
|
+
return;
|
|
5506
|
+
}
|
|
5507
|
+
const fileUrl = URL.createObjectURL(file);
|
|
5508
|
+
setSelectedFile(file);
|
|
5509
|
+
setInitialFile(null);
|
|
5510
|
+
setSelectedPreview(fileUrl);
|
|
5511
|
+
onChange(file);
|
|
5512
|
+
if (file.type.startsWith("image/") || file.type === "application/json") {
|
|
5513
|
+
const base64 = await convertUrlToBase64(fileUrl);
|
|
5514
|
+
const base64Data = extractBase64Data(base64);
|
|
5515
|
+
setValue(name, base64Data, { shouldDirty: true });
|
|
5516
|
+
} else {
|
|
5517
|
+
setValue(name, file, { shouldDirty: true });
|
|
5518
|
+
}
|
|
5519
|
+
if (filename) {
|
|
5520
|
+
setValue(
|
|
5521
|
+
rootField ? `${rootField?.name}.${index}.${filename}` : filename,
|
|
5522
|
+
file?.name,
|
|
5523
|
+
{ shouldDirty: true }
|
|
5524
|
+
);
|
|
5525
|
+
}
|
|
5526
|
+
};
|
|
5527
|
+
const handleRemoveFile = (onChange) => {
|
|
5528
|
+
if (selectedPreview) URL.revokeObjectURL(selectedPreview);
|
|
5529
|
+
setSelectedFile(null);
|
|
5530
|
+
setSelectedPreview(null);
|
|
5531
|
+
setInitialFile(null);
|
|
5532
|
+
onChange(null);
|
|
5533
|
+
};
|
|
5503
5534
|
(0, import_react22.useEffect)(() => {
|
|
5504
5535
|
return () => {
|
|
5505
|
-
if (
|
|
5506
|
-
URL.revokeObjectURL(
|
|
5536
|
+
if (selectedPreview) {
|
|
5537
|
+
URL.revokeObjectURL(selectedPreview);
|
|
5507
5538
|
}
|
|
5508
5539
|
};
|
|
5509
|
-
}, [
|
|
5510
|
-
(0, import_react22.useEffect)(() => {
|
|
5511
|
-
if (binaryRef.current) {
|
|
5512
|
-
const isInsideTable2 = !!binaryRef.current.closest("table");
|
|
5513
|
-
setIsInsideTable(isInsideTable2);
|
|
5514
|
-
}
|
|
5515
|
-
}, []);
|
|
5540
|
+
}, [selectedPreview]);
|
|
5516
5541
|
return {
|
|
5517
5542
|
inputId,
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5543
|
+
selectedFile,
|
|
5544
|
+
selectedPreview,
|
|
5545
|
+
initialFile,
|
|
5521
5546
|
binaryRef,
|
|
5522
|
-
|
|
5523
|
-
|
|
5547
|
+
handleFileChange,
|
|
5548
|
+
handleRemoveFile,
|
|
5524
5549
|
checkIsImageLink,
|
|
5525
|
-
|
|
5550
|
+
getBase64WithMimeType
|
|
5526
5551
|
};
|
|
5527
5552
|
};
|
|
5528
5553
|
|
package/dist/widget.mjs
CHANGED
|
@@ -5488,12 +5488,33 @@ var colorFieldController = (props) => {
|
|
|
5488
5488
|
// src/widget/basic/binary-field/controller.ts
|
|
5489
5489
|
import { useEffect as useEffect13, useId as useId2, useRef as useRef4, useState as useState12 } from "react";
|
|
5490
5490
|
import { isBase64Image } from "@fctc/interface-logic/utils";
|
|
5491
|
+
var ALLOWED_TYPES = [
|
|
5492
|
+
"image/jpeg",
|
|
5493
|
+
"image/png",
|
|
5494
|
+
"application/pdf",
|
|
5495
|
+
"video/mp4",
|
|
5496
|
+
"application/zip",
|
|
5497
|
+
"application/x-zip-compressed",
|
|
5498
|
+
"application/vnd.ms-excel",
|
|
5499
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
5500
|
+
"application/json"
|
|
5501
|
+
];
|
|
5502
|
+
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
5503
|
+
var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
|
|
5491
5504
|
var binaryFieldController = (props) => {
|
|
5492
|
-
const {
|
|
5505
|
+
const {
|
|
5506
|
+
name,
|
|
5507
|
+
methods,
|
|
5508
|
+
readonly = false,
|
|
5509
|
+
value,
|
|
5510
|
+
filename,
|
|
5511
|
+
rootField,
|
|
5512
|
+
index
|
|
5513
|
+
} = props;
|
|
5493
5514
|
const inputId = useId2();
|
|
5494
|
-
const [
|
|
5495
|
-
const [
|
|
5496
|
-
const [
|
|
5515
|
+
const [selectedFile, setSelectedFile] = useState12(null);
|
|
5516
|
+
const [selectedPreview, setSelectedPreview] = useState12(null);
|
|
5517
|
+
const [initialFile, setInitialFile] = useState12(value || null);
|
|
5497
5518
|
const { setValue } = methods;
|
|
5498
5519
|
const binaryRef = useRef4(null);
|
|
5499
5520
|
const convertUrlToBase64 = async (url) => {
|
|
@@ -5502,9 +5523,7 @@ var binaryFieldController = (props) => {
|
|
|
5502
5523
|
const blob = await response.blob();
|
|
5503
5524
|
return new Promise((resolve, reject) => {
|
|
5504
5525
|
const reader = new FileReader();
|
|
5505
|
-
reader.onloadend = () =>
|
|
5506
|
-
resolve(reader.result);
|
|
5507
|
-
};
|
|
5526
|
+
reader.onloadend = () => resolve(reader.result);
|
|
5508
5527
|
reader.onerror = reject;
|
|
5509
5528
|
reader.readAsDataURL(blob);
|
|
5510
5529
|
});
|
|
@@ -5513,40 +5532,13 @@ var binaryFieldController = (props) => {
|
|
|
5513
5532
|
throw error;
|
|
5514
5533
|
}
|
|
5515
5534
|
};
|
|
5516
|
-
const extractBase64Data = (base64Url) =>
|
|
5517
|
-
|
|
5518
|
-
return base64Url.split("base64,")[1];
|
|
5519
|
-
}
|
|
5520
|
-
return base64Url;
|
|
5521
|
-
};
|
|
5522
|
-
const handleImageChange = async (e, onChange) => {
|
|
5523
|
-
if (readonly) return;
|
|
5524
|
-
const file = e?.target?.files?.[0];
|
|
5525
|
-
if (file) {
|
|
5526
|
-
const imageUrl = URL.createObjectURL(file);
|
|
5527
|
-
setSelectedImage(imageUrl);
|
|
5528
|
-
setInitialImage(null);
|
|
5529
|
-
onChange(file);
|
|
5530
|
-
const compressedBase64 = await convertUrlToBase64(imageUrl);
|
|
5531
|
-
const base64Data = extractBase64Data(compressedBase64);
|
|
5532
|
-
setValue(name, base64Data, {
|
|
5533
|
-
shouldDirty: true
|
|
5534
|
-
});
|
|
5535
|
-
}
|
|
5536
|
-
};
|
|
5537
|
-
const handleRemoveImage = (onChange) => {
|
|
5538
|
-
setSelectedImage(null);
|
|
5539
|
-
setInitialImage(null);
|
|
5540
|
-
onChange(null);
|
|
5541
|
-
};
|
|
5542
|
-
const isBlobUrl = (url) => {
|
|
5543
|
-
return /^blob:/.test(url);
|
|
5544
|
-
};
|
|
5535
|
+
const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
|
|
5536
|
+
const isBlobUrl = (url) => /^blob:/.test(url);
|
|
5545
5537
|
const checkIsImageLink = (url) => {
|
|
5546
5538
|
const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
|
|
5547
5539
|
return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
|
|
5548
5540
|
};
|
|
5549
|
-
const
|
|
5541
|
+
const getBase64WithMimeType = (base64) => {
|
|
5550
5542
|
if (typeof base64 !== "string" || base64.length < 10) return null;
|
|
5551
5543
|
if (isBase64Image(base64)) return base64;
|
|
5552
5544
|
let mimeType = null;
|
|
@@ -5557,29 +5549,62 @@ var binaryFieldController = (props) => {
|
|
|
5557
5549
|
else if (base64.startsWith("UklGR")) mimeType = "image/webp";
|
|
5558
5550
|
return mimeType ? `data:${mimeType};base64,${base64}` : null;
|
|
5559
5551
|
};
|
|
5552
|
+
const handleFileChange = async (e, onChange) => {
|
|
5553
|
+
if (readonly) return;
|
|
5554
|
+
const file = e?.target?.files?.[0];
|
|
5555
|
+
if (!file) return;
|
|
5556
|
+
if (!ALLOWED_TYPES.includes(file.type)) {
|
|
5557
|
+
alert(`File type not allowed: ${file.type}`);
|
|
5558
|
+
return;
|
|
5559
|
+
}
|
|
5560
|
+
if (file.size > MAX_FILE_SIZE) {
|
|
5561
|
+
alert(`File exceeds 10MB limit.`);
|
|
5562
|
+
return;
|
|
5563
|
+
}
|
|
5564
|
+
const fileUrl = URL.createObjectURL(file);
|
|
5565
|
+
setSelectedFile(file);
|
|
5566
|
+
setInitialFile(null);
|
|
5567
|
+
setSelectedPreview(fileUrl);
|
|
5568
|
+
onChange(file);
|
|
5569
|
+
if (file.type.startsWith("image/") || file.type === "application/json") {
|
|
5570
|
+
const base64 = await convertUrlToBase64(fileUrl);
|
|
5571
|
+
const base64Data = extractBase64Data(base64);
|
|
5572
|
+
setValue(name, base64Data, { shouldDirty: true });
|
|
5573
|
+
} else {
|
|
5574
|
+
setValue(name, file, { shouldDirty: true });
|
|
5575
|
+
}
|
|
5576
|
+
if (filename) {
|
|
5577
|
+
setValue(
|
|
5578
|
+
rootField ? `${rootField?.name}.${index}.${filename}` : filename,
|
|
5579
|
+
file?.name,
|
|
5580
|
+
{ shouldDirty: true }
|
|
5581
|
+
);
|
|
5582
|
+
}
|
|
5583
|
+
};
|
|
5584
|
+
const handleRemoveFile = (onChange) => {
|
|
5585
|
+
if (selectedPreview) URL.revokeObjectURL(selectedPreview);
|
|
5586
|
+
setSelectedFile(null);
|
|
5587
|
+
setSelectedPreview(null);
|
|
5588
|
+
setInitialFile(null);
|
|
5589
|
+
onChange(null);
|
|
5590
|
+
};
|
|
5560
5591
|
useEffect13(() => {
|
|
5561
5592
|
return () => {
|
|
5562
|
-
if (
|
|
5563
|
-
URL.revokeObjectURL(
|
|
5593
|
+
if (selectedPreview) {
|
|
5594
|
+
URL.revokeObjectURL(selectedPreview);
|
|
5564
5595
|
}
|
|
5565
5596
|
};
|
|
5566
|
-
}, [
|
|
5567
|
-
useEffect13(() => {
|
|
5568
|
-
if (binaryRef.current) {
|
|
5569
|
-
const isInsideTable2 = !!binaryRef.current.closest("table");
|
|
5570
|
-
setIsInsideTable(isInsideTable2);
|
|
5571
|
-
}
|
|
5572
|
-
}, []);
|
|
5597
|
+
}, [selectedPreview]);
|
|
5573
5598
|
return {
|
|
5574
5599
|
inputId,
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5600
|
+
selectedFile,
|
|
5601
|
+
selectedPreview,
|
|
5602
|
+
initialFile,
|
|
5578
5603
|
binaryRef,
|
|
5579
|
-
|
|
5580
|
-
|
|
5604
|
+
handleFileChange,
|
|
5605
|
+
handleRemoveFile,
|
|
5581
5606
|
checkIsImageLink,
|
|
5582
|
-
|
|
5607
|
+
getBase64WithMimeType
|
|
5583
5608
|
};
|
|
5584
5609
|
};
|
|
5585
5610
|
|