@fctc/widget-logic 3.10.5 → 3.10.7

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/hooks.js CHANGED
@@ -568,7 +568,6 @@ var useCompany = ({ service }) => {
568
568
  (0, import_react7.useEffect)(() => {
569
569
  if (current_company_id) {
570
570
  const companyIDs = [current_company_id];
571
- setAllowCompanies([...companyIDs]);
572
571
  setCompanies(companyIDs);
573
572
  }
574
573
  }, [current_company_id]);
package/dist/hooks.mjs CHANGED
@@ -549,7 +549,6 @@ var useCompany = ({ service }) => {
549
549
  useEffect4(() => {
550
550
  if (current_company_id) {
551
551
  const companyIDs = [current_company_id];
552
- setAllowCompanies([...companyIDs]);
553
552
  setCompanies(companyIDs);
554
553
  }
555
554
  }, [current_company_id]);
package/dist/index.js CHANGED
@@ -4618,7 +4618,6 @@ var useCompany = ({ service }) => {
4618
4618
  (0, import_react7.useEffect)(() => {
4619
4619
  if (current_company_id) {
4620
4620
  const companyIDs = [current_company_id];
4621
- setAllowCompanies([...companyIDs]);
4622
4621
  setCompanies(companyIDs);
4623
4622
  }
4624
4623
  }, [current_company_id]);
@@ -6194,12 +6193,33 @@ var colorFieldController = (props) => {
6194
6193
  // src/widget/basic/binary-field/controller.ts
6195
6194
  var import_react22 = require("react");
6196
6195
  var import_utils16 = require("@fctc/interface-logic/utils");
6196
+ var ALLOWED_TYPES = [
6197
+ "image/jpeg",
6198
+ "image/png",
6199
+ "application/pdf",
6200
+ "video/mp4",
6201
+ "application/zip",
6202
+ "application/x-zip-compressed",
6203
+ "application/vnd.ms-excel",
6204
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
6205
+ "application/json"
6206
+ ];
6207
+ var MAX_FILE_SIZE = 10 * 1024 * 1024;
6208
+ var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
6197
6209
  var binaryFieldController = (props) => {
6198
- const { name, methods, readonly = false, value } = props;
6210
+ const {
6211
+ name,
6212
+ methods,
6213
+ readonly = false,
6214
+ value,
6215
+ filename,
6216
+ rootField,
6217
+ index
6218
+ } = props;
6199
6219
  const inputId = (0, import_react22.useId)();
6200
- const [selectedImage, setSelectedImage] = (0, import_react22.useState)(null);
6201
- const [initialImage, setInitialImage] = (0, import_react22.useState)(value || null);
6202
- const [isInsideTable, setIsInsideTable] = (0, import_react22.useState)(false);
6220
+ const [selectedFile, setSelectedFile] = (0, import_react22.useState)(null);
6221
+ const [selectedPreview, setSelectedPreview] = (0, import_react22.useState)(null);
6222
+ const [initialFile, setInitialFile] = (0, import_react22.useState)(value || null);
6203
6223
  const { setValue } = methods;
6204
6224
  const binaryRef = (0, import_react22.useRef)(null);
6205
6225
  const convertUrlToBase64 = async (url) => {
@@ -6208,9 +6228,7 @@ var binaryFieldController = (props) => {
6208
6228
  const blob = await response.blob();
6209
6229
  return new Promise((resolve, reject) => {
6210
6230
  const reader = new FileReader();
6211
- reader.onloadend = () => {
6212
- resolve(reader.result);
6213
- };
6231
+ reader.onloadend = () => resolve(reader.result);
6214
6232
  reader.onerror = reject;
6215
6233
  reader.readAsDataURL(blob);
6216
6234
  });
@@ -6219,40 +6237,13 @@ var binaryFieldController = (props) => {
6219
6237
  throw error;
6220
6238
  }
6221
6239
  };
6222
- const extractBase64Data = (base64Url) => {
6223
- if (base64Url.includes("base64,")) {
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
- };
6240
+ const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
6241
+ const isBlobUrl = (url) => /^blob:/.test(url);
6251
6242
  const checkIsImageLink = (url) => {
6252
6243
  const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
6253
6244
  return imageExtensions.test(url) || (0, import_utils16.isBase64Image)(url) || isBlobUrl(url);
6254
6245
  };
6255
- const getImageBase64WithMimeType = (base64) => {
6246
+ const getBase64WithMimeType = (base64) => {
6256
6247
  if (typeof base64 !== "string" || base64.length < 10) return null;
6257
6248
  if ((0, import_utils16.isBase64Image)(base64)) return base64;
6258
6249
  let mimeType = null;
@@ -6263,29 +6254,62 @@ var binaryFieldController = (props) => {
6263
6254
  else if (base64.startsWith("UklGR")) mimeType = "image/webp";
6264
6255
  return mimeType ? `data:${mimeType};base64,${base64}` : null;
6265
6256
  };
6257
+ const handleFileChange = async (e, onChange) => {
6258
+ if (readonly) return;
6259
+ const file = e?.target?.files?.[0];
6260
+ if (!file) return;
6261
+ if (!ALLOWED_TYPES.includes(file.type)) {
6262
+ alert(`File type not allowed: ${file.type}`);
6263
+ return;
6264
+ }
6265
+ if (file.size > MAX_FILE_SIZE) {
6266
+ alert(`File exceeds 10MB limit.`);
6267
+ return;
6268
+ }
6269
+ const fileUrl = URL.createObjectURL(file);
6270
+ setSelectedFile(file);
6271
+ setInitialFile(null);
6272
+ setSelectedPreview(fileUrl);
6273
+ onChange(file);
6274
+ if (file.type.startsWith("image/") || file.type === "application/json") {
6275
+ const base64 = await convertUrlToBase64(fileUrl);
6276
+ const base64Data = extractBase64Data(base64);
6277
+ setValue(name, base64Data, { shouldDirty: true });
6278
+ } else {
6279
+ setValue(name, file, { shouldDirty: true });
6280
+ }
6281
+ if (filename) {
6282
+ setValue(
6283
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
6284
+ file?.name,
6285
+ { shouldDirty: true }
6286
+ );
6287
+ }
6288
+ };
6289
+ const handleRemoveFile = (onChange) => {
6290
+ if (selectedPreview) URL.revokeObjectURL(selectedPreview);
6291
+ setSelectedFile(null);
6292
+ setSelectedPreview(null);
6293
+ setInitialFile(null);
6294
+ onChange(null);
6295
+ };
6266
6296
  (0, import_react22.useEffect)(() => {
6267
6297
  return () => {
6268
- if (selectedImage) {
6269
- URL.revokeObjectURL(selectedImage);
6298
+ if (selectedPreview) {
6299
+ URL.revokeObjectURL(selectedPreview);
6270
6300
  }
6271
6301
  };
6272
- }, [selectedImage]);
6273
- (0, import_react22.useEffect)(() => {
6274
- if (binaryRef.current) {
6275
- const isInsideTable2 = !!binaryRef.current.closest("table");
6276
- setIsInsideTable(isInsideTable2);
6277
- }
6278
- }, []);
6302
+ }, [selectedPreview]);
6279
6303
  return {
6280
6304
  inputId,
6281
- selectedImage,
6282
- initialImage,
6283
- isInsideTable,
6305
+ selectedFile,
6306
+ selectedPreview,
6307
+ initialFile,
6284
6308
  binaryRef,
6285
- handleImageChange,
6286
- handleRemoveImage,
6309
+ handleFileChange,
6310
+ handleRemoveFile,
6287
6311
  checkIsImageLink,
6288
- getImageBase64WithMimeType
6312
+ getBase64WithMimeType
6289
6313
  };
6290
6314
  };
6291
6315
 
package/dist/index.mjs CHANGED
@@ -4693,7 +4693,6 @@ var useCompany = ({ service }) => {
4693
4693
  useEffect4(() => {
4694
4694
  if (current_company_id) {
4695
4695
  const companyIDs = [current_company_id];
4696
- setAllowCompanies([...companyIDs]);
4697
4696
  setCompanies(companyIDs);
4698
4697
  }
4699
4698
  }, [current_company_id]);
@@ -6274,12 +6273,33 @@ var colorFieldController = (props) => {
6274
6273
  // src/widget/basic/binary-field/controller.ts
6275
6274
  import { useEffect as useEffect13, useId as useId2, useRef as useRef4, useState as useState12 } from "react";
6276
6275
  import { isBase64Image } from "@fctc/interface-logic/utils";
6276
+ var ALLOWED_TYPES = [
6277
+ "image/jpeg",
6278
+ "image/png",
6279
+ "application/pdf",
6280
+ "video/mp4",
6281
+ "application/zip",
6282
+ "application/x-zip-compressed",
6283
+ "application/vnd.ms-excel",
6284
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
6285
+ "application/json"
6286
+ ];
6287
+ var MAX_FILE_SIZE = 10 * 1024 * 1024;
6288
+ var MAX_TOTAL_SIZE = 50 * 1024 * 1024;
6277
6289
  var binaryFieldController = (props) => {
6278
- const { name, methods, readonly = false, value } = props;
6290
+ const {
6291
+ name,
6292
+ methods,
6293
+ readonly = false,
6294
+ value,
6295
+ filename,
6296
+ rootField,
6297
+ index
6298
+ } = props;
6279
6299
  const inputId = useId2();
6280
- const [selectedImage, setSelectedImage] = useState12(null);
6281
- const [initialImage, setInitialImage] = useState12(value || null);
6282
- const [isInsideTable, setIsInsideTable] = useState12(false);
6300
+ const [selectedFile, setSelectedFile] = useState12(null);
6301
+ const [selectedPreview, setSelectedPreview] = useState12(null);
6302
+ const [initialFile, setInitialFile] = useState12(value || null);
6283
6303
  const { setValue } = methods;
6284
6304
  const binaryRef = useRef4(null);
6285
6305
  const convertUrlToBase64 = async (url) => {
@@ -6288,9 +6308,7 @@ var binaryFieldController = (props) => {
6288
6308
  const blob = await response.blob();
6289
6309
  return new Promise((resolve, reject) => {
6290
6310
  const reader = new FileReader();
6291
- reader.onloadend = () => {
6292
- resolve(reader.result);
6293
- };
6311
+ reader.onloadend = () => resolve(reader.result);
6294
6312
  reader.onerror = reject;
6295
6313
  reader.readAsDataURL(blob);
6296
6314
  });
@@ -6299,40 +6317,13 @@ var binaryFieldController = (props) => {
6299
6317
  throw error;
6300
6318
  }
6301
6319
  };
6302
- const extractBase64Data = (base64Url) => {
6303
- if (base64Url.includes("base64,")) {
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
- };
6320
+ const extractBase64Data = (base64Url) => base64Url.includes("base64,") ? base64Url.split("base64,")[1] : base64Url;
6321
+ const isBlobUrl = (url) => /^blob:/.test(url);
6331
6322
  const checkIsImageLink = (url) => {
6332
6323
  const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
6333
6324
  return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
6334
6325
  };
6335
- const getImageBase64WithMimeType = (base64) => {
6326
+ const getBase64WithMimeType = (base64) => {
6336
6327
  if (typeof base64 !== "string" || base64.length < 10) return null;
6337
6328
  if (isBase64Image(base64)) return base64;
6338
6329
  let mimeType = null;
@@ -6343,29 +6334,62 @@ var binaryFieldController = (props) => {
6343
6334
  else if (base64.startsWith("UklGR")) mimeType = "image/webp";
6344
6335
  return mimeType ? `data:${mimeType};base64,${base64}` : null;
6345
6336
  };
6337
+ const handleFileChange = async (e, onChange) => {
6338
+ if (readonly) return;
6339
+ const file = e?.target?.files?.[0];
6340
+ if (!file) return;
6341
+ if (!ALLOWED_TYPES.includes(file.type)) {
6342
+ alert(`File type not allowed: ${file.type}`);
6343
+ return;
6344
+ }
6345
+ if (file.size > MAX_FILE_SIZE) {
6346
+ alert(`File exceeds 10MB limit.`);
6347
+ return;
6348
+ }
6349
+ const fileUrl = URL.createObjectURL(file);
6350
+ setSelectedFile(file);
6351
+ setInitialFile(null);
6352
+ setSelectedPreview(fileUrl);
6353
+ onChange(file);
6354
+ if (file.type.startsWith("image/") || file.type === "application/json") {
6355
+ const base64 = await convertUrlToBase64(fileUrl);
6356
+ const base64Data = extractBase64Data(base64);
6357
+ setValue(name, base64Data, { shouldDirty: true });
6358
+ } else {
6359
+ setValue(name, file, { shouldDirty: true });
6360
+ }
6361
+ if (filename) {
6362
+ setValue(
6363
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
6364
+ file?.name,
6365
+ { shouldDirty: true }
6366
+ );
6367
+ }
6368
+ };
6369
+ const handleRemoveFile = (onChange) => {
6370
+ if (selectedPreview) URL.revokeObjectURL(selectedPreview);
6371
+ setSelectedFile(null);
6372
+ setSelectedPreview(null);
6373
+ setInitialFile(null);
6374
+ onChange(null);
6375
+ };
6346
6376
  useEffect13(() => {
6347
6377
  return () => {
6348
- if (selectedImage) {
6349
- URL.revokeObjectURL(selectedImage);
6378
+ if (selectedPreview) {
6379
+ URL.revokeObjectURL(selectedPreview);
6350
6380
  }
6351
6381
  };
6352
- }, [selectedImage]);
6353
- useEffect13(() => {
6354
- if (binaryRef.current) {
6355
- const isInsideTable2 = !!binaryRef.current.closest("table");
6356
- setIsInsideTable(isInsideTable2);
6357
- }
6358
- }, []);
6382
+ }, [selectedPreview]);
6359
6383
  return {
6360
6384
  inputId,
6361
- selectedImage,
6362
- initialImage,
6363
- isInsideTable,
6385
+ selectedFile,
6386
+ selectedPreview,
6387
+ initialFile,
6364
6388
  binaryRef,
6365
- handleImageChange,
6366
- handleRemoveImage,
6389
+ handleFileChange,
6390
+ handleRemoveFile,
6367
6391
  checkIsImageLink,
6368
- getImageBase64WithMimeType
6392
+ getBase64WithMimeType
6369
6393
  };
6370
6394
  };
6371
6395
 
package/dist/types.d.mts CHANGED
@@ -30,6 +30,7 @@ interface IInputFieldProps {
30
30
  widget?: string;
31
31
  aid?: string | number;
32
32
  context?: string | Object;
33
+ filename?: string;
33
34
  }
34
35
 
35
36
  export type { IInputFieldProps, ValuePropsType };
package/dist/types.d.ts CHANGED
@@ -30,6 +30,7 @@ interface IInputFieldProps {
30
30
  widget?: string;
31
31
  aid?: string | number;
32
32
  context?: string | Object;
33
+ filename?: string;
33
34
  }
34
35
 
35
36
  export type { IInputFieldProps, ValuePropsType };
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
- selectedImage: string | null;
214
- initialImage: any;
215
- isInsideTable: boolean;
216
+ selectedFile: File | null;
217
+ selectedPreview: string | null;
218
+ initialFile: any;
216
219
  binaryRef: react.RefObject<HTMLDivElement>;
217
- handleImageChange: (e: ChangeEvent<HTMLInputElement>, onChange: (file: File | null) => void) => Promise<void>;
218
- handleRemoveImage: (onChange: (file: File | null) => void) => void;
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
- getImageBase64WithMimeType: (base64: any) => string | null;
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
- selectedImage: string | null;
214
- initialImage: any;
215
- isInsideTable: boolean;
216
+ selectedFile: File | null;
217
+ selectedPreview: string | null;
218
+ initialFile: any;
216
219
  binaryRef: react.RefObject<HTMLDivElement>;
217
- handleImageChange: (e: ChangeEvent<HTMLInputElement>, onChange: (file: File | null) => void) => Promise<void>;
218
- handleRemoveImage: (onChange: (file: File | null) => void) => void;
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
- getImageBase64WithMimeType: (base64: any) => string | null;
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 { name, methods, readonly = false, value } = props;
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 [selectedImage, setSelectedImage] = (0, import_react22.useState)(null);
5438
- const [initialImage, setInitialImage] = (0, import_react22.useState)(value || null);
5439
- const [isInsideTable, setIsInsideTable] = (0, import_react22.useState)(false);
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
- if (base64Url.includes("base64,")) {
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 getImageBase64WithMimeType = (base64) => {
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 (selectedImage) {
5506
- URL.revokeObjectURL(selectedImage);
5536
+ if (selectedPreview) {
5537
+ URL.revokeObjectURL(selectedPreview);
5507
5538
  }
5508
5539
  };
5509
- }, [selectedImage]);
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
- selectedImage,
5519
- initialImage,
5520
- isInsideTable,
5543
+ selectedFile,
5544
+ selectedPreview,
5545
+ initialFile,
5521
5546
  binaryRef,
5522
- handleImageChange,
5523
- handleRemoveImage,
5547
+ handleFileChange,
5548
+ handleRemoveFile,
5524
5549
  checkIsImageLink,
5525
- getImageBase64WithMimeType
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 { name, methods, readonly = false, value } = props;
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 [selectedImage, setSelectedImage] = useState12(null);
5495
- const [initialImage, setInitialImage] = useState12(value || null);
5496
- const [isInsideTable, setIsInsideTable] = useState12(false);
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
- if (base64Url.includes("base64,")) {
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 getImageBase64WithMimeType = (base64) => {
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 (selectedImage) {
5563
- URL.revokeObjectURL(selectedImage);
5593
+ if (selectedPreview) {
5594
+ URL.revokeObjectURL(selectedPreview);
5564
5595
  }
5565
5596
  };
5566
- }, [selectedImage]);
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
- selectedImage,
5576
- initialImage,
5577
- isInsideTable,
5600
+ selectedFile,
5601
+ selectedPreview,
5602
+ initialFile,
5578
5603
  binaryRef,
5579
- handleImageChange,
5580
- handleRemoveImage,
5604
+ handleFileChange,
5605
+ handleRemoveFile,
5581
5606
  checkIsImageLink,
5582
- getImageBase64WithMimeType
5607
+ getBase64WithMimeType
5583
5608
  };
5584
5609
  };
5585
5610
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fctc/widget-logic",
3
- "version": "3.10.5",
3
+ "version": "3.10.7",
4
4
  "types": "dist/index.d.ts",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -74,7 +74,7 @@
74
74
  "test": "jest"
75
75
  },
76
76
  "dependencies": {
77
- "@fctc/interface-logic": "^3.5.0",
77
+ "@fctc/interface-logic": "^3.5.1",
78
78
  "@headlessui/react": "^2.2.6",
79
79
  "@tanstack/react-query": "^5.84.0",
80
80
  "i18next": "^25.3.2",