formanitor 0.0.30 → 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 +226 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -4
- package/dist/index.d.ts +20 -4
- package/dist/index.mjs +225 -3
- 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;
|
|
@@ -847,7 +847,7 @@ function VoiceMicButton({ fieldId, onTranscriptReady }) {
|
|
|
847
847
|
setActiveFieldId(fieldId);
|
|
848
848
|
setStatus("recording");
|
|
849
849
|
try {
|
|
850
|
-
await voice.startRecording();
|
|
850
|
+
await voice.startRecording(fieldId);
|
|
851
851
|
} catch {
|
|
852
852
|
setStatus("idle");
|
|
853
853
|
setActiveFieldId(null);
|
|
@@ -1229,6 +1229,19 @@ var RichTextWidget = ({ fieldId }) => {
|
|
|
1229
1229
|
const el = editor.view.dom;
|
|
1230
1230
|
el.style.minHeight = `${minHeight}px`;
|
|
1231
1231
|
}, [editor, minHeight]);
|
|
1232
|
+
React15.useEffect(() => {
|
|
1233
|
+
if (!editor || editor.isDestroyed) return;
|
|
1234
|
+
const el = editor.view.dom;
|
|
1235
|
+
const handler = (e) => {
|
|
1236
|
+
const { text } = e.detail;
|
|
1237
|
+
if (!text) return;
|
|
1238
|
+
const currentText = editor.getText();
|
|
1239
|
+
const prefix = currentText.length > 0 && !/\s$/.test(currentText) ? " " : "";
|
|
1240
|
+
editor.chain().focus().insertContent(prefix + text).run();
|
|
1241
|
+
};
|
|
1242
|
+
el.addEventListener("insertTranscript", handler);
|
|
1243
|
+
return () => el.removeEventListener("insertTranscript", handler);
|
|
1244
|
+
}, [editor]);
|
|
1232
1245
|
React15.useEffect(() => {
|
|
1233
1246
|
if (!editor || editor.isDestroyed) return;
|
|
1234
1247
|
const fromForm = stringValue;
|
|
@@ -2173,6 +2186,162 @@ var ImageUploadWidget = ({ fieldId }) => {
|
|
|
2173
2186
|
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
2174
2187
|
] });
|
|
2175
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
|
+
};
|
|
2176
2345
|
var distance = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
2177
2346
|
var smoothPoint = (prev, curr, smoothing = 0.75) => {
|
|
2178
2347
|
if (!prev) return curr;
|
|
@@ -7437,6 +7606,8 @@ function renderWidget(fieldId, fieldDef) {
|
|
|
7437
7606
|
return /* @__PURE__ */ jsxRuntime.jsx(RepeatableWidget, { fieldId });
|
|
7438
7607
|
case "image_upload":
|
|
7439
7608
|
return /* @__PURE__ */ jsxRuntime.jsx(ImageUploadWidget, { fieldId });
|
|
7609
|
+
case "media_upload":
|
|
7610
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MediaUploadWidget, { fieldId });
|
|
7440
7611
|
case "signature":
|
|
7441
7612
|
return /* @__PURE__ */ jsxRuntime.jsx(SignatureUploadWidget, { fieldId });
|
|
7442
7613
|
case "editable_table":
|
|
@@ -7844,6 +8015,55 @@ var ReadOnlyImageUpload = ({
|
|
|
7844
8015
|
fieldDef.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500", children: fieldDef.description })
|
|
7845
8016
|
] });
|
|
7846
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
|
+
};
|
|
7847
8067
|
var ReadOnlySignature = ({
|
|
7848
8068
|
fieldDef,
|
|
7849
8069
|
value
|
|
@@ -8045,6 +8265,8 @@ var ReadOnlyFieldRenderer = ({ fieldDef, value }) => {
|
|
|
8045
8265
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyRepeatable, { fieldDef, value });
|
|
8046
8266
|
case "image_upload":
|
|
8047
8267
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyImageUpload, { fieldDef, value });
|
|
8268
|
+
case "media_upload":
|
|
8269
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyMediaUpload, { fieldDef, value });
|
|
8048
8270
|
case "signature":
|
|
8049
8271
|
return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlySignature, { fieldDef, value });
|
|
8050
8272
|
case "editable_table":
|
|
@@ -8262,8 +8484,10 @@ exports.FormControls = FormControls;
|
|
|
8262
8484
|
exports.FormProvider = FormProvider;
|
|
8263
8485
|
exports.FormStore = FormStore;
|
|
8264
8486
|
exports.ImageUploadWidget = ImageUploadWidget;
|
|
8487
|
+
exports.MediaUploadWidget = MediaUploadWidget;
|
|
8265
8488
|
exports.ReadOnlyForm = ReadOnlyForm;
|
|
8266
8489
|
exports.ReadOnlyImageUpload = ReadOnlyImageUpload;
|
|
8490
|
+
exports.ReadOnlyMediaUpload = ReadOnlyMediaUpload;
|
|
8267
8491
|
exports.ReadOnlySignature = ReadOnlySignature;
|
|
8268
8492
|
exports.ReadOnlyTable = ReadOnlyTable;
|
|
8269
8493
|
exports.RichTextWidget = RichTextWidget;
|