code-craft-studio
Version:
A comprehensive QR code and barcode scanning/generation library for React. Works with or without Capacitor. Supports 22+ QR data types and 14+ barcode formats (EAN, UPC, Code 128, etc.), with customizable designs, analytics, and React components. Provider
147 lines • 8 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useState, useEffect, useCallback, useRef } from 'react';
import { QRCodeStudio } from '../../index';
import { validateQRData, QRValidationError } from '../../core/validators/qr-validators';
// import './QRGenerator.css'; // CSS should be imported by the consuming app
export const QRGenerator = ({ type, data, design = {}, size = 300, format = 'png', onGenerate, className = '', style, showDownload = true, showShare = true, errorCorrectionLevel = 'M', version, maskPattern, margin, scale, width, toSJISFunc, }) => {
const [qrCode, setQrCode] = useState(null);
const [isGenerating, setIsGenerating] = useState(false);
const [error, setError] = useState(null);
const [selectedFormat, setSelectedFormat] = useState(format);
const canvasRef = useRef(null);
const containerRef = useRef(null);
// Generate QR code when props change
useEffect(() => {
generateQRCode();
}, [type, data, design, size]);
const generateQRCode = useCallback(async () => {
try {
// Validate data
validateQRData(type, data);
setIsGenerating(true);
setError(null);
const result = await QRCodeStudio.generate({
type,
data,
design,
size,
errorCorrectionLevel,
version,
maskPattern,
margin,
scale,
width,
toSJISFunc,
});
setQrCode(result);
onGenerate === null || onGenerate === void 0 ? void 0 : onGenerate(result);
// Apply custom design if needed
if (design.logo || design.frame) {
applyCustomDesign(result);
}
}
catch (err) {
if (err instanceof QRValidationError) {
setError(`Validation Error: ${err.message}`);
}
else {
setError(err instanceof Error ? err.message : 'Failed to generate QR code');
}
}
finally {
setIsGenerating(false);
}
}, [type, data, design, size, onGenerate]);
const applyCustomDesign = async (qrResult) => {
if (!canvasRef.current || !qrResult.dataUrl)
return;
const canvas = canvasRef.current;
const ctx = canvas.getContext('2d');
if (!ctx)
return;
canvas.width = size;
canvas.height = size;
// Draw QR code
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0, size, size);
// Apply logo if provided
if (design.logo) {
const logoImg = new Image();
logoImg.crossOrigin = 'anonymous';
logoImg.onload = () => {
var _a;
const logoSize = design.logo.size || size * 0.2;
const logoMargin = design.logo.margin || 10;
const x = (size - logoSize) / 2;
const y = (size - logoSize) / 2;
// Draw white background for logo
ctx.fillStyle = ((_a = design.colors) === null || _a === void 0 ? void 0 : _a.light) || '#FFFFFF';
ctx.fillRect(x - logoMargin, y - logoMargin, logoSize + logoMargin * 2, logoSize + logoMargin * 2);
// Draw logo
if (design.logo.borderRadius) {
ctx.save();
ctx.beginPath();
ctx.roundRect(x, y, logoSize, logoSize, design.logo.borderRadius);
ctx.clip();
ctx.drawImage(logoImg, x, y, logoSize, logoSize);
ctx.restore();
}
else {
ctx.drawImage(logoImg, x, y, logoSize, logoSize);
}
};
logoImg.src = design.logo.src;
}
};
img.src = qrResult.dataUrl;
};
const handleDownload = async () => {
if (!qrCode)
return;
try {
await QRCodeStudio.saveQRCode({
qrCode,
fileName: `qrcode_${type}_${Date.now()}`,
format: selectedFormat,
});
}
catch (_a) {
setError('Failed to download QR code');
}
};
const handleShare = async () => {
if (!qrCode || !qrCode.dataUrl)
return;
if (navigator.share) {
try {
const blob = await (await fetch(qrCode.dataUrl)).blob();
const file = new File([blob], `qrcode.${selectedFormat}`, { type: `image/${selectedFormat}` });
await navigator.share({
title: 'QR Code',
text: `QR Code for ${type}`,
files: [file],
});
}
catch (err) {
if (err.name !== 'AbortError') {
setError('Failed to share QR code');
}
}
}
else {
// Fallback: Copy to clipboard
try {
await navigator.clipboard.writeText(qrCode.shortUrl || qrCode.landingPageUrl || qrCode.dataUrl);
alert('Link copied to clipboard!');
}
catch (_a) {
setError('Sharing not supported on this device');
}
}
};
const exportFormats = ['png', 'jpg', 'svg', 'pdf', 'json', 'webp', 'gif', 'eps', 'wmf'];
return (_jsxs("div", { ref: containerRef, className: `qr-generator-container ${className}`, style: style, children: [error && (_jsxs("div", { className: "qr-generator-error", children: [_jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), _jsx("p", { children: error }), _jsx("button", { onClick: generateQRCode, children: "Retry" })] })), isGenerating && (_jsxs("div", { className: "qr-generator-loading", children: [_jsx("div", { className: "loading-spinner" }), _jsx("p", { children: "Generating QR Code..." })] })), !isGenerating && qrCode && !error && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "qr-code-preview", children: [qrCode.svg ? (_jsx("div", { className: "qr-code-svg", dangerouslySetInnerHTML: { __html: qrCode.svg }, style: { width: size, height: size } })) : qrCode.dataUrl ? (_jsx("img", { src: qrCode.dataUrl, alt: "QR Code", className: "qr-code-image", style: { width: size, height: size } })) : null, _jsx("canvas", { ref: canvasRef, style: { display: 'none' } })] }), _jsxs("div", { className: "qr-generator-actions", children: [showDownload && (_jsxs("div", { className: "download-section", children: [_jsx("select", { value: selectedFormat, onChange: (e) => setSelectedFormat(e.target.value), className: "format-select", children: exportFormats.map(fmt => (_jsx("option", { value: fmt, children: fmt.toUpperCase() }, fmt))) }), _jsxs("button", { onClick: handleDownload, className: "download-button", children: [_jsx("span", { className: "button-icon", children: "\u2B07\uFE0F" }), "Download"] })] })), showShare && (_jsxs("button", { onClick: handleShare, className: "share-button", children: [_jsx("span", { className: "button-icon", children: "\uD83D\uDD17" }), "Share"] }))] }), qrCode.shortUrl && (_jsxs("div", { className: "qr-code-url", children: [_jsx("label", { children: "Short URL:" }), _jsx("input", { type: "text", value: qrCode.shortUrl, readOnly: true, onClick: (e) => e.target.select() })] })), qrCode.landingPageUrl && (_jsxs("div", { className: "qr-code-url", children: [_jsx("label", { children: "Landing Page:" }), _jsx("input", { type: "text", value: qrCode.landingPageUrl, readOnly: true, onClick: (e) => e.target.select() })] }))] }))] }));
};
export default QRGenerator;
//# sourceMappingURL=QRGenerator.js.map