feat: add transparent background option for form fields

This commit is contained in:
alam00000
2026-03-15 19:52:35 +05:30
parent dae6f1b15f
commit 31f43b557f
2 changed files with 218 additions and 47 deletions

View File

@@ -454,6 +454,7 @@ function createField(type: FormField['type'], x: number, y: number): void {
multiline: type === 'text' ? false : undefined, multiline: type === 'text' ? false : undefined,
borderColor: '#000000', borderColor: '#000000',
hideBorder: false, hideBorder: false,
transparentBackground: false,
barcodeFormat: type === 'barcode' ? 'qrcode' : undefined, barcodeFormat: type === 'barcode' ? 'qrcode' : undefined,
barcodeValue: type === 'barcode' ? 'https://example.com' : undefined, barcodeValue: type === 'barcode' ? 'https://example.com' : undefined,
}; };
@@ -463,6 +464,105 @@ function createField(type: FormField['type'], x: number, y: number): void {
updateFieldCount(); updateFieldCount();
} }
function hasTransparentBackground(field: FormField): boolean {
return Boolean(field.transparentBackground);
}
function applyFieldContainerState(
container: HTMLElement,
field: FormField,
selected: boolean
): void {
container.classList.remove(
'border-indigo-200',
'group-hover:border-dashed',
'group-hover:border-indigo-300',
'border-dashed',
'border-indigo-500',
'bg-indigo-50',
'bg-indigo-50/30',
'bg-transparent'
);
if (selected) {
container.classList.add('border-dashed', 'border-indigo-500');
container.classList.add(
hasTransparentBackground(field) ? 'bg-transparent' : 'bg-indigo-50'
);
return;
}
container.classList.add(
'border-indigo-200',
'group-hover:border-dashed',
'group-hover:border-indigo-300'
);
container.classList.add(
hasTransparentBackground(field) ? 'bg-transparent' : 'bg-indigo-50/30'
);
}
function getPreviewBackgroundColor(
field: FormField,
fallbackColor: string
): string {
return hasTransparentBackground(field) ? 'transparent' : fallbackColor;
}
function getPdfBackgroundOptions(
field: FormField,
red: number,
green: number,
blue: number
): { backgroundColor?: ReturnType<typeof rgb> } {
if (hasTransparentBackground(field)) {
return {};
}
return {
backgroundColor: rgb(red, green, blue),
};
}
function clearTransparentWidgetBackground(
field: FormField,
widgetDict: PDFDict,
pdfDoc: PDFDocument
): void {
if (!hasTransparentBackground(field)) {
return;
}
widgetDict.delete(PDFName.of('BG'));
const mk = widgetDict.get(PDFName.of('MK'));
const mkDict = mk ? pdfDoc.context.lookupMaybe(mk, PDFDict) : undefined;
mkDict?.delete(PDFName.of('BG'));
}
function clearTransparentFieldWidgetBackgrounds(
field: FormField,
widgets: Array<{ dict: PDFDict }>,
pdfDoc: PDFDocument
): void {
if (!hasTransparentBackground(field)) {
return;
}
widgets.forEach((widget) => {
clearTransparentWidgetBackground(field, widget.dict, pdfDoc);
});
}
function rerenderSelectedField(field: FormField): void {
const shouldReselect = selectedField?.id === field.id;
renderField(field);
if (shouldReselect) {
selectField(field);
}
}
// Render field on canvas // Render field on canvas
function renderField(field: FormField): void { function renderField(field: FormField): void {
const existingField = document.getElementById(field.id); const existingField = document.getElementById(field.id);
@@ -496,9 +596,10 @@ function renderField(field: FormField): void {
// Create input container - light border by default, dashed on hover // Create input container - light border by default, dashed on hover
const fieldContainer = document.createElement('div'); const fieldContainer = document.createElement('div');
fieldContainer.className = fieldContainer.className =
'field-container relative border-2 border-indigo-200 group-hover:border-dashed group-hover:border-indigo-300 bg-indigo-50/30 rounded transition-all'; 'field-container relative border-2 rounded transition-all';
fieldContainer.style.width = '100%'; fieldContainer.style.width = '100%';
fieldContainer.style.height = field.height + 'px'; fieldContainer.style.height = field.height + 'px';
applyFieldContainerState(fieldContainer, field, false);
// Create content based on type // Create content based on type
const contentEl = document.createElement('div'); const contentEl = document.createElement('div');
@@ -544,7 +645,10 @@ function renderField(field: FormField): void {
} else if (field.type === 'dropdown') { } else if (field.type === 'dropdown') {
contentEl.className = contentEl.className =
'w-full h-full flex items-center px-2 text-sm text-black'; 'w-full h-full flex items-center px-2 text-sm text-black';
contentEl.style.backgroundColor = '#e6f0ff'; // Light blue background like Firefox contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#e6f0ff'
);
// Show selected option or first option or placeholder // Show selected option or first option or placeholder
let displayText = 'Select...'; let displayText = 'Select...';
@@ -566,7 +670,11 @@ function renderField(field: FormField): void {
fieldContainer.appendChild(arrow); fieldContainer.appendChild(arrow);
} else if (field.type === 'optionlist') { } else if (field.type === 'optionlist') {
contentEl.className = contentEl.className =
'w-full h-full flex flex-col text-sm bg-white overflow-hidden border border-gray-300'; 'w-full h-full flex flex-col text-sm overflow-hidden border border-gray-300';
contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#ffffff'
);
// Render options as a list // Render options as a list
if (field.options && field.options.length > 0) { if (field.options && field.options.length > 0) {
field.options.forEach((opt, index) => { field.options.forEach((opt, index) => {
@@ -595,28 +703,47 @@ function renderField(field: FormField): void {
} }
} else if (field.type === 'button') { } else if (field.type === 'button') {
contentEl.className = contentEl.className =
'field-content w-full h-full flex items-center justify-center bg-gray-200 text-sm font-semibold'; 'field-content w-full h-full flex items-center justify-center text-sm font-semibold';
contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#e5e7eb'
);
contentEl.style.color = field.textColor || '#000000'; contentEl.style.color = field.textColor || '#000000';
contentEl.textContent = field.label || 'Button'; contentEl.textContent = field.label || 'Button';
} else if (field.type === 'signature') { } else if (field.type === 'signature') {
contentEl.className = contentEl.className =
'w-full h-full flex items-center justify-center bg-gray-50 text-gray-400'; 'w-full h-full flex items-center justify-center text-gray-400';
contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#f9fafb'
);
contentEl.innerHTML = contentEl.innerHTML =
'<div class="flex flex-col items-center"><i data-lucide="pen-tool" class="w-6 h-6 mb-1"></i><span class="text-[10px]">Sign Here</span></div>'; '<div class="flex flex-col items-center"><i data-lucide="pen-tool" class="w-6 h-6 mb-1"></i><span class="text-[10px]">Sign Here</span></div>';
setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0); setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0);
} else if (field.type === 'date') { } else if (field.type === 'date') {
contentEl.className = contentEl.className =
'w-full h-full flex items-center justify-center bg-white text-gray-600 border border-gray-300'; 'w-full h-full flex items-center justify-center text-gray-600 border border-gray-300';
contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#ffffff'
);
contentEl.innerHTML = `<div class="flex items-center gap-2 px-2"><i data-lucide="calendar" class="w-4 h-4"></i><span class="text-sm date-format-text">${field.dateFormat || 'mm/dd/yyyy'}</span></div>`; contentEl.innerHTML = `<div class="flex items-center gap-2 px-2"><i data-lucide="calendar" class="w-4 h-4"></i><span class="text-sm date-format-text">${field.dateFormat || 'mm/dd/yyyy'}</span></div>`;
setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0); setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0);
} else if (field.type === 'image') { } else if (field.type === 'image') {
contentEl.className = contentEl.className =
'w-full h-full flex items-center justify-center bg-gray-100 text-gray-500 border border-gray-300'; 'w-full h-full flex items-center justify-center text-gray-500 border border-gray-300';
contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#f3f4f6'
);
contentEl.innerHTML = `<div class="flex flex-col items-center text-center p-1"><i data-lucide="image" class="w-6 h-6 mb-1"></i><span class="text-[10px] leading-tight">${field.label || 'Click to Upload Image'}</span></div>`; contentEl.innerHTML = `<div class="flex flex-col items-center text-center p-1"><i data-lucide="image" class="w-6 h-6 mb-1"></i><span class="text-[10px] leading-tight">${field.label || 'Click to Upload Image'}</span></div>`;
setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0); setTimeout(() => (window as LucideWindow).lucide?.createIcons(), 0);
} else if (field.type === 'barcode') { } else if (field.type === 'barcode') {
contentEl.className = contentEl.className = 'w-full h-full flex items-center justify-center';
'w-full h-full flex items-center justify-center bg-white'; contentEl.style.backgroundColor = getPreviewBackgroundColor(
field,
'#ffffff'
);
if (field.barcodeValue) { if (field.barcodeValue) {
try { try {
const offscreen = document.createElement('canvas'); const offscreen = document.createElement('canvas');
@@ -933,17 +1060,7 @@ function selectField(field: FormField): void {
const handles = fieldWrapper.querySelectorAll('.resize-handle'); const handles = fieldWrapper.querySelectorAll('.resize-handle');
if (container) { if (container) {
// Remove hover classes and add selected classes applyFieldContainerState(container, field, true);
container.classList.remove(
'border-indigo-200',
'group-hover:border-dashed',
'group-hover:border-indigo-300'
);
container.classList.add(
'border-dashed',
'border-indigo-500',
'bg-indigo-50'
);
} }
if (label) { if (label) {
@@ -970,17 +1087,7 @@ function deselectAll(): void {
const handles = fieldWrapper.querySelectorAll('.resize-handle'); const handles = fieldWrapper.querySelectorAll('.resize-handle');
if (container) { if (container) {
// Revert to default/hover state applyFieldContainerState(container, selectedField, false);
container.classList.remove(
'border-dashed',
'border-indigo-500',
'bg-indigo-50'
);
container.classList.add(
'border-indigo-200',
'group-hover:border-dashed',
'group-hover:border-indigo-300'
);
} }
if (label) { if (label) {
@@ -1285,6 +1392,10 @@ function showProperties(field: FormField): void {
<input type="checkbox" id="propHideBorder" ${field.hideBorder ? 'checked' : ''} class="mr-2"> <input type="checkbox" id="propHideBorder" ${field.hideBorder ? 'checked' : ''} class="mr-2">
<label for="propHideBorder" class="text-xs font-semibold text-gray-300">Hide Border</label> <label for="propHideBorder" class="text-xs font-semibold text-gray-300">Hide Border</label>
</div> </div>
<div class="flex items-center">
<input type="checkbox" id="propTransparentBackground" ${field.transparentBackground ? 'checked' : ''} class="mr-2">
<label for="propTransparentBackground" class="text-xs font-semibold text-gray-300">Transparent Background</label>
</div>
<button id="deleteBtn" class="w-full bg-red-600 text-white py-2 rounded hover:bg-red-700 transition text-sm font-semibold"> <button id="deleteBtn" class="w-full bg-red-600 text-white py-2 rounded hover:bg-red-700 transition text-sm font-semibold">
Delete Field Delete Field
</button> </button>
@@ -1400,6 +1511,9 @@ function showProperties(field: FormField): void {
const propHideBorder = document.getElementById( const propHideBorder = document.getElementById(
'propHideBorder' 'propHideBorder'
) as HTMLInputElement; ) as HTMLInputElement;
const propTransparentBackground = document.getElementById(
'propTransparentBackground'
) as HTMLInputElement;
propBorderColor.addEventListener('input', (e) => { propBorderColor.addEventListener('input', (e) => {
field.borderColor = (e.target as HTMLInputElement).value; field.borderColor = (e.target as HTMLInputElement).value;
@@ -1407,6 +1521,12 @@ function showProperties(field: FormField): void {
propHideBorder.addEventListener('change', (e) => { propHideBorder.addEventListener('change', (e) => {
field.hideBorder = (e.target as HTMLInputElement).checked; field.hideBorder = (e.target as HTMLInputElement).checked;
rerenderSelectedField(field);
});
propTransparentBackground.addEventListener('change', (e) => {
field.transparentBackground = (e.target as HTMLInputElement).checked;
rerenderSelectedField(field);
}); });
deleteBtn.addEventListener('click', () => { deleteBtn.addEventListener('click', () => {
@@ -2136,7 +2256,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), ...getPdfBackgroundOptions(field, 1, 1, 1),
textColor: rgb(rgbColor.r, rgbColor.g, rgbColor.b), textColor: rgb(rgbColor.r, rgbColor.g, rgbColor.b),
}); });
@@ -2175,6 +2295,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
textField.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'checkbox') { } else if (field.type === 'checkbox') {
const checkBox = form.createCheckBox(field.name); const checkBox = form.createCheckBox(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000'); const borderRgb = hexToRgb(field.borderColor || '#000000');
@@ -2185,7 +2310,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), ...getPdfBackgroundOptions(field, 1, 1, 1),
}); });
if (field.checked) checkBox.check(); if (field.checked) checkBox.check();
if (field.required) checkBox.enableRequired(); if (field.required) checkBox.enableRequired();
@@ -2195,6 +2320,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
checkBox.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'radio') { } else if (field.type === 'radio') {
const groupName = field.name; const groupName = field.name;
let radioGroup; let radioGroup;
@@ -2223,7 +2353,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), ...getPdfBackgroundOptions(field, 1, 1, 1),
}); });
if (field.checked) radioGroup.select(field.exportValue || 'Yes'); if (field.checked) radioGroup.select(field.exportValue || 'Yes');
if (field.required) radioGroup.enableRequired(); if (field.required) radioGroup.enableRequired();
@@ -2233,6 +2363,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
radioGroup.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'dropdown') { } else if (field.type === 'dropdown') {
const dropdown = form.createDropdown(field.name); const dropdown = form.createDropdown(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000'); const borderRgb = hexToRgb(field.borderColor || '#000000');
@@ -2243,7 +2378,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), // Light blue not supported in standard PDF appearance easily without streams ...getPdfBackgroundOptions(field, 1, 1, 1),
}); });
if (field.options) dropdown.setOptions(field.options); if (field.options) dropdown.setOptions(field.options);
if (field.defaultValue && field.options?.includes(field.defaultValue)) if (field.defaultValue && field.options?.includes(field.defaultValue))
@@ -2264,6 +2399,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
dropdown.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'optionlist') { } else if (field.type === 'optionlist') {
const optionList = form.createOptionList(field.name); const optionList = form.createOptionList(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000'); const borderRgb = hexToRgb(field.borderColor || '#000000');
@@ -2274,7 +2414,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), ...getPdfBackgroundOptions(field, 1, 1, 1),
}); });
if (field.options) optionList.setOptions(field.options); if (field.options) optionList.setOptions(field.options);
if (field.defaultValue && field.options?.includes(field.defaultValue)) if (field.defaultValue && field.options?.includes(field.defaultValue))
@@ -2295,6 +2435,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
optionList.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'button') { } else if (field.type === 'button') {
const button = form.createButton(field.name); const button = form.createButton(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000'); const borderRgb = hexToRgb(field.borderColor || '#000000');
@@ -2305,7 +2450,7 @@ downloadBtn.addEventListener('click', async () => {
height: height, height: height,
borderWidth: field.hideBorder ? 0 : 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(0.8, 0.8, 0.8), // Light gray ...getPdfBackgroundOptions(field, 0.8, 0.8, 0.8),
}); });
// Add Action // Add Action
@@ -2383,16 +2528,22 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
button.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'date') { } else if (field.type === 'date') {
const dateField = form.createTextField(field.name); const dateField = form.createTextField(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000');
dateField.addToPage(pdfPage, { dateField.addToPage(pdfPage, {
x: x, x: x,
y: y, y: y,
width: width, width: width,
height: height, height: height,
borderWidth: 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(0, 0, 0), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(1, 1, 1), ...getPdfBackgroundOptions(field, 1, 1, 1),
}); });
// Add Date Format and Keystroke Actions to the FIELD (not widget) // Add Date Format and Keystroke Actions to the FIELD (not widget)
@@ -2424,16 +2575,22 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
dateField.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'image') { } else if (field.type === 'image') {
const imageBtn = form.createButton(field.name); const imageBtn = form.createButton(field.name);
const borderRgb = hexToRgb(field.borderColor || '#000000');
imageBtn.addToPage(field.label || 'Click to Upload Image', pdfPage, { imageBtn.addToPage(field.label || 'Click to Upload Image', pdfPage, {
x: x, x: x,
y: y, y: y,
width: width, width: width,
height: height, height: height,
borderWidth: 1, borderWidth: field.hideBorder ? 0 : 1,
borderColor: rgb(0, 0, 0), borderColor: rgb(borderRgb.r, borderRgb.g, borderRgb.b),
backgroundColor: rgb(0.9, 0.9, 0.9), ...getPdfBackgroundOptions(field, 0.9, 0.9, 0.9),
}); });
// Add Import Icon Action // Add Import Icon Action
@@ -2451,7 +2608,6 @@ downloadBtn.addEventListener('click', async () => {
// IF (Icon Fit) -> SW: A (Always Scale), S: A (Anamorphic/Fill) // IF (Icon Fit) -> SW: A (Always Scale), S: A (Anamorphic/Fill)
const mkDict = pdfDoc.context.obj({ const mkDict = pdfDoc.context.obj({
TP: 1, TP: 1,
BG: [0.9, 0.9, 0.9], // Background color (Light Gray)
BC: [0, 0, 0], // Border color (Black) BC: [0, 0, 0], // Border color (Black)
IF: { IF: {
SW: PDFName.of('A'), SW: PDFName.of('A'),
@@ -2459,6 +2615,9 @@ downloadBtn.addEventListener('click', async () => {
FB: true, FB: true,
}, },
}); });
if (!hasTransparentBackground(field)) {
mkDict.set(PDFName.of('BG'), pdfDoc.context.obj([0.9, 0.9, 0.9]));
}
widget.dict.set(PDFName.of('MK'), mkDict); widget.dict.set(PDFName.of('MK'), mkDict);
}); });
@@ -2467,6 +2626,11 @@ downloadBtn.addEventListener('click', async () => {
widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip)); widget.dict.set(PDFName.of('TU'), PDFString.of(field.tooltip));
}); });
} }
clearTransparentFieldWidgetBackgrounds(
field,
imageBtn.acroField.getWidgets(),
pdfDoc
);
} else if (field.type === 'signature') { } else if (field.type === 'signature') {
const context = pdfDoc.context; const context = pdfDoc.context;
@@ -2490,12 +2654,18 @@ downloadBtn.addEventListener('click', async () => {
// Add border and background appearance // Add border and background appearance
const borderStyle = context.obj({ const borderStyle = context.obj({
W: 1, // Border width W: field.hideBorder ? 0 : 1, // Border width
S: PDFName.of('S'), // Solid border S: PDFName.of('S'), // Solid border
}) as PDFDict; }) as PDFDict;
widgetDict.set(PDFName.of('BS'), borderStyle); widgetDict.set(PDFName.of('BS'), borderStyle);
widgetDict.set(PDFName.of('BC'), context.obj([0, 0, 0])); // Border color (black) const borderRgb = hexToRgb(field.borderColor || '#000000');
widgetDict.set(PDFName.of('BG'), context.obj([0.95, 0.95, 0.95])); // Background color widgetDict.set(
PDFName.of('BC'),
context.obj([borderRgb.r, borderRgb.g, borderRgb.b])
); // Border color
if (!hasTransparentBackground(field)) {
widgetDict.set(PDFName.of('BG'), context.obj([0.95, 0.95, 0.95]));
}
const widgetRef = context.register(widgetDict); const widgetRef = context.register(widgetDict);

View File

@@ -81,6 +81,7 @@ export interface FormField {
multiline?: boolean; multiline?: boolean;
borderColor?: string; borderColor?: string;
hideBorder?: boolean; hideBorder?: boolean;
transparentBackground?: boolean;
barcodeFormat?: string; barcodeFormat?: string;
barcodeValue?: string; barcodeValue?: string;
} }