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 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
- result[field.id] = {
357
- _type: "s3_key",
358
- value: raw
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 val = Number(this.state.values[fieldId]) || 0;
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 [hasSignature, setHasSignature] = React11.useState(false);
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
- if (!fieldDef) return null;
1556
- const uploadHandler = store.getUploadHandler();
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
- setHasSignature(true);
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 clearCanvas = () => {
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 (!canvas || !ctx) return;
1641
- ctx.fillStyle = "#fff";
1642
- ctx.fillRect(0, 0, 400, 200);
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
- setHasSignature(false);
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 (!hasSignature) return;
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
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1678
- /* @__PURE__ */ jsxRuntime.jsx(
1679
- "canvas",
1680
- {
1681
- ref: canvasRef,
1682
- className: "border border-gray-200 rounded cursor-crosshair touch-none",
1683
- onMouseDown: startDrawing,
1684
- onMouseMove: draw,
1685
- onMouseUp: stopDrawing,
1686
- onMouseLeave: stopDrawing,
1687
- onTouchStart: startDrawing,
1688
- onTouchMove: draw,
1689
- onTouchEnd: stopDrawing
1690
- }
1691
- ),
1692
- /* @__PURE__ */ jsxRuntime.jsx(
1693
- Button,
1694
- {
1695
- type: "button",
1696
- size: "icon",
1697
- variant: "ghost",
1698
- className: "absolute top-2 left-2 bg-white/80",
1699
- onClick: clearCanvas,
1700
- disabled: !hasSignature,
1701
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "h-4 w-4" })
1702
- }
1703
- )
1704
- ] }),
1705
- /* @__PURE__ */ jsxRuntime.jsxs(
1706
- Button,
1707
- {
1708
- type: "button",
1709
- onClick: confirmSignature,
1710
- disabled: !hasSignature || isUploading,
1711
- className: "text-xs",
1712
- children: [
1713
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4 mr-1" }),
1714
- isUploading ? "Saving\u2026" : "Confirm"
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] flex items-center", children: displayValue || /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-400 italic", children: "No value" }) })
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 }) => {