formanitor 0.0.49 → 0.0.50

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.cjs CHANGED
@@ -1548,16 +1548,28 @@ var FormStore = class {
1548
1548
  result[field.id] = null;
1549
1549
  return;
1550
1550
  }
1551
- if (field.type === "image_upload" || field.type === "media_upload" || field.type === "signature") {
1551
+ if (field.type === "image_upload" || field.type === "media_upload" || field.type === "signature" || field.type === "file_upload") {
1552
1552
  const raw = values[field.id];
1553
- if (raw !== void 0 && raw !== null && raw !== "") {
1554
- const key = typeof raw === "string" ? raw : raw.s3_key || raw.value || null;
1555
- if (key && typeof key === "string") {
1556
- result[field.id] = {
1557
- _type: "s3_key",
1558
- value: key
1559
- };
1553
+ if (raw === void 0 || raw === null || raw === "") {
1554
+ return;
1555
+ }
1556
+ const wrapKey = (key2) => {
1557
+ if (typeof key2 !== "string" || !key2) return null;
1558
+ return { _type: "s3_key", value: key2 };
1559
+ };
1560
+ if (Array.isArray(raw)) {
1561
+ const wrapped2 = raw.map(
1562
+ (item) => typeof item === "string" ? wrapKey(item) : wrapKey(item.s3_key ?? item.value)
1563
+ ).filter(Boolean);
1564
+ if (wrapped2.length > 0) {
1565
+ result[field.id] = wrapped2;
1560
1566
  }
1567
+ return;
1568
+ }
1569
+ const key = typeof raw === "string" ? raw : raw.s3_key ?? raw.value ?? null;
1570
+ const wrapped = wrapKey(key);
1571
+ if (wrapped) {
1572
+ result[field.id] = wrapped;
1561
1573
  }
1562
1574
  }
1563
1575
  });
@@ -3795,6 +3807,190 @@ var SignatureUploadWidget = ({ fieldId }) => {
3795
3807
  showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
3796
3808
  ] });
3797
3809
  };
