formanitor 0.0.5 → 0.0.8
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 +134 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -13
- package/dist/index.d.ts +10 -13
- package/dist/index.mjs +134 -59
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -353,10 +353,13 @@ var FormStore = class {
|
|
|
353
353
|
if (field.type === "image_upload" || field.type === "signature") {
|
|
354
354
|
const raw = values[field.id];
|
|
355
355
|
if (raw !== void 0 && raw !== null && raw !== "") {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
356
|
+
const key = typeof raw === "string" ? raw : raw.s3_key || raw.value || null;
|
|
357
|
+
if (key && typeof key === "string") {
|
|
358
|
+
result[field.id] = {
|
|
359
|
+
_type: "s3_key",
|
|
360
|
+
value: key
|
|
361
|
+
};
|
|
362
|
+
}
|
|
360
363
|
}
|
|
361
364
|
}
|
|
362
365
|
});
|
|
@@ -368,7 +371,20 @@ var FormStore = class {
|
|
|
368
371
|
this.schema.computations.forEach((comp) => {
|
|
369
372
|
if (comp.type === "sum") {
|
|
370
373
|
const sum = comp.fields.reduce((acc, fieldId) => {
|
|
371
|
-
const
|
|
374
|
+
const raw = this.state.values[fieldId];
|
|
375
|
+
const fieldDef = this.fieldMap[fieldId];
|
|
376
|
+
const options = fieldDef?.type === "select" || fieldDef?.type === "multiselect" || fieldDef?.type === "radio" || fieldDef?.type === "checkbox" ? fieldDef.options : void 0;
|
|
377
|
+
const hasScoreOptions = options?.some((o) => o.score !== void 0);
|
|
378
|
+
let val;
|
|
379
|
+
if (hasScoreOptions && options) {
|
|
380
|
+
const selected = fieldDef?.type === "multiselect" || fieldDef?.type === "checkbox" ? (Array.isArray(raw) ? raw : [raw]).filter(Boolean) : [raw];
|
|
381
|
+
val = selected.reduce((s, v) => {
|
|
382
|
+
const opt = options.find((o) => o.value === v || String(o.value) === String(v));
|
|
383
|
+
return s + (opt && "score" in opt && typeof opt.score === "number" ? opt.score : 0);
|
|
384
|
+
}, 0);
|
|
385
|
+
} else {
|
|
386
|
+
val = Number(raw) || 0;
|
|
387
|
+
}
|
|
372
388
|
return acc + val;
|
|
373
389
|
}, 0);
|
|
374
390
|
if (this.state.values[comp.target] !== sum) {
|
|
@@ -1539,8 +1555,15 @@ var smoothPoint = (prev, curr, smoothing = 0.75) => {
|
|
|
1539
1555
|
y: prev.y * smoothing + curr.y * (1 - smoothing)
|
|
1540
1556
|
};
|
|
1541
1557
|
};
|
|
1558
|
+
function extractDisplayUrl(value) {
|
|
1559
|
+
if (!value || typeof value !== "object") return null;
|
|
1560
|
+
if (typeof value.presigned_url === "string" && value.presigned_url) {
|
|
1561
|
+
return value.presigned_url;
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1542
1565
|
var SignatureUploadWidget = ({ fieldId }) => {
|
|
1543
|
-
const { fieldDef, setValue, setTouched, error, disabled, touched } = useField(fieldId);
|
|
1566
|
+
const { fieldDef, setValue, setTouched, error, disabled, touched, value } = useField(fieldId);
|
|
1544
1567
|
const store = useFormStore();
|
|
1545
1568
|
const { state } = useForm();
|
|
1546
1569
|
const canvasRef = React11.useRef(null);
|
|
@@ -1549,13 +1572,14 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1549
1572
|
const lastTimeRef = React11.useRef(null);
|
|
1550
1573
|
const lastWidthRef = React11.useRef(2);
|
|
1551
1574
|
const [isDrawing, setIsDrawing] = React11.useState(false);
|
|
1552
|
-
const [
|
|
1575
|
+
const [hasDrawing, setHasDrawing] = React11.useState(false);
|
|
1553
1576
|
const [isUploading, setIsUploading] = React11.useState(false);
|
|
1577
|
+
const [isConfirmed, setIsConfirmed] = React11.useState(false);
|
|
1554
1578
|
const showError = !!error && (touched || state.submitAttempted);
|
|
1555
|
-
|
|
1556
|
-
const
|
|
1557
|
-
if (!uploadHandler) return null;
|
|
1579
|
+
const displayUrl = React11.useMemo(() => extractDisplayUrl(value), [value]);
|
|
1580
|
+
const showPreview = displayUrl !== null;
|
|
1558
1581
|
React11.useEffect(() => {
|
|
1582
|
+
if (showPreview) return;
|
|
1559
1583
|
const canvas = canvasRef.current;
|
|
1560
1584
|
if (!canvas) return;
|
|
1561
1585
|
const ctx = canvas.getContext("2d");
|
|
@@ -1573,7 +1597,9 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1573
1597
|
ctx.strokeStyle = "#000";
|
|
1574
1598
|
ctx.fillStyle = "#fff";
|
|
1575
1599
|
ctx.fillRect(0, 0, width, height);
|
|
1576
|
-
}, []);
|
|
1600
|
+
}, [showPreview]);
|
|
1601
|
+
const uploadHandler = store.getUploadHandler();
|
|
1602
|
+
if (!fieldDef || !uploadHandler) return null;
|
|
1577
1603
|
const getPoint = (event) => {
|
|
1578
1604
|
const canvas = canvasRef.current;
|
|
1579
1605
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -1586,6 +1612,7 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1586
1612
|
const startDrawing = (event) => {
|
|
1587
1613
|
if (disabled) return;
|
|
1588
1614
|
setIsDrawing(true);
|
|
1615
|
+
setIsConfirmed(false);
|
|
1589
1616
|
setTouched();
|
|
1590
1617
|
const ctx = canvasRef.current?.getContext("2d");
|
|
1591
1618
|
if (!ctx) return;
|
|
@@ -1627,23 +1654,31 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1627
1654
|
lastPointRef.current = smoothed;
|
|
1628
1655
|
lastTimeRef.current = now;
|
|
1629
1656
|
lastWidthRef.current = width;
|
|
1630
|
-
|
|
1657
|
+
setHasDrawing(true);
|
|
1631
1658
|
};
|
|
1632
1659
|
const stopDrawing = () => {
|
|
1633
1660
|
setIsDrawing(false);
|
|
1634
1661
|
lastPointRef.current = null;
|
|
1635
1662
|
lastTimeRef.current = null;
|
|
1636
1663
|
};
|
|
1637
|
-
const
|
|
1664
|
+
const clearSignature = () => {
|
|
1665
|
+
if (showPreview) {
|
|
1666
|
+
setValue(null);
|
|
1667
|
+
setTouched();
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1638
1670
|
const canvas = canvasRef.current;
|
|
1639
1671
|
const ctx = canvas?.getContext("2d");
|
|
1640
|
-
if (
|
|
1641
|
-
|
|
1642
|
-
|
|
1672
|
+
if (canvas && ctx) {
|
|
1673
|
+
ctx.fillStyle = "#fff";
|
|
1674
|
+
ctx.fillRect(0, 0, 400, 200);
|
|
1675
|
+
}
|
|
1643
1676
|
pathRef.current = "";
|
|
1644
1677
|
lastPointRef.current = null;
|
|
1645
|
-
|
|
1678
|
+
setHasDrawing(false);
|
|
1679
|
+
setIsConfirmed(false);
|
|
1646
1680
|
setValue(null);
|
|
1681
|
+
setTouched();
|
|
1647
1682
|
};
|
|
1648
1683
|
const generateSVG = () => `
|
|
1649
1684
|
<svg width="400" height="200" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -1656,7 +1691,7 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1656
1691
|
fill="none"/>
|
|
1657
1692
|
</svg>`.trim();
|
|
1658
1693
|
const confirmSignature = async () => {
|
|
1659
|
-
if (!
|
|
1694
|
+
if (!hasDrawing) return;
|
|
1660
1695
|
setIsUploading(true);
|
|
1661
1696
|
setTouched();
|
|
1662
1697
|
try {
|
|
@@ -1665,55 +1700,95 @@ var SignatureUploadWidget = ({ fieldId }) => {
|
|
|
1665
1700
|
const filename = `signature_${Date.now()}.svg`;
|
|
1666
1701
|
const key = await uploadHandler(blob, filename);
|
|
1667
1702
|
setValue(key);
|
|
1703
|
+
setIsConfirmed(true);
|
|
1704
|
+
setHasDrawing(false);
|
|
1705
|
+
} catch (err) {
|
|
1706
|
+
console.error("[SignatureUpload] Upload failed:", err);
|
|
1668
1707
|
} finally {
|
|
1669
1708
|
setIsUploading(false);
|
|
1670
1709
|
}
|
|
1671
1710
|
};
|
|
1711
|
+
const canClear = showPreview ? !disabled : hasDrawing || isConfirmed;
|
|
1672
1712
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1673
1713
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
1674
1714
|
fieldDef.label,
|
|
1675
1715
|
fieldDef.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
1676
1716
|
] }),
|
|
1677
|
-
|
|
1678
|
-
/*
|
|
1679
|
-
|
|
1680
|
-
{
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
+
showPreview ? (
|
|
1718
|
+
/* ── Preview mode: existing signature from backend ── */
|
|
1719
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1720
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border border-gray-200 rounded bg-white flex items-center justify-start p-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1721
|
+
"img",
|
|
1722
|
+
{
|
|
1723
|
+
src: displayUrl,
|
|
1724
|
+
alt: "Signature",
|
|
1725
|
+
className: "object-contain max-w-full",
|
|
1726
|
+
style: { width: 400, height: 200 }
|
|
1727
|
+
}
|
|
1728
|
+
) }),
|
|
1729
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1730
|
+
Button,
|
|
1731
|
+
{
|
|
1732
|
+
type: "button",
|
|
1733
|
+
size: "icon",
|
|
1734
|
+
variant: "ghost",
|
|
1735
|
+
className: "absolute top-2 left-2 bg-white/80 hover:bg-red-50",
|
|
1736
|
+
onClick: clearSignature,
|
|
1737
|
+
disabled: !canClear,
|
|
1738
|
+
title: "Delete signature and draw a new one",
|
|
1739
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
|
|
1740
|
+
}
|
|
1741
|
+
)
|
|
1742
|
+
] })
|
|
1743
|
+
) : (
|
|
1744
|
+
/* ── Canvas mode: drawing / confirmed ── */
|
|
1745
|
+
/* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1746
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1747
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1748
|
+
"canvas",
|
|
1749
|
+
{
|
|
1750
|
+
ref: canvasRef,
|
|
1751
|
+
className: `border rounded touch-none ${isConfirmed ? "border-green-300 cursor-default" : "border-gray-200 cursor-crosshair"}`,
|
|
1752
|
+
onMouseDown: startDrawing,
|
|
1753
|
+
onMouseMove: draw,
|
|
1754
|
+
onMouseUp: stopDrawing,
|
|
1755
|
+
onMouseLeave: stopDrawing,
|
|
1756
|
+
onTouchStart: startDrawing,
|
|
1757
|
+
onTouchMove: draw,
|
|
1758
|
+
onTouchEnd: stopDrawing
|
|
1759
|
+
}
|
|
1760
|
+
),
|
|
1761
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1762
|
+
Button,
|
|
1763
|
+
{
|
|
1764
|
+
type: "button",
|
|
1765
|
+
size: "icon",
|
|
1766
|
+
variant: "ghost",
|
|
1767
|
+
className: "absolute top-2 left-2 bg-white/80",
|
|
1768
|
+
onClick: clearSignature,
|
|
1769
|
+
disabled: !canClear,
|
|
1770
|
+
title: isConfirmed ? "Clear saved signature" : "Clear canvas",
|
|
1771
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
|
|
1772
|
+
}
|
|
1773
|
+
)
|
|
1774
|
+
] }),
|
|
1775
|
+
isConfirmed ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-green-600", children: [
|
|
1776
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }),
|
|
1777
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Signature saved" })
|
|
1778
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1779
|
+
Button,
|
|
1780
|
+
{
|
|
1781
|
+
type: "button",
|
|
1782
|
+
onClick: confirmSignature,
|
|
1783
|
+
disabled: !hasDrawing || isUploading,
|
|
1784
|
+
className: "text-xs",
|
|
1785
|
+
children: [
|
|
1786
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4 mr-1" }),
|
|
1787
|
+
isUploading ? "Saving\u2026" : "Confirm"
|
|
1788
|
+
]
|
|
1789
|
+
}
|
|
1790
|
+
)
|
|
1791
|
+
] })
|
|
1717
1792
|
),
|
|
1718
1793
|
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
1719
1794
|
] });
|
|
@@ -2271,7 +2346,7 @@ var ReadOnlyText = ({ fieldDef, value }) => {
|
|
|
2271
2346
|
className: "prose prose-sm max-w-none text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50",
|
|
2272
2347
|
dangerouslySetInnerHTML: { __html: displayValue }
|
|
2273
2348
|
}
|
|
2274
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem]
|
|
2349
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: displayValue || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400 italic", children: "No value" }) })
|
|
2275
2350
|
] });
|
|
2276
2351
|
};
|
|
2277
2352
|
var ReadOnlySelect = ({ fieldDef, value }) => {
|