Skip to content

Commit 3b76deb

Browse files
committed
feat(signature): refactoring and rearrange codes
1 parent 15e6fdc commit 3b76deb

5 files changed

Lines changed: 247 additions & 832 deletions

File tree

packages/pluggableWidgets/signature-web/src/components/Signature.tsx

Lines changed: 16 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,40 @@
11
import classNames from "classnames";
2-
import { ReactElement, useEffect, useRef } from "react";
3-
// import ReactResizeDetector from "react-resize-detector";
4-
import SignaturePad, { Options } from "signature_pad";
2+
import { ReactElement } from "react";
53

4+
import { useSignaturePad } from "src/utils/useSignaturePad";
5+
import Utils from "../utils/Utils";
6+
import { SignatureProps } from "../utils/customTypes";
67
import { Alert } from "./Alert";
78
import { Grid } from "./Grid";
8-
import { Dimensions, SizeContainer } from "./SizeContainer";
9-
import { SignatureContainerProps } from "typings/SignatureProps";
10-
import Utils from "../utils/Utils";
11-
12-
export type penOptions = "fountain" | "ballpoint" | "marker";
13-
14-
export interface SignatureProps extends Dimensions, SignatureContainerProps {
15-
className: string;
16-
alertMessage?: string;
17-
clearSignature: boolean;
18-
showGrid: boolean;
19-
gridCellWidth: number;
20-
gridCellHeight: number;
21-
gridBorderColor: string;
22-
gridBorderWidth: number;
23-
penType: penOptions;
24-
penColor: string;
25-
onSignEndAction?: (imageUrl?: string) => void;
26-
wrapperStyle?: object;
27-
readOnly: boolean;
28-
}
9+
import { SizeContainer } from "./SizeContainer";
2910

3011
export function SignatureComponent(props: SignatureProps): ReactElement {
31-
const { className, alertMessage, wrapperStyle } = props;
32-
const canvasRef = useRef<HTMLCanvasElement | null>(null);
33-
const signaturePadRef = useRef<SignaturePad | null>(null);
34-
35-
const handleSignEnd = (): void => {
36-
const imageDataUrl = signaturePadRef.current?.toDataURL();
12+
const { className, alertMessage, wrapperStyle, imageSource, hasSignatureAttribute, onSignEndAction } = props;
3713

14+
const handleSignEnd = (imageDataUrl?: string): void => {
3815
if (imageDataUrl) {
39-
props.imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl));
16+
imageSource.setValue(Utils.convertUrlToBlob(imageDataUrl));
4017
}
41-
// Trigger microflow to update signature attribute
42-
if (props.onSignEndAction) {
43-
props.onSignEndAction(signaturePadRef.current?.toDataURL());
18+
19+
if (hasSignatureAttribute) {
20+
hasSignatureAttribute.setValue(true);
4421
}
45-
};
4622

47-
const signaturePadOptions = (): Options => {
48-
let options: Options = {};
49-
if (props.penType === "fountain") {
50-
options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 };
51-
} else if (props.penType === "ballpoint") {
52-
options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 };
53-
} else if (props.penType === "marker") {
54-
options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 };
23+
// Trigger microflow to update signature attribute
24+
if (onSignEndAction) {
25+
onSignEndAction(imageDataUrl);
5526
}
56-
return options;
5727
};
5828

59-
useEffect(() => {
60-
if (canvasRef.current) {
61-
signaturePadRef.current = new SignaturePad(canvasRef.current, {
62-
penColor: props.penColor,
63-
...signaturePadOptions()
64-
});
65-
signaturePadRef.current.addEventListener("endStroke", handleSignEnd);
66-
if (props.readOnly) {
67-
signaturePadRef.current?.off();
68-
}
69-
}
70-
}, []);
29+
const { canvasRef, signaturePadRef } = useSignaturePad(props, handleSignEnd);
7130

7231
const onResize = (): void => {
7332
if (canvasRef.current) {
74-
const data = signaturePadRef.current?.toData();
7533
canvasRef.current.width =
7634
canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetWidth : 0;
7735
canvasRef.current.height =
7836
canvasRef.current && canvasRef.current.parentElement ? canvasRef.current.parentElement.offsetHeight : 0;
79-
signaturePadRef.current?.clear();
80-
if (data) {
81-
signaturePadRef.current?.fromData(data);
82-
}
37+
signaturePadRef.current?.redraw();
8338
}
8439
};
8540

packages/pluggableWidgets/signature-web/src/components/SizeContainer.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,7 @@
11
import { createElement, CSSProperties, FC, PropsWithChildren } from "react";
22
import classNames from "classnames";
33
import { useResizeObserver } from "../utils/useResizeObserver";
4-
5-
export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels";
6-
7-
export type WidthUnitType = "percentage" | "pixels";
8-
9-
export interface Dimensions {
10-
widthUnit: WidthUnitType;
11-
width: number;
12-
heightUnit: HeightUnitType;
13-
height: number;
14-
}
4+
import { Dimensions, HeightUnitType, WidthUnitType } from "../utils/customTypes";
155

166
export interface SizeProps extends Dimensions, PropsWithChildren {
177
className: string;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { SignatureContainerProps } from "typings/SignatureProps";
2+
3+
export type HeightUnitType = "percentageOfWidth" | "percentageOfParent" | "pixels";
4+
5+
export type WidthUnitType = "percentage" | "pixels";
6+
7+
export interface Dimensions {
8+
widthUnit: WidthUnitType;
9+
width: number;
10+
heightUnit: HeightUnitType;
11+
height: number;
12+
}
13+
14+
export type penOptions = "fountain" | "ballpoint" | "marker";
15+
16+
export interface SignatureProps extends Dimensions, SignatureContainerProps {
17+
className: string;
18+
alertMessage?: string;
19+
clearSignature: boolean;
20+
showGrid: boolean;
21+
gridCellWidth: number;
22+
gridCellHeight: number;
23+
gridBorderColor: string;
24+
gridBorderWidth: number;
25+
penType: penOptions;
26+
penColor: string;
27+
onSignEndAction?: (imageUrl?: string) => void;
28+
wrapperStyle?: object;
29+
readOnly: boolean;
30+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { RefObject, useCallback, useEffect, useMemo, useRef } from "react";
2+
import SignaturePad, { Options } from "signature_pad";
3+
import { SignatureProps } from "./customTypes";
4+
5+
export function useSignaturePad(
6+
props: Pick<SignatureProps, "readOnly" | "imageSource" | "hasSignatureAttribute" | "penType" | "penColor">,
7+
onSignEnd?: (imageDataURL?: string) => void
8+
): {
9+
signaturePadRef: RefObject<SignaturePad | null>;
10+
canvasRef: RefObject<HTMLCanvasElement | null>;
11+
} {
12+
const { readOnly, imageSource, hasSignatureAttribute, penType, penColor } = props;
13+
const signaturePadRef = useRef<SignaturePad | null>(null);
14+
const canvasRef = useRef<HTMLCanvasElement | null>(null);
15+
const hasSignature = useRef(false);
16+
17+
useEffect(() => {
18+
if (readOnly) {
19+
signaturePadRef.current?.off();
20+
} else {
21+
signaturePadRef.current?.on();
22+
}
23+
}, [readOnly]);
24+
25+
useEffect(() => {
26+
if (imageSource?.status === "available" && imageSource.value?.uri && signaturePadRef.current?.isEmpty()) {
27+
signaturePadRef.current?.fromDataURL(imageSource.value.uri);
28+
}
29+
}, [imageSource]);
30+
31+
useEffect(() => {
32+
if (hasSignatureAttribute?.status === "available") {
33+
if (hasSignatureAttribute?.value !== hasSignature.current) {
34+
if (hasSignature.current === true) {
35+
signaturePadRef.current?.clear();
36+
}
37+
hasSignature.current = !!hasSignatureAttribute?.value;
38+
}
39+
}
40+
}, [hasSignatureAttribute?.status, hasSignatureAttribute?.value]);
41+
42+
const signaturePadOptions: Options = useMemo(() => {
43+
let options: Options = {};
44+
if (penType === "fountain") {
45+
options = { minWidth: 0.6, maxWidth: 2.6, velocityFilterWeight: 0.6 };
46+
} else if (penType === "ballpoint") {
47+
options = { minWidth: 1.4, maxWidth: 1.5, velocityFilterWeight: 1.5 };
48+
} else if (penType === "marker") {
49+
options = { minWidth: 2, maxWidth: 4, velocityFilterWeight: 0.9 };
50+
}
51+
return options;
52+
}, [penType]);
53+
54+
const handleSignEnd = useCallback(() => {
55+
const imageDataUrl = signaturePadRef.current?.toDataURL();
56+
57+
if (imageDataUrl && onSignEnd) {
58+
onSignEnd(imageDataUrl);
59+
}
60+
}, [onSignEnd]);
61+
62+
useEffect(() => {
63+
if (canvasRef.current) {
64+
signaturePadRef.current = new SignaturePad(canvasRef.current, {
65+
penColor,
66+
...signaturePadOptions
67+
});
68+
signaturePadRef.current.addEventListener("endStroke", handleSignEnd);
69+
if (readOnly) {
70+
signaturePadRef.current?.off();
71+
}
72+
}
73+
}, [handleSignEnd, penColor, readOnly, signaturePadOptions]);
74+
75+
return { signaturePadRef, canvasRef };
76+
}

0 commit comments

Comments
 (0)