3810
+ function Upload3({
3811
+ value,
3812
+ accept,
3813
+ multiple,
3814
+ disabled,
3815
+ onChange,
3816
+ className,
3817
+ formatsLabel,
3818
+ placeholder = "Upload File",
3819
+ beforeUploadContent,
3820
+ id: idProp
3821
+ }) {
3822
+ const inputRef = React15__namespace.default.useRef(null);
3823
+ const generatedId = React15__namespace.default.useId();
3824
+ const inputId = idProp ?? generatedId;
3825
+ const handleFileChange = (e) => {
3826
+ onChange(e.target.files ?? null);
3827
+ };
3828
+ React15__namespace.default.useEffect(() => {
3829
+ if (!value && inputRef.current) {
3830
+ inputRef.current.value = "";
3831
+ }
3832
+ }, [value]);
3833
+ const count = value?.length ?? 0;
3834
+ const formatsText = formatsLabel ?? accept;
3835
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3836
+ "div",
3837
+ {
3838
+ className: cn(
3839
+ "border border-dashed bg-[#F7F7F7] border-gray-200 rounded-lg py-5 px-4 flex items-center justify-center text-[#989898]",
3840
+ disabled && "opacity-50 pointer-events-none",
3841
+ className
3842
+ ),
3843
+ children: [
3844
+ /* @__PURE__ */ jsxRuntime.jsx(
3845
+ "input",
3846
+ {
3847
+ type: "file",
3848
+ ref: inputRef,
3849
+ accept,
3850
+ id: inputId,
3851
+ className: "hidden",
3852
+ multiple,
3853
+ disabled,
3854
+ onChange: handleFileChange
3855
+ }
3856
+ ),
3857
+ /* @__PURE__ */ jsxRuntime.jsx(
3858
+ "label",
3859
+ {
3860
+ htmlFor: inputId,
3861
+ className: cn("cursor-pointer w-full", disabled && "cursor-not-allowed"),
3862
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { children: count > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-sm font-semibold text-gray-700", children: [
3863
+ count,
3864
+ " file",
3865
+ count === 1 ? "" : "s",
3866
+ " selected"
3867
+ ] }) : beforeUploadContent ? beforeUploadContent : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center", children: [
3868
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { size: 16, className: "rotate-180" }),
3869
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-semibold mt-0.5 text-gray-700", children: placeholder }),
3870
+ formatsText ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 text-[10px]", children: [
3871
+ "Supported formats - ",
3872
+ formatsText
3873
+ ] }) : null
3874
+ ] }) })
3875
+ }
3876
+ )
3877
+ ]
3878
+ }
3879
+ );
3880
+ }
3881
+ function fileListFromArray(files) {
3882
+ const dt = new DataTransfer();
3883
+ files.forEach((f) => dt.items.add(f));
3884
+ return dt.files;
3885
+ }
3886
+ function matchesAccept(file, accept) {
3887
+ if (!accept || accept === "*/*") return true;
3888
+ const tokens = accept.split(",").map((t) => t.trim().toLowerCase());
3889
+ const name = file.name.toLowerCase();
3890
+ const type = file.type.toLowerCase();
3891
+ return tokens.some((token) => {
3892
+ if (token.startsWith(".")) return name.endsWith(token);
3893
+ if (token.endsWith("/*")) {
3894
+ const prefix = token.slice(0, -1);
3895
+ return type.startsWith(prefix);
3896
+ }
3897
+ return type === token;
3898
+ });
3899
+ }
3900
+ var FormFileUploadWidget = ({
3901
+ fieldId
3902
+ }) => {
3903
+ const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
3904
+ const store = useFormStore();
3905
+ const { state } = useForm();
3906
+ const [localFiles, setLocalFiles] = React15.useState(null);
3907
+ const [isUploading, setIsUploading] = React15.useState(false);
3908
+ const showError = !!error && (touched || state.submitAttempted);
3909
+ if (!fieldDef || fieldDef.type !== "file_upload") return null;
3910
+ const def = fieldDef;
3911
+ const accept = def.accept ?? "*/*";
3912
+ const maxSize = def.maxSize ?? 10 * 1024 * 1024;
3913
+ const allowMultiple = def.multiple === true;
3914
+ const uploadHandler = store.getUploadHandler();
3915
+ if (!uploadHandler) {
3916
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3917
+ /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: fieldId, children: [
3918
+ fieldDef.label,
3919
+ fieldDef.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
3920
+ ] }),
3921
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-2 border-red-300 rounded-lg p-4 bg-red-50", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600", children: "Upload handler not configured. Please provide an onUpload function in FormProvider config." }) })
3922
+ ] });
3923
+ }
3924
+ const hasStoredValue = value !== null && value !== void 0 && value !== "" && !(Array.isArray(value) && value.length === 0);
3925
+ const handleChange = async (files) => {
3926
+ setTouched();
3927
+ if (!files || files.length === 0) {
3928
+ setLocalFiles(null);
3929
+ setValue(null);
3930
+ return;
3931
+ }
3932
+ const selected = Array.from(files);
3933
+ for (const file of selected) {
3934
+ if (!matchesAccept(file, accept)) {
3935
+ alert(`File type not allowed: ${file.name}`);
3936
+ return;
3937
+ }
3938
+ if (file.size > maxSize) {
3939
+ alert(
3940
+ `File must be less than ${Math.round(maxSize / (1024 * 1024))}MB: ${file.name}`
3941
+ );
3942
+ return;
3943
+ }
3944
+ }
3945
+ const toUpload = allowMultiple ? selected : [selected[0]];
3946
+ setLocalFiles(fileListFromArray(toUpload));
3947
+ setIsUploading(true);
3948
+ store.incrementPendingUploads();
3949
+ try {
3950
+ if (allowMultiple) {
3951
+ const keys = [];
3952
+ for (const file of toUpload) {
3953
+ keys.push(await uploadHandler(file, file.name));
3954
+ }
3955
+ setValue(keys);
3956
+ } else {
3957
+ const key = await uploadHandler(toUpload[0], toUpload[0].name);
3958
+ setValue(key);
3959
+ }
3960
+ } catch (err) {
3961
+ console.error("[FormFileUpload] Upload failed:", err);
3962
+ const message = err instanceof Error ? err.message : "Upload failed. Please try again.";
3963
+ alert(message);
3964
+ setLocalFiles(null);
3965
+ setValue(null);
3966
+ } finally {
3967
+ setIsUploading(false);
3968
+ store.decrementPendingUploads();
3969
+ }
3970
+ };
3971
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
3972
+ /* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: fieldId, children: [
3973
+ fieldDef.label,
3974
+ fieldDef.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
3975
+ ] }),
3976
+ /* @__PURE__ */ jsxRuntime.jsx(
3977
+ Upload3,
3978
+ {
3979
+ accept,
3980
+ multiple: allowMultiple,
3981
+ value: localFiles,
3982
+ onChange: handleChange,
3983
+ disabled: disabled || isUploading,
3984
+ placeholder: isUploading ? "Uploading..." : def.uploadPlaceholder ?? "Upload File",
3985
+ formatsLabel: def.uploadFormats,
3986
+ className: isUploading ? "opacity-70" : void 0
3987
+ }
3988
+ ),
3989
+ hasStoredValue && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-green-600", children: allowMultiple && Array.isArray(value) ? `${value.length} file(s) uploaded` : "File uploaded" }),
3990
+ fieldDef.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: fieldDef.description }),
3991
+ showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
3992
+ ] });
3993
+ };
3798
3994
  var EditableTableWidget = ({
3799
3995
  fieldId
3800
3996
  }) => {
@@ -14242,6 +14438,8 @@ function renderWidget(fieldId, fieldDef) {
14242
14438
  return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadWidget, { fieldId });
14243
14439
  case "media_upload":
14244
14440
  return /* @__PURE__ */ jsxRuntime.jsx(MediaUploadWidget, { fieldId });
14441
+ case "file_upload":
14442
+ return /* @__PURE__ */ jsxRuntime.jsx(FormFileUploadWidget, { fieldId });
14245
14443
  case "signature":
14246
14444
  return /* @__PURE__ */ jsxRuntime.jsx(SignatureUploadWidget, { fieldId });
14247
14445
  case "editable_table":
@@ -15340,6 +15538,8 @@ var ReadOnlyFieldRenderer = ({
15340
15538
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyImageUpload, { fieldDef, value });
15341
15539
  case "media_upload":
15342
15540
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyMediaUpload, { fieldDef, value });
15541
+ case "file_upload":
15542
+ return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyMediaUpload, { fieldDef, value });
15343
15543
  case "signature":
