mirror of
https://github.com/documenso/documenso.git
synced 2025-11-19 19:21:39 +10:00
Merge branch 'main' into feat/document-table-filters
This commit is contained in:
75
packages/lib/client-only/hooks/use-element-bounds.ts
Normal file
75
packages/lib/client-only/hooks/use-element-bounds.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { getBoundingClientRect } from '@documenso/lib/client-only/get-bounding-client-rect';
|
||||
|
||||
export const useElementBounds = (elementOrSelector: HTMLElement | string, withScroll = false) => {
|
||||
const [bounds, setBounds] = useState({
|
||||
top: 0,
|
||||
left: 0,
|
||||
height: 0,
|
||||
width: 0,
|
||||
});
|
||||
|
||||
const calculateBounds = () => {
|
||||
const $el =
|
||||
typeof elementOrSelector === 'string'
|
||||
? document.querySelector<HTMLElement>(elementOrSelector)
|
||||
: elementOrSelector;
|
||||
|
||||
if (!$el) {
|
||||
throw new Error('Element not found');
|
||||
}
|
||||
|
||||
if (withScroll) {
|
||||
return getBoundingClientRect($el);
|
||||
}
|
||||
|
||||
const { top, left, width, height } = $el.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
top,
|
||||
left,
|
||||
width,
|
||||
height,
|
||||
};
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setBounds(calculateBounds());
|
||||
}, [calculateBounds]);
|
||||
|
||||
useEffect(() => {
|
||||
const onResize = () => {
|
||||
setBounds(calculateBounds());
|
||||
};
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
};
|
||||
}, [calculateBounds]);
|
||||
|
||||
useEffect(() => {
|
||||
const $el =
|
||||
typeof elementOrSelector === 'string'
|
||||
? document.querySelector<HTMLElement>(elementOrSelector)
|
||||
: elementOrSelector;
|
||||
|
||||
if (!$el) {
|
||||
return;
|
||||
}
|
||||
|
||||
const observer = new ResizeObserver(() => {
|
||||
setBounds(calculateBounds());
|
||||
});
|
||||
|
||||
observer.observe($el);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [calculateBounds]);
|
||||
|
||||
return bounds;
|
||||
};
|
||||
@ -128,7 +128,7 @@ export const sealDocument = async ({
|
||||
|
||||
// Normalize and flatten layers that could cause issues with the signature
|
||||
normalizeSignatureAppearances(doc);
|
||||
flattenForm(doc);
|
||||
await flattenForm(doc);
|
||||
flattenAnnotations(doc);
|
||||
|
||||
// Add rejection stamp if the document is rejected
|
||||
@ -153,7 +153,7 @@ export const sealDocument = async ({
|
||||
}
|
||||
|
||||
// Re-flatten post-insertion to handle fields that create arcoFields
|
||||
flattenForm(doc);
|
||||
await flattenForm(doc);
|
||||
|
||||
const pdfBytes = await doc.save();
|
||||
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import fontkit from '@pdf-lib/fontkit';
|
||||
import type { PDFField, PDFWidgetAnnotation } from 'pdf-lib';
|
||||
import {
|
||||
PDFCheckBox,
|
||||
@ -13,6 +14,8 @@ import {
|
||||
translate,
|
||||
} from 'pdf-lib';
|
||||
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
|
||||
export const removeOptionalContentGroups = (document: PDFDocument) => {
|
||||
const context = document.context;
|
||||
const catalog = context.lookup(context.trailerInfo.Root);
|
||||
@ -21,12 +24,20 @@ export const removeOptionalContentGroups = (document: PDFDocument) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const flattenForm = (document: PDFDocument) => {
|
||||
export const flattenForm = async (document: PDFDocument) => {
|
||||
removeOptionalContentGroups(document);
|
||||
|
||||
const form = document.getForm();
|
||||
|
||||
form.updateFieldAppearances();
|
||||
const fontNoto = await fetch(`${NEXT_PUBLIC_WEBAPP_URL()}/fonts/noto-sans.ttf`).then(
|
||||
async (res) => res.arrayBuffer(),
|
||||
);
|
||||
|
||||
document.registerFontkit(fontkit);
|
||||
|
||||
const font = await document.embedFont(fontNoto);
|
||||
|
||||
form.updateFieldAppearances(font);
|
||||
|
||||
for (const field of form.getFields()) {
|
||||
for (const widget of field.acroField.getWidgets()) {
|
||||
|
||||
@ -1,8 +1,15 @@
|
||||
// https://github.com/Hopding/pdf-lib/issues/20#issuecomment-412852821
|
||||
import fontkit from '@pdf-lib/fontkit';
|
||||
import { FieldType } from '@prisma/client';
|
||||
import type { PDFDocument, PDFFont } from 'pdf-lib';
|
||||
import { RotationTypes, TextAlignment, degrees, radiansToDegrees, rgb } from 'pdf-lib';
|
||||
import type { PDFDocument, PDFFont, PDFTextField } from 'pdf-lib';
|
||||
import {
|
||||
RotationTypes,
|
||||
TextAlignment,
|
||||
degrees,
|
||||
radiansToDegrees,
|
||||
rgb,
|
||||
setFontAndSize,
|
||||
} from 'pdf-lib';
|
||||
import { P, match } from 'ts-pattern';
|
||||
|
||||
import {
|
||||
@ -442,6 +449,10 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
|
||||
adjustedFieldY = adjustedPosition.yPos;
|
||||
}
|
||||
|
||||
// Set properties for the text field
|
||||
setTextFieldFontSize(textField, font, fontSize);
|
||||
textField.setText(textToInsert);
|
||||
|
||||
// Set the position and size of the text field
|
||||
textField.addToPage(page, {
|
||||
x: adjustedFieldX,
|
||||
@ -450,6 +461,8 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
|
||||
height: adjustedFieldHeight,
|
||||
rotate: degrees(pageRotationInDegrees),
|
||||
|
||||
font,
|
||||
|
||||
// Hide borders.
|
||||
borderWidth: 0,
|
||||
borderColor: undefined,
|
||||
@ -457,10 +470,6 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
|
||||
|
||||
...(isDebugMode ? { borderWidth: 1, borderColor: rgb(0, 0, 1) } : {}),
|
||||
});
|
||||
|
||||
// Set properties for the text field
|
||||
textField.setFontSize(fontSize);
|
||||
textField.setText(textToInsert);
|
||||
});
|
||||
|
||||
return pdf;
|
||||
@ -629,3 +638,21 @@ function breakLongString(text: string, maxWidth: number, font: PDFFont, fontSize
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
const setTextFieldFontSize = (textField: PDFTextField, font: PDFFont, fontSize: number) => {
|
||||
textField.defaultUpdateAppearances(font);
|
||||
textField.updateAppearances(font);
|
||||
|
||||
try {
|
||||
textField.setFontSize(fontSize);
|
||||
} catch (err) {
|
||||
let da = textField.acroField.getDefaultAppearance() ?? '';
|
||||
|
||||
da += `\n ${setFontAndSize(font.name, fontSize)}`;
|
||||
|
||||
textField.acroField.setDefaultAppearance(da);
|
||||
}
|
||||
|
||||
textField.defaultUpdateAppearances(font);
|
||||
textField.updateAppearances(font);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user