export const usePdfExportSimple = () => { const exportToPDF = async (elementSelector: string, filename: string) => { // Only run on client side if (process.server || typeof window === "undefined") { throw new Error("PDF generation is only available on the client side"); } try { // Dynamic import for client-side only const html2pdf = (await import("html2pdf.js")).default; // Get the element to export const element = document.querySelector(elementSelector); if (!element) { throw new Error(`Element with selector "${elementSelector}" not found`); } // Clone the element to avoid modifying the original const clonedElement = element.cloneNode(true) as HTMLElement; // Fix CSS compatibility issues by applying only computed styles const fixCSSCompatibility = (el: HTMLElement) => { // Get all elements including the root const allElements = [el, ...el.querySelectorAll("*")] as HTMLElement[]; allElements.forEach((elem) => { // Get computed styles const computedStyle = window.getComputedStyle(elem); // Clear all existing styles to start fresh elem.removeAttribute("style"); elem.removeAttribute("class"); // Apply only essential computed styles that are safe elem.style.display = computedStyle.display; elem.style.position = computedStyle.position; elem.style.width = computedStyle.width; elem.style.height = computedStyle.height; elem.style.margin = computedStyle.margin; elem.style.padding = computedStyle.padding; elem.style.fontSize = computedStyle.fontSize; elem.style.fontWeight = computedStyle.fontWeight; elem.style.fontFamily = computedStyle.fontFamily; elem.style.lineHeight = computedStyle.lineHeight; elem.style.textAlign = computedStyle.textAlign; // Apply safe color values - convert any complex colors to simple ones const safeColor = computedStyle.color.includes("oklch") || computedStyle.color.includes("oklab") ? "#000000" : computedStyle.color; const safeBgColor = computedStyle.backgroundColor.includes("oklch") || computedStyle.backgroundColor.includes("oklab") ? "transparent" : computedStyle.backgroundColor; elem.style.color = safeColor; elem.style.backgroundColor = safeBgColor; elem.style.borderWidth = computedStyle.borderWidth; elem.style.borderStyle = computedStyle.borderStyle; elem.style.borderColor = "#cccccc"; // Safe fallback color }); }; // Apply CSS fixes fixCSSCompatibility(clonedElement); // Temporarily add to DOM for processing clonedElement.style.position = "absolute"; clonedElement.style.left = "-9999px"; clonedElement.style.top = "-9999px"; document.body.appendChild(clonedElement); // Simple options for better compatibility const options = { margin: 0.5, filename: filename, image: { type: "jpeg", quality: 0.98 }, html2canvas: { scale: 2, useCORS: true, allowTaint: false, logging: false, ignoreElements: (element: Element) => { // Skip elements that might cause issues return ( element.classList.contains("no-pdf") || element.classList.contains("export-controls") ); }, onclone: (clonedDoc: Document) => { // Remove ALL existing stylesheets to avoid oklch() issues const stylesheets = clonedDoc.querySelectorAll( 'style, link[rel="stylesheet"]' ); stylesheets.forEach((sheet) => sheet.remove()); // Add only safe, basic CSS const safeStyle = clonedDoc.createElement("style"); safeStyle.textContent = ` * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 12px; line-height: 1.5; color: #000000; background: #ffffff; } .export-controls, .no-pdf { display: none !important; } /* Basic typography */ h1 { font-size: 24px; font-weight: bold; margin: 20px 0 10px 0; } h2 { font-size: 20px; font-weight: bold; margin: 16px 0 8px 0; } h3 { font-size: 16px; font-weight: bold; margin: 12px 0 6px 0; } p { margin: 8px 0; } ul, ol { margin: 8px 0; padding-left: 20px; } li { margin: 4px 0; } /* Form elements */ input, textarea, select { border: 1px solid #ccc; padding: 4px; font-size: 12px; background: #fff; color: #000; } `; clonedDoc.head.appendChild(safeStyle); }, }, jsPDF: { unit: "in", format: "letter", orientation: "portrait", }, }; console.log("Generating PDF with html2pdf..."); // Wait a moment for DOM changes to settle await new Promise((resolve) => setTimeout(resolve, 100)); try { // Generate and save the PDF using the cloned element await html2pdf().set(options).from(clonedElement).save(); console.log("PDF generated successfully!"); } finally { // Clean up the cloned element if (clonedElement.parentNode) { document.body.removeChild(clonedElement); } } } catch (error: any) { console.error("PDF generation error:", error); throw new Error(`PDF generation failed: ${error.message || error}`); } }; return { exportToPDF }; };