15344
15544
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlySignature, { fieldDef, value });
15345
15545
  case "editable_table":
@@ -15842,6 +16042,7 @@ exports.DynamicFormV2 = DynamicFormV2;
15842
16042
  exports.EMAIL_REGEX = EMAIL_REGEX;
15843
16043
  exports.FieldRenderer = FieldRenderer;
15844
16044
  exports.FormControls = FormControls;
16045
+ exports.FormFileUploadWidget = FormFileUploadWidget;
15845
16046
  exports.FormProvider = FormProvider;
15846
16047
  exports.FormStore = FormStore;
15847
16048
  exports.ImageUploadWidget = ImageUploadWidget;
@@ -15857,6 +16058,7 @@ exports.RichTextWidget = RichTextWidget;
15857
16058
  exports.SignatureUploadWidget = SignatureUploadWidget;
15858
16059
  exports.SmartForm = SmartForm;
15859
16060
  exports.SmartTextareaWidget = SmartTextareaWidget;
16061
+ exports.Upload = Upload3;
15860
16062
  exports.createUploadHandler = createUploadHandler;
15861
16063
  exports.evaluateRules = evaluateRules;
15862
16064
  exports.fieldMetaRequestsMarMedicationOrdersButton = fieldMetaRequestsMarMedicationOrdersButton;