formanitor 0.0.31 → 0.0.32
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 +212 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.mjs +211 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -458,7 +458,7 @@ var FormStore = class {
|
|
|
458
458
|
result[field.id] = parts.length > 0 ? parts.join("\n\n") : null;
|
|
459
459
|
return;
|
|
460
460
|
}
|
|
461
|
-
if (field.type === "image_upload" || field.type === "signature") {
|
|
461
|
+
if (field.type === "image_upload" || field.type === "media_upload" || field.type === "signature") {
|
|
462
462
|
const raw = values[field.id];
|
|
463
463
|
if (raw !== void 0 && raw !== null && raw !== "") {
|
|
464
464
|
const key = typeof raw === "string" ? raw : raw.s3_key || raw.value || null;
|
|
@@ -2186,6 +2186,162 @@ var ImageUploadWidget = ({ fieldId }) => {
|
|
|
2186
2186
|
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
2187
2187
|
] });
|
|
2188
2188
|
};
|
|
2189
|
+
function urlLooksLikePdf(url) {
|
|
2190
|
+
return /\.pdf($|\?)/i.test(url) || url.toLowerCase().includes("application/pdf");
|
|
2191
|
+
}
|
|
2192
|
+
function isAcceptedMediaFile(file) {
|
|
2193
|
+
if (file.type.startsWith("image/")) return true;
|
|
2194
|
+
if (file.type === "application/pdf") return true;
|
|
2195
|
+
if (file.name.toLowerCase().endsWith(".pdf")) return true;
|
|
2196
|
+
return false;
|
|
2197
|
+
}
|
|
2198
|
+
var MediaUploadWidget = ({ fieldId }) => {
|
|
2199
|
+
const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);
|
|
2200
|
+
const store = useFormStore();
|
|
2201
|
+
const { state } = useForm();
|
|
2202
|
+
const [isUploading, setIsUploading] = React15.useState(false);
|
|
2203
|
+
const [preview, setPreview] = React15.useState(null);
|
|
2204
|
+
const [previewIsPdf, setPreviewIsPdf] = React15.useState(false);
|
|
2205
|
+
const fileInputRef = React15.useRef(null);
|
|
2206
|
+
const pendingPreviewKindRef = React15.useRef(null);
|
|
2207
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
2208
|
+
if (!fieldDef) return null;
|
|
2209
|
+
const uploadHandler = store.getUploadHandler();
|
|
2210
|
+
if (!uploadHandler) {
|
|
2211
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
2212
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: fieldId, children: [
|
|
2213
|
+
fieldDef.label,
|
|
2214
|
+
fieldDef.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
2215
|
+
] }),
|
|
2216
|
+
/* @__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." }) })
|
|
2217
|
+
] });
|
|
2218
|
+
}
|
|
2219
|
+
React15__namespace.default.useEffect(() => {
|
|
2220
|
+
if (value && typeof value === "string") {
|
|
2221
|
+
setPreview(value);
|
|
2222
|
+
if (pendingPreviewKindRef.current) {
|
|
2223
|
+
setPreviewIsPdf(pendingPreviewKindRef.current === "pdf");
|
|
2224
|
+
pendingPreviewKindRef.current = null;
|
|
2225
|
+
} else {
|
|
2226
|
+
setPreviewIsPdf(urlLooksLikePdf(value));
|
|
2227
|
+
}
|
|
2228
|
+
} else {
|
|
2229
|
+
setPreview(null);
|
|
2230
|
+
setPreviewIsPdf(false);
|
|
2231
|
+
}
|
|
2232
|
+
}, [value]);
|
|
2233
|
+
const handleFileSelect = async (event) => {
|
|
2234
|
+
const file = event.target.files?.[0];
|
|
2235
|
+
if (!file) return;
|
|
2236
|
+
if (!isAcceptedMediaFile(file)) {
|
|
2237
|
+
alert("Please select an image or PDF file");
|
|
2238
|
+
return;
|
|
2239
|
+
}
|
|
2240
|
+
const maxSize = 10 * 1024 * 1024;
|
|
2241
|
+
if (file.size > maxSize) {
|
|
2242
|
+
alert("File size must be less than 10MB");
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
const isPdf = file.type === "application/pdf" || file.name.toLowerCase().endsWith(".pdf");
|
|
2246
|
+
setIsUploading(true);
|
|
2247
|
+
setTouched();
|
|
2248
|
+
store.incrementPendingUploads();
|
|
2249
|
+
try {
|
|
2250
|
+
const previewUrl = URL.createObjectURL(file);
|
|
2251
|
+
setPreview(previewUrl);
|
|
2252
|
+
setPreviewIsPdf(isPdf);
|
|
2253
|
+
const s3Key = await uploadHandler(file, file.name);
|
|
2254
|
+
pendingPreviewKindRef.current = isPdf ? "pdf" : "image";
|
|
2255
|
+
setValue(s3Key);
|
|
2256
|
+
} catch (error2) {
|
|
2257
|
+
console.error("Upload failed:", error2);
|
|
2258
|
+
const errorMessage = error2 instanceof Error ? error2.message : "Upload failed. Please try again.";
|
|
2259
|
+
alert(errorMessage);
|
|
2260
|
+
setPreview(null);
|
|
2261
|
+
setPreviewIsPdf(false);
|
|
2262
|
+
} finally {
|
|
2263
|
+
setIsUploading(false);
|
|
2264
|
+
store.decrementPendingUploads();
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
const handleRemove = () => {
|
|
2268
|
+
pendingPreviewKindRef.current = null;
|
|
2269
|
+
setValue(null);
|
|
2270
|
+
setPreview(null);
|
|
2271
|
+
setPreviewIsPdf(false);
|
|
2272
|
+
if (fileInputRef.current) {
|
|
2273
|
+
fileInputRef.current.value = "";
|
|
2274
|
+
}
|
|
2275
|
+
setTouched();
|
|
2276
|
+
};
|
|
2277
|
+
const handleUploadClick = () => {
|
|
2278
|
+
fileInputRef.current?.click();
|
|
2279
|
+
};
|
|
2280
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
2281
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: fieldId, children: [
|
|
2282
|
+
fieldDef.label,
|
|
2283
|
+
fieldDef.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
2284
|
+
] }),
|
|
2285
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-2 border-dashed border-gray-300 rounded-lg p-4", children: preview ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
2286
|
+
previewIsPdf ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2287
|
+
"iframe",
|
|
2288
|
+
{
|
|
2289
|
+
src: preview,
|
|
2290
|
+
title: "Uploaded PDF",
|
|
2291
|
+
className: "w-full max-h-48 min-h-36 rounded-lg border border-gray-200 bg-white"
|
|
2292
|
+
}
|
|
2293
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2294
|
+
"img",
|
|
2295
|
+
{
|
|
2296
|
+
src: preview,
|
|
2297
|
+
alt: "Uploaded image",
|
|
2298
|
+
className: "max-w-full max-h-48 mx-auto rounded-lg"
|
|
2299
|
+
}
|
|
2300
|
+
),
|
|
2301
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2302
|
+
Button,
|
|
2303
|
+
{
|
|
2304
|
+
type: "button",
|
|
2305
|
+
variant: "destructive",
|
|
2306
|
+
size: "sm",
|
|
2307
|
+
className: "absolute top-2 right-2",
|
|
2308
|
+
onClick: handleRemove,
|
|
2309
|
+
disabled: disabled || isUploading,
|
|
2310
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
|
|
2311
|
+
}
|
|
2312
|
+
)
|
|
2313
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-8", children: [
|
|
2314
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "h-12 w-12 mx-auto text-gray-400 mb-4" }),
|
|
2315
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-600 mb-4", children: "Click to upload an image or PDF, or drag and drop" }),
|
|
2316
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2317
|
+
Button,
|
|
2318
|
+
{
|
|
2319
|
+
type: "button",
|
|
2320
|
+
variant: "outline",
|
|
2321
|
+
onClick: handleUploadClick,
|
|
2322
|
+
disabled: disabled || isUploading,
|
|
2323
|
+
children: [
|
|
2324
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "h-4 w-4 mr-2" }),
|
|
2325
|
+
isUploading ? "Uploading..." : "Choose Image"
|
|
2326
|
+
]
|
|
2327
|
+
}
|
|
2328
|
+
)
|
|
2329
|
+
] }) }),
|
|
2330
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2331
|
+
"input",
|
|
2332
|
+
{
|
|
2333
|
+
ref: fileInputRef,
|
|
2334
|
+
type: "file",
|
|
2335
|
+
accept: "image/*,application/pdf",
|
|
2336
|
+
onChange: handleFileSelect,
|
|
2337
|
+
className: "hidden",
|
|
2338
|
+
disabled: disabled || isUploading
|
|
2339
|
+
}
|
|
2340
|
+
),
|
|
2341
|
+
fieldDef.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: fieldDef.description }),
|
|
2342
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
2343
|
+
] });
|
|
2344
|
+
};
|
|
2189
2345
|
var distance = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
2190
2346
|
var smoothPoint = (prev, curr, smoothing = 0.75) => {
|
|
2191
2347
|
if (!prev) return curr;
|
|
@@ -7450,6 +7606,8 @@ function renderWidget(fieldId, fieldDef) {
|
|
|
7450
7606
|
return /* @__PURE__ */ jsxRuntime.jsx(RepeatableWidget, { fieldId });
|
|
7451
7607
|
case "image_upload":
|
|
7452
7608
|
return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadWidget, { fieldId });
|
|
7609
|
+
case "media_upload":
|
|
7610
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MediaUploadWidget, { fieldId });
|
|
7453
7611
|
case "signature":
|
|
7454
7612
|
return /* @__PURE__ */ jsxRuntime.jsx(SignatureUploadWidget, { fieldId });
|
|
7455
7613
|
case "editable_table":
|
|
@@ -7857,6 +8015,55 @@ var ReadOnlyImageUpload = ({
|
|
|
7857
8015
|
fieldDef.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: fieldDef.description })
|
|
7858
8016
|
] });
|
|
7859
8017
|
};
|
|
8018
|
+
function urlLooksLikePdf2(url) {
|
|
8019
|
+
return /\.pdf($|\?)/i.test(url) || url.toLowerCase().includes("application/pdf");
|
|
8020
|
+
}
|
|
8021
|
+
var ReadOnlyMediaUpload = ({
|
|
8022
|
+
fieldDef,
|
|
8023
|
+
value
|
|
8024
|
+
}) => {
|
|
8025
|
+
const [useIframe, setUseIframe] = React15.useState(false);
|
|
8026
|
+
let url = null;
|
|
8027
|
+
if (typeof value === "string") {
|
|
8028
|
+
url = value;
|
|
8029
|
+
} else if (value && typeof value === "object") {
|
|
8030
|
+
const typed = value;
|
|
8031
|
+
url = typed.presigned_url || typed.value || typed.s3_key || null;
|
|
8032
|
+
}
|
|
8033
|
+
React15.useEffect(() => {
|
|
8034
|
+
setUseIframe(false);
|
|
8035
|
+
}, [url]);
|
|
8036
|
+
const showAsPdf = url && (urlLooksLikePdf2(url) || useIframe);
|
|
8037
|
+
if (!url) {
|
|
8038
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
8039
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: fieldDef.label }),
|
|
8040
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-gray-200 rounded-lg p-4 bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center py-4", children: [
|
|
8041
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Image, { className: "h-8 w-8 mx-auto text-gray-400 mb-2" }),
|
|
8042
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500", children: "No file uploaded" })
|
|
8043
|
+
] }) })
|
|
8044
|
+
] });
|
|
8045
|
+
}
|
|
8046
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
8047
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: fieldDef.label }),
|
|
8048
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-gray-200 rounded-lg p-4 bg-white", children: showAsPdf ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8049
|
+
"iframe",
|
|
8050
|
+
{
|
|
8051
|
+
src: url,
|
|
8052
|
+
title: `${fieldDef.label} PDF`,
|
|
8053
|
+
className: "w-full max-h-48 min-h-36 rounded-lg border border-gray-200 bg-white"
|
|
8054
|
+
}
|
|
8055
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
8056
|
+
"img",
|
|
8057
|
+
{
|
|
8058
|
+
src: url,
|
|
8059
|
+
alt: `${fieldDef.label} upload`,
|
|
8060
|
+
className: "max-w-full max-h-48 mx-auto rounded-lg",
|
|
8061
|
+
onError: () => setUseIframe(true)
|
|
8062
|
+
}
|
|
8063
|
+
) }),
|
|
8064
|
+
fieldDef.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: fieldDef.description })
|
|
8065
|
+
] });
|
|
8066
|
+
};
|
|
7860
8067
|
var ReadOnlySignature = ({
|
|
7861
8068
|
fieldDef,
|
|
7862
8069
|
value
|
|
@@ -8058,6 +8265,8 @@ var ReadOnlyFieldRenderer = ({ fieldDef, value }) => {
|
|
|
8058
8265
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyRepeatable, { fieldDef, value });
|
|
8059
8266
|
case "image_upload":
|
|
8060
8267
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyImageUpload, { fieldDef, value });
|
|
8268
|
+
case "media_upload":
|
|
8269
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyMediaUpload, { fieldDef, value });
|
|
8061
8270
|
case "signature":
|
|
8062
8271
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlySignature, { fieldDef, value });
|
|
8063
8272
|
case "editable_table":
|
|
@@ -8275,8 +8484,10 @@ exports.FormControls = FormControls;
|
|
|
8275
8484
|
exports.FormProvider = FormProvider;
|
|
8276
8485
|
exports.FormStore = FormStore;
|
|
8277
8486
|
exports.ImageUploadWidget = ImageUploadWidget;
|
|
8487
|
+
exports.MediaUploadWidget = MediaUploadWidget;
|
|
8278
8488
|
exports.ReadOnlyForm = ReadOnlyForm;
|
|
8279
8489
|
exports.ReadOnlyImageUpload = ReadOnlyImageUpload;
|
|
8490
|
+
exports.ReadOnlyMediaUpload = ReadOnlyMediaUpload;
|
|
8280
8491
|
exports.ReadOnlySignature = ReadOnlySignature;
|
|
8281
8492
|
exports.ReadOnlyTable = ReadOnlyTable;
|
|
8282
8493
|
exports.RichTextWidget = RichTextWidget;
|