UNPKG

@devm7mdali/pdf-maker

Version:

PDF maker web component

206 lines (173 loc) 6.84 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.PDFMaker = factory()); })(this, (function () { 'use strict'; /** * Custom element for converting HTML to PDF * @element pdf-maker * @attr {string} api-key - API key for authentication * @attr {string} endpoint - PDF generation endpoint URL * @attr {string} filename - Default filename for downloaded PDF * @attr {'portrait'|'landscape'} orientation - PDF orientation * @attr {string} placeholder - Textarea placeholder text * @fires pdf-maker:start - Fired when PDF generation starts * @fires pdf-maker:success - Fired when PDF is successfully generated * @fires pdf-maker:error - Fired when PDF generation fails */ class PDFMaker extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this._defaultFilename = 'document.pdf'; this._textarea = null; this._button = null; this._status = null; } static get observedAttributes() { //! explained at the top return ['api-key', 'endpoint', 'filename', 'orientation', 'placeholder']; } attributeChangedCallback(name, oldValue, newValue) { if (oldValue === newValue) return; switch (name) { case 'placeholder': if (this._textarea) { this._textarea.placeholder = newValue || 'Enter / paste HTML to convert to PDF'; } break; case 'filename': this._defaultFilename = newValue || 'document.pdf'; break; } } // Public API Properties (matching TypeScript declarations) get html() { return this._textarea?.value || ''; } set html(value) { if (this._textarea) { this._textarea.value = value || ''; } } get loading() { return this._button?.disabled || false; } get status() { return this._status?.textContent || ''; } // Public API Methods (matching TypeScript declarations) async generatePDF() { if (!this._button) { throw new Error('Component not ready'); } // Return a promise that resolves with the blob return new Promise((resolve, reject) => { const handleSuccess = (e) => { this.removeEventListener('pdf-maker:success', handleSuccess); this.removeEventListener('pdf-maker:error', handleError); resolve(e.detail.blob); }; const handleError = (e) => { this.removeEventListener('pdf-maker:success', handleSuccess); this.removeEventListener('pdf-maker:error', handleError); reject(e.detail.error); }; this.addEventListener('pdf-maker:success', handleSuccess, { once: true }); this.addEventListener('pdf-maker:error', handleError, { once: true }); // Trigger the button click this._button.click(); }); } // Private method to dispatch custom events _dispatch(eventName, detail = {}) { this.dispatchEvent(new CustomEvent(`pdf-maker:${eventName}`, { detail, bubbles: true, cancelable: false })); } connectedCallback() { this.getAttribute('api-key'); const endpoint = this.getAttribute('endpoint') || 'https://your-api.com/upload'; const defaultFilename = this.getAttribute('filename') || 'document.pdf'; this.getAttribute('orientation') || 'portrait'; const style = document.createElement('style'); style.textContent = ` .uploader { display: flex; flex-direction: column; gap: 8px; font-family: system-ui,sans-serif; } textarea { border: 1px solid #ccc; border-radius: 6px; padding: 6px; font-family: monospace; } button { background:#4f46e5; color:#fff; border:none; padding:8px 12px; border-radius:6px; cursor:pointer; } button:disabled { opacity:.6; cursor:progress; } .status { font-size:12px; color:#555; min-height:16px; } `; const wrapper = document.createElement('div'); wrapper.className = 'uploader'; const input = document.createElement('textarea'); input.rows = 6; input.placeholder = 'Enter / paste HTML to convert to PDF'; const button = document.createElement('button'); button.textContent = 'Generate PDF'; const status = document.createElement('div'); status.className = 'status'; // Store references for public API access this._textarea = input; this._button = button; this._status = status; button.addEventListener('click', async () => { const html = input.value.trim(); if (!html) return alert('Please provide HTML content.'); // Dispatch start event this._dispatch('start', { html }); status.textContent = 'Requesting PDF...'; status.className = 'status'; button.disabled = true; try { const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ html, orientation: 'portrait' }) }); const contentType = res.headers.get('content-type') || ''; if (!res.ok) { let detail = ''; try { detail = contentType.includes('json') ? JSON.stringify(await res.json()) : (await res.text()).slice(0, 200); } catch { } throw new Error(`HTTP ${res.status} ${detail}`); } if (!contentType.includes('application/pdf')) { throw new Error(`Unexpected content-type ${contentType}`); } const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = defaultFilename; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); status.textContent = 'PDF downloaded.'; } catch (err) { const errorMessage = 'Error: ' + (err.message || err); status.textContent = errorMessage; status.className = 'status error'; // Dispatch error event this._dispatch('error', { error: err, html }); } finally { button.disabled = false; } }); wrapper.appendChild(input); wrapper.appendChild(button); wrapper.appendChild(status); this.shadowRoot.append(style, wrapper); } } customElements.define('pdf-maker', PDFMaker); return PDFMaker; })); //# sourceMappingURL=pdf-maker.umd.js.map