qrcode-studio
Version:
A comprehensive Capacitor plugin for QR code and barcode scanning/generation. Supports 22+ QR data types and 14+ barcode formats (EAN, UPC, Code 128, etc.), with customizable designs, analytics, and React components. Works seamlessly across web, iOS, and
96 lines • 7.36 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState } from 'react';
import { QRCodeStudio } from '../index';
export const BarcodeScanner = ({ onScan, onError, formats, showTorchButton = true, showFormatSelector = false, multiple = false, scanOptions = {}, className = '', style = {}, showOverlay = true, overlayComponent, showProductInfo = true, }) => {
const [isScanning, setIsScanning] = useState(false);
const [torchEnabled, setTorchEnabled] = useState(false);
const [torchAvailable, setTorchAvailable] = useState(false);
const [selectedFormats, setSelectedFormats] = useState(formats || []);
const [lastScan, setLastScan] = useState(null);
const scannerRef = useRef(null);
useEffect(() => {
let scanListener;
let errorListener;
let torchListener;
const initScanner = async () => {
try {
// Check permissions
const permissions = await QRCodeStudio.checkPermissions();
if (permissions.camera !== 'granted') {
const requestResult = await QRCodeStudio.requestPermissions();
if (requestResult.camera !== 'granted') {
onError === null || onError === void 0 ? void 0 : onError({
code: 'PERMISSION_DENIED',
message: 'Camera permission denied',
});
return;
}
}
// Check torch availability
const torch = await QRCodeStudio.isTorchAvailable();
setTorchAvailable(torch.available);
// Setup listeners
scanListener = await QRCodeStudio.addListener('scanResult', (result) => {
setLastScan(result);
onScan(result);
});
errorListener = await QRCodeStudio.addListener('scanError', (error) => {
onError === null || onError === void 0 ? void 0 : onError(error);
});
torchListener = await QRCodeStudio.addListener('torchStateChanged', (state) => {
setTorchEnabled(state.isEnabled);
});
// Start scanning
await QRCodeStudio.startScan(Object.assign(Object.assign({}, scanOptions), { formats: selectedFormats.length > 0 ? selectedFormats : undefined, multiple, showTorchButton: false }));
setIsScanning(true);
}
catch (error) {
onError === null || onError === void 0 ? void 0 : onError({
code: 'INIT_ERROR',
message: error instanceof Error ? error.message : 'Failed to initialize scanner',
});
}
};
initScanner();
return () => {
if (isScanning) {
QRCodeStudio.stopScan();
}
scanListener === null || scanListener === void 0 ? void 0 : scanListener.remove();
errorListener === null || errorListener === void 0 ? void 0 : errorListener.remove();
torchListener === null || torchListener === void 0 ? void 0 : torchListener.remove();
};
}, [selectedFormats, multiple]);
const handleTorchToggle = async () => {
try {
if (torchEnabled) {
await QRCodeStudio.disableTorch();
}
else {
await QRCodeStudio.enableTorch();
}
}
catch (error) {
console.error('Failed to toggle torch:', error);
}
};
const handleFormatChange = (format, checked) => {
setSelectedFormats(prev => {
if (checked) {
return [...prev, format];
}
else {
return prev.filter(f => f !== format);
}
});
};
const formatGroups = {
'2D Codes': ['QR_CODE', 'DATA_MATRIX', 'AZTEC', 'PDF_417', 'MAXICODE'],
'Product Codes': ['EAN_13', 'EAN_8', 'UPC_A', 'UPC_E'],
'Industrial Codes': ['CODE_128', 'CODE_39', 'CODE_93', 'CODABAR', 'ITF', 'ITF_14'],
'Specialty': ['MSI', 'MSI_PLESSEY', 'PHARMACODE', 'RSS_14', 'RSS_EXPANDED'],
};
return (_jsxs("div", { ref: scannerRef, className: `barcode-scanner ${className}`, style: Object.assign({ position: 'relative', width: '100%', height: '100%' }, style), children: [showOverlay && !overlayComponent && (_jsxs("div", { className: "barcode-scanner-overlay", children: [_jsxs("div", { className: "scanning-frame", children: [_jsx("div", { className: "corner corner-tl" }), _jsx("div", { className: "corner corner-tr" }), _jsx("div", { className: "corner corner-bl" }), _jsx("div", { className: "corner corner-br" })] }), _jsxs("div", { className: "scanner-controls", children: [showTorchButton && torchAvailable && (_jsx("button", { className: `torch-button ${torchEnabled ? 'enabled' : ''}`, onClick: handleTorchToggle, "aria-label": torchEnabled ? 'Turn off flashlight' : 'Turn on flashlight', children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: torchEnabled ? (_jsx("path", { d: "M6,14L7,14.05L13,14.05L14,14L14,7L13,6.95L7,6.95L6,7L6,14M8,2L16,2L16,7L20,7L20,12L16,12L16,22L8,22L8,12L4,12L4,7L8,7L8,2M10,4L10,10L14,10L14,4L10,4Z" })) : (_jsx("path", { d: "M6,14L7,14.05L13,14.05L14,14L14,7L13,6.95L7,6.95L6,7L6,14M8,2L16,2L16,7L20,7L20,12L16,12L16,22L8,22L8,12L4,12L4,7L8,7L8,2Z" })) }) })), showFormatSelector && (_jsxs("div", { className: "format-selector", children: [_jsx("button", { className: "format-selector-toggle", children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: _jsx("path", { d: "M3,4H7V8H3V4M9,5V7H21V5H9M3,10H7V14H3V10M9,11V13H21V11H9M3,16H7V20H3V16M9,17V19H21V17H9" }) }) }), _jsx("div", { className: "format-dropdown", children: Object.entries(formatGroups).map(([group, groupFormats]) => (_jsxs("div", { className: "format-group", children: [_jsx("div", { className: "format-group-label", children: group }), groupFormats.map(format => (_jsxs("label", { className: "format-option", children: [_jsx("input", { type: "checkbox", checked: selectedFormats.includes(format), onChange: (e) => handleFormatChange(format, e.target.checked) }), _jsx("span", { children: format.replace(/_/g, ' ') })] }, format)))] }, group))) })] }))] }), lastScan && showProductInfo && lastScan.productInfo && (_jsx("div", { className: "product-info-overlay", children: _jsxs("div", { className: "product-info", children: [_jsx("h3", { children: lastScan.productInfo.name }), lastScan.productInfo.brand && _jsx("p", { className: "brand", children: lastScan.productInfo.brand }), lastScan.productInfo.price && (_jsxs("p", { className: "price", children: [lastScan.productInfo.price.currency, " ", lastScan.productInfo.price.value] })), _jsx("p", { className: "barcode", children: lastScan.content }), _jsx("p", { className: "format", children: lastScan.format.replace(/_/g, ' ') })] }) })), _jsx("div", { className: "scanner-instructions", children: multiple ? 'Scan multiple barcodes' : 'Position barcode within frame' })] })), overlayComponent] }));
};
export default BarcodeScanner;
//# sourceMappingURL=BarcodeScanner.js.map