Skip to content

Commit 27b0b42

Browse files
v2.23.1
Enable widget placement on click in desktop view Disable signature types not working Change icon of agreement sign checkbox Update dependencies
1 parent 8788afa commit 27b0b42

File tree

11 files changed

+728
-77
lines changed

11 files changed

+728
-77
lines changed

apps/OpenSign/package-lock.json

Lines changed: 603 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/OpenSign/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
"private": true,
55
"dependencies": {
66
"@formkit/auto-animate": "^0.8.2",
7+
"@imgly/background-removal": "^1.6.0",
78
"@lottiefiles/dotlottie-react": "^0.13.5",
89
"@pdf-lib/fontkit": "^1.1.1",
910
"@radix-ui/themes": "^3.2.1",
1011
"@reduxjs/toolkit": "^2.8.2",
11-
"@imgly/background-removal": "^1.6.0",
1212
"axios": "^1.9.0",
1313
"date-fns-tz": "^3.2.0",
1414
"file-saver": "^2.0.5",
@@ -19,8 +19,8 @@
1919
"jwt-decode": "^4.0.0",
2020
"moment": "^2.30.1",
2121
"parse": "^6.1.1",
22-
"pkijs": "^3.0.8",
2322
"pdf-lib": "^1.17.1",
23+
"pkijs": "^3.0.8",
2424
"print-js": "^1.6.0",
2525
"prismjs": "^1.30.0",
2626
"radix-ui": "^1.4.2",

apps/OpenSign/src/components/pdf/AgreementSign.jsx

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,32 @@ function AgreementSign(props) {
1212
<div className="op-modal op-modal-open absolute z-[448]">
1313
<div className="w-[95%] md:w-[60%] lg:w-[40%] op-modal-box overflow-y-auto hide-scrollbar text-sm p-4">
1414
<div className="flex flex-row items-center">
15-
<input
16-
data-tut="IsAgree"
17-
className="mr-3 op-checkbox op-checkbox-m"
18-
type="checkbox"
19-
value={isChecked}
20-
onChange={(e) => {
21-
setIsChecked(e.target.checked);
22-
if (e.target.checked) {
23-
props.setIsAgreeTour(false);
24-
}
25-
props.showFirstWidget();
26-
}}
27-
/>
15+
<label className="inline-flex justify-center items-center cursor-pointer mb-0">
16+
{/* 1) This div becomes the “fake” checkbox */}
17+
<div
18+
data-tut="IsAgree"
19+
className={`w-6 h-6 border-2 mr-3 rounded-full flex text-center items-center justify-center ${isChecked ? "op-border-primary" : "border-red-500"}`}
20+
>
21+
{isChecked ? (
22+
<span className="op-text-primary text-sm font-bold"></span>
23+
) : (
24+
<span className="text-red-500 text-sm font-bold">X</span>
25+
)}
26+
</div>
27+
{/* 2) Visually hide the native checkbox but keep it in the DOM */}
28+
<input
29+
className="sr-only"
30+
type="checkbox"
31+
checked={isChecked}
32+
onChange={(e) => {
33+
setIsChecked(e.target.checked);
34+
if (e.target.checked) {
35+
props.setIsAgreeTour(false);
36+
}
37+
props.showFirstWidget();
38+
}}
39+
/>
40+
</label>
2841
<div className="text-[11px] md:text-base">
2942
<span>{t("agree-p1")}</span>
3043
<span

apps/OpenSign/src/components/pdf/WidgetComponent.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ function WidgetComponent(props) {
241241
handleDivClick={props.handleDivClick}
242242
handleMouseLeave={props.handleMouseLeave}
243243
signRef={signRef}
244+
addPositionOfSignature={props.addPositionOfSignature}
244245
/>
245246
</div>
246247
</div>

apps/OpenSign/src/components/pdf/WidgetsValueModal.jsx

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
onSaveSign,
1515
radioButtonWidget,
1616
selectCheckbox,
17-
signatureTypes,
1817
textInputWidget,
1918
textWidget,
2019
years
@@ -85,7 +84,8 @@ function WidgetsValueModal(props) {
8584
setXyPosition,
8685
isSave,
8786
setUniqueId,
88-
tempSignerId
87+
tempSignerId,
88+
signatureTypes
8989
} = props;
9090
const [penColor, setPenColor] = useState("blue");
9191
const [isOptional, setIsOptional] = useState(true);
@@ -400,7 +400,7 @@ function WidgetsValueModal(props) {
400400

401401
if (getIndex !== -1) {
402402
setIsSignTypes(true);
403-
const tab = signatureTypes[getIndex].name;
403+
const tab = signatureTypes?.[getIndex].name;
404404
if (tab === "draw") {
405405
setIsTab("draw");
406406
setSignatureType("draw");
@@ -427,7 +427,7 @@ function WidgetsValueModal(props) {
427427
}
428428
}
429429
function isTabEnabled(tabName) {
430-
const isEnabled = signatureTypes.find((x) => x.name === tabName)?.enabled;
430+
const isEnabled = signatureTypes?.find((x) => x.name === tabName)?.enabled;
431431
return isEnabled;
432432
}
433433

@@ -683,51 +683,64 @@ function WidgetsValueModal(props) {
683683
}
684684
// eslint-disable-next-line react-hooks/exhaustive-deps
685685
}, [isTab]);
686-
//function for convert input text value in image
686+
// function for convert input text value in image
687687
const convertToImg = async (fontStyle, text, color) => {
688-
//get text content to convert in image
689-
const textContent = text;
690-
const fontfamily = fontStyle
691-
? fontStyle
692-
: fontSelect
693-
? fontSelect
694-
: "Fasthand";
695-
const fontSizeValue = "40px";
696-
//creating span for getting text content width
688+
// 1) Read the max widget dimensions:
689+
const maxWidth = currWidgetsDetails.Width; // e.g. 150 px
690+
const maxHeight = currWidgetsDetails.Height; // e.g. 40 px
691+
692+
// 2) Pick a “baseline” font size for measurement:
693+
const baselineFontSizePx = 40;
694+
const chosenFontFamily = fontStyle || fontSelect || "Fasthand";
695+
const fillColor = color || penColor;
696+
697+
// 3) Create a temporary <span> (hidden) to measure the text at 40px:
697698
const span = document.createElement("span");
698-
span.textContent = textContent;
699-
span.style.font = `${fontSizeValue} ${fontfamily}`; // here put your text size and font family
700-
span.style.color = color ? color : penColor;
701-
span.style.display = "hidden";
702-
document.body.appendChild(span); // Replace 'container' with the ID of the container element
699+
span.textContent = text;
700+
span.style.font = `${baselineFontSizePx}px ${chosenFontFamily}`;
701+
span.style.visibility = "hidden"; // keep it in the DOM so offsetWidth/Height works
702+
span.style.whiteSpace = "nowrap"; // so we measure a single line
703+
document.body.appendChild(span);
704+
705+
// Measured size at 40px:
706+
const measuredWidth = span.offsetWidth;
707+
const measuredHeight = span.offsetHeight;
708+
document.body.removeChild(span);
703709

704-
//create canvas to render text in canvas and convert in image
705-
const canvasElement = document.createElement("canvas");
706-
// Draw the text content on the canvas
707-
const ctx = canvasElement.getContext("2d");
710+
// 4) Compute uniform scale so that 40px‐sized text fits inside (maxWidth × maxHeight):
711+
const scaleX = maxWidth / measuredWidth;
712+
const scaleY = maxHeight / measuredHeight;
713+
const scale = Math.min(scaleX, scaleY, 1); // never scale up beyond 1
714+
715+
// 5) Final text size in **CSS px**:
716+
const finalFontSizePx = baselineFontSizePx * scale;
717+
718+
// 6) Create a <canvas> that is ALWAYS maxWidth × maxHeight in **CSS px**,
719+
// but use devicePixelRatio for sharpness.
708720
const pixelRatio = window.devicePixelRatio || 1;
709-
const addExtraWidth = currWidgetsDetails?.type === "initials" ? 10 : 50;
710-
const width = span.offsetWidth + addExtraWidth;
711-
const height = span.offsetHeight;
712-
setTextWidth(width);
713-
setTextHeight(height);
714-
const font = span.style["font"];
715-
// Set the canvas dimensions to match the span
716-
canvasElement.width = width * pixelRatio;
717-
canvasElement.height = height * pixelRatio;
721+
const canvas = document.createElement("canvas");
722+
723+
// ★ Instead of using `finalTextWidth/Height`, force it to be the max box:
724+
canvas.width = Math.ceil(maxWidth * pixelRatio);
725+
canvas.height = Math.ceil(maxHeight * pixelRatio);
718726

719-
// You can customize text styles if needed
720-
ctx.font = font;
721-
ctx.fillStyle = color ? color : penColor; // Set the text color
727+
const ctx = canvas.getContext("2d");
728+
ctx.scale(pixelRatio, pixelRatio);
729+
730+
// 7) Draw the text **centered** inside the full maxWidth×maxHeight box:
731+
ctx.font = `${finalFontSizePx}px ${chosenFontFamily}`;
732+
ctx.fillStyle = fillColor;
722733
ctx.textAlign = "center";
723734
ctx.textBaseline = "middle";
724-
ctx.scale(pixelRatio, pixelRatio);
725-
// Draw the content of the span onto the canvas
726-
ctx.fillText(span.textContent, width / 2, height / 2); // Adjust the x,y-coordinate as needed
727-
//remove span tag
728-
document.body.removeChild(span);
729-
// Convert the canvas to image data
730-
const dataUrl = canvasElement.toDataURL("image/png");
735+
736+
// ★ Center = (maxWidth/2, maxHeight/2):
737+
const centerX = maxWidth / 2;
738+
const centerY = maxHeight / 2;
739+
740+
ctx.fillText(text, centerX, centerY);
741+
742+
// 8) Export to a PNG data-URL:
743+
const dataUrl = canvas.toDataURL("image/png");
731744
setSignature(dataUrl);
732745
};
733746
const PenColorComponent = (props) => {

apps/OpenSign/src/constant/Utils.jsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -683,10 +683,14 @@ export const signPdfFun = async (
683683
};
684684

685685
export const randomId = () => {
686-
const randomBytes = crypto.getRandomValues(new Uint16Array(1));
687-
const randomValue = randomBytes[0];
688-
const randomDigit = 1000 + (randomValue % 9000);
689-
return randomDigit;
686+
// 1. Grab a cryptographically-secure 32-bit random value
687+
const randomBytes = crypto.getRandomValues(new Uint32Array(1));
688+
const raw = randomBytes[0]; // 0 … 4 294 967 295
689+
690+
// 2. Collapse into a 90 000 000-wide band (0…89 999 999), then shift to 10 000 000…99 999 999
691+
const eightDigit = 10_000_000 + (raw % 90_000_000);
692+
693+
return eightDigit;
690694
};
691695

692696
export const createDocument = async (
@@ -1552,7 +1556,7 @@ export const multiSignEmbed = async (
15521556
let hasError = false;
15531557
for (let item of widgets) {
15541558
//pdfOriginalWH contained all pdf's pages width and height
1555-
//'getSize' is used to get particular pdf's page width and height
1559+
//'getSize' is used to get particular pdf's page width and height
15561560
const getSize = pdfOriginalWH.find(
15571561
(page) => page?.pageNumber === item?.pageNumber
15581562
);

apps/OpenSign/src/pages/Form.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,7 @@ const Forms = (props) => {
455455
setBcc([]);
456456
setFolder({ ObjectId: "", Name: "" });
457457
const notifySign =
458-
extUserData?.NotifyOnSignatures
458+
extUserData?.NotifyOnSignatures !== undefined
459459
? extUserData?.NotifyOnSignatures
460460
: true;
461461
setFormData({
@@ -534,7 +534,7 @@ const Forms = (props) => {
534534
setBcc([]);
535535
setFolder({ ObjectId: "", Name: "" });
536536
const notifySign =
537-
extUserData?.NotifyOnSignatures
537+
extUserData?.NotifyOnSignatures !== undefined
538538
? extUserData?.NotifyOnSignatures
539539
: true;
540540
let obj = {

apps/OpenSign/src/pages/PdfRequestFiles.jsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ function PdfRequestFiles(
821821
await embedDocId(pdfOriginalWH, pdfDoc, docId);
822822
}
823823
}
824-
//embed all widgets in document
824+
//embed all widgets in document
825825
const pdfBytes = await multiSignEmbed(
826826
pdfOriginalWH,
827827
widgets,
@@ -1564,11 +1564,15 @@ function PdfRequestFiles(
15641564
const widgetValue = widgetDataValue(dragTypeValue, parseUser);
15651565
//adding and updating drop position in array when user drop signature button in div
15661566
if (item === "onclick") {
1567+
// `getBoundingClientRect()` is used to get accurate measurement width, height of the Pdf div
1568+
const divWidth = divRef.current.getBoundingClientRect().width;
15671569
const divHeight = divRef.current.getBoundingClientRect().height;
1568-
// `getBoundingClientRect()` is used to get accurate measurement height of the div
1570+
// Compute the pixel‐space center within the PDF viewport:
1571+
const centerX_Pixels = divWidth / 2 - widgetWidth / 2;
1572+
const xPosition_Final = centerX_Pixels / (containerScale * scale);
15691573
dropObj = {
15701574
//onclick put placeholder center on pdf
1571-
xPosition: widgetWidth / 4 + containerWH.width / 2,
1575+
xPosition: xPosition_Final,
15721576
yPosition: widgetHeight + divHeight / 2,
15731577
isStamp:
15741578
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
@@ -2259,6 +2263,7 @@ function PdfRequestFiles(
22592263
index={pageNumber}
22602264
setUniqueId={setUniqueId}
22612265
tempSignerId={tempSignerId}
2266+
signatureTypes={signatureType}
22622267
/>
22632268
)}
22642269
<DownloadPdfZip

apps/OpenSign/src/pages/PlaceHolderSign.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,11 +524,15 @@ function PlaceHolderSign() {
524524
defaultWidthHeight(dragTypeValue).height * containerScale;
525525
//adding and updating drop position in array when user drop signature button in div
526526
if (item === "onclick") {
527+
// `getBoundingClientRect()` is used to get accurate measurement width, height of the Pdf div
528+
const divWidth = divRef.current.getBoundingClientRect().width;
527529
const divHeight = divRef.current.getBoundingClientRect().height;
528-
// `getBoundingClientRect()` is used to get accurate measurement height of the div
530+
// Compute the pixel‐space center within the PDF viewport:
531+
const centerX_Pixels = divWidth / 2 - widgetWidth / 2;
532+
const xPosition_Final = centerX_Pixels / (containerScale * scale);
529533
dropObj = {
530534
//onclick put placeholder center on pdf
531-
xPosition: widgetWidth / 4 + containerWH.width / 2,
535+
xPosition: xPosition_Final,
532536
yPosition: widgetHeight + divHeight / 2,
533537
isStamp:
534538
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
@@ -2589,6 +2593,7 @@ function PlaceHolderSign() {
25892593
isSave={true}
25902594
tempSignerId={tempSignerId}
25912595
setUniqueId={setUniqueId}
2596+
signatureTypes={signatureType}
25922597
/>
25932598
)}
25942599
<ModalUi

apps/OpenSign/src/pages/SignyourselfPdf.jsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ import {
3737
generatePdfName,
3838
handleRemoveWidgets,
3939
addWidgetSelfsignOptions,
40-
getOriginalWH
40+
getOriginalWH,
41+
signatureTypes
4142
} from "../constant/Utils";
4243
import { useParams } from "react-router";
4344
import Tour from "../primitives/Tour";
@@ -365,15 +366,19 @@ function SignYourSelf() {
365366
);
366367
//adding and updating drop position in array when user drop signature button in div
367368
if (item === "onclick") {
368-
// `getBoundingClientRect()` is used to get accurate measurement height of the div
369+
// `getBoundingClientRect()` is used to get accurate measurement width, height of the Pdf div
369370
const divHeight = divRef.current.getBoundingClientRect().height;
371+
const divWidth = divRef.current.getBoundingClientRect().width;
370372
const getWidth = widgetTypeExist
371373
? calculateInitialWidthHeight(widgetValue).getWidth
372374
: defaultWidthHeight(dragTypeValue).width;
373375
const getHeight = defaultWidthHeight(dragTypeValue).height;
374376

377+
// Compute the pixel‐space center within the PDF viewport:
378+
const centerX_Pixels = divWidth / 2 - getWidth / 2;
379+
const xPosition_Final = centerX_Pixels / (containerScale * scale);
375380
dropObj = {
376-
xPosition: getWidth / 2 + containerWH.width / 2,
381+
xPosition: xPosition_Final,
377382
yPosition: getHeight + divHeight / 2,
378383
isStamp:
379384
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
@@ -1330,6 +1335,7 @@ function SignYourSelf() {
13301335
currWidgetsDetails={currWidgetsDetails}
13311336
index={index}
13321337
isSave={true}
1338+
signatureTypes={signatureTypes}
13331339
/>
13341340
)}
13351341
<RotateAlert

0 commit comments

Comments
 (0)