diff --git a/packages/ui/primitives/signature-pad/helper.ts b/packages/ui/primitives/signature-pad/helper.ts index ec4c19a8e..831dc6119 100644 --- a/packages/ui/primitives/signature-pad/helper.ts +++ b/packages/ui/primitives/signature-pad/helper.ts @@ -1,3 +1,39 @@ +import { SIGNATURE_MIN_COVERAGE_THRESHOLD } from '@documenso/lib/constants/signatures'; +import type { RefObject } from 'react'; + +/** + * Checks whether the signature covers enough of the canvas to be considered + * valid, by measuring the percentage of non-transparent pixels against + * SIGNATURE_MIN_COVERAGE_THRESHOLD. + */ +export const checkSignatureValidity = (element: RefObject) => { + if (!element.current) { + return false; + } + + const ctx = element.current.getContext('2d'); + + if (!ctx) { + return false; + } + + const imageData = ctx.getImageData(0, 0, element.current.width, element.current.height); + const data = imageData.data; + let filledPixels = 0; + const totalPixels = data.length / 4; + + for (let i = 0; i < data.length; i += 4) { + if (data[i + 3] > 0) { + filledPixels++; + } + } + + const filledPercentage = filledPixels / totalPixels; + const isValid = filledPercentage > SIGNATURE_MIN_COVERAGE_THRESHOLD; + + return isValid; +}; + export const average = (a: number, b: number) => (a + b) / 2; export const getSvgPathFromStroke = (points: number[][], closed = true) => { diff --git a/packages/ui/primitives/signature-pad/signature-pad-draw.tsx b/packages/ui/primitives/signature-pad/signature-pad-draw.tsx index acc77f9a7..a6981a604 100644 --- a/packages/ui/primitives/signature-pad/signature-pad-draw.tsx +++ b/packages/ui/primitives/signature-pad/signature-pad-draw.tsx @@ -1,46 +1,18 @@ import { unsafe_useEffectOnce } from '@documenso/lib/client-only/hooks/use-effect-once'; -import { SIGNATURE_CANVAS_DPI, SIGNATURE_MIN_COVERAGE_THRESHOLD } from '@documenso/lib/constants/signatures'; +import { SIGNATURE_CANVAS_DPI } from '@documenso/lib/constants/signatures'; -import { Trans } from '@lingui/react/macro'; +import { Trans, useLingui } from '@lingui/react/macro'; import { Undo2 } from 'lucide-react'; import type { StrokeOptions } from 'perfect-freehand'; import { getStroke } from 'perfect-freehand'; -import type { MouseEvent, PointerEvent, RefObject, TouchEvent } from 'react'; +import type { MouseEvent, PointerEvent, TouchEvent } from 'react'; import { useMemo, useRef, useState } from 'react'; import { cn } from '../../lib/utils'; -import { getSvgPathFromStroke } from './helper'; +import { checkSignatureValidity, getSvgPathFromStroke } from './helper'; import { Point } from './point'; import { SignaturePadColorPicker } from './signature-pad-color-picker'; -const checkSignatureValidity = (element: RefObject) => { - if (!element.current) { - return false; - } - - const ctx = element.current.getContext('2d'); - - if (!ctx) { - return false; - } - - const imageData = ctx.getImageData(0, 0, element.current.width, element.current.height); - const data = imageData.data; - let filledPixels = 0; - const totalPixels = data.length / 4; - - for (let i = 0; i < data.length; i += 4) { - if (data[i + 3] > 0) { - filledPixels++; - } - } - - const filledPercentage = filledPixels / totalPixels; - const isValid = filledPercentage > SIGNATURE_MIN_COVERAGE_THRESHOLD; - - return isValid; -}; - export type SignaturePadDrawProps = { className?: string; value: string; @@ -48,6 +20,8 @@ export type SignaturePadDrawProps = { }; export const SignaturePadDraw = ({ className, value, onChange, ...props }: SignaturePadDrawProps) => { + const { t } = useLingui(); + const $el = useRef(null); const $imageData = useRef(null); @@ -276,9 +250,19 @@ export const SignaturePadDraw = ({ className, value, onChange, ...props }: Signa {...props} /> - + -
+
+ + +
+ )} + + {hasImage && ( +
+ +
+ )} + + {isSignatureValid === false && ( +
+ + Signature is too small + +
+ )} + + {!hasImage && ( + $fileInput.current?.click()} + >
@@ -150,8 +446,8 @@ export const SignaturePadUpload = ({ className, value, onChange, ...props }: Sig
- )} -
+ + )}
); }; diff --git a/packages/ui/primitives/signature-pad/signature-tabs.tsx b/packages/ui/primitives/signature-pad/signature-tabs.tsx index 5a4ca10bf..9a9a82b47 100644 --- a/packages/ui/primitives/signature-pad/signature-tabs.tsx +++ b/packages/ui/primitives/signature-pad/signature-tabs.tsx @@ -59,7 +59,7 @@ interface TabsListProps extends React.HTMLAttributes { export function TabsList({ children, className, ...props }: TabsListProps) { return ( -
+
{children}
);