Files
scan-wave/src/routes/private/scanner/QRScanner.svelte
2025-06-25 14:54:06 +02:00

78 lines
2.1 KiB
Svelte

<script lang="ts">
import { onMount, onDestroy } from 'svelte';
import {
Html5QrcodeScanner,
type Html5QrcodeResult,
Html5QrcodeScanType,
Html5QrcodeSupportedFormats
} from 'html5-qrcode';
let width: number = 300;
let height: number = 300;
let { message = $bindable() } = $props();
function onScanSuccess(decodedText: string, decodedResult: Html5QrcodeResult): void {
//console.log(`Code scanned = ${decodedText}`);
message = decodedText;
}
// usually better to ignore and keep scanning
function onScanFailure(message: string) {
//console.log(`Code scan error = ${message}`);
}
let scanner: Html5QrcodeScanner;
onMount(() => {
scanner = new Html5QrcodeScanner(
'qr-scanner',
{
fps: 5,
qrbox: { width, height },
aspectRatio: 1,
supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA],
formatsToSupport: [Html5QrcodeSupportedFormats.QR_CODE],
},
false // non-verbose
);
scanner.render(onScanSuccess, onScanFailure);
});
onDestroy(() => {
if (scanner) {
scanner.clear().catch(() => {});
}
});
</script>
<div id="qr-scanner" class="w-full h-full max-w-none overflow-hidden rounded-sm"></div>
<style>
/* Hide unwanted icons */
#qr-scanner :global(img[alt='Info icon']),
#qr-scanner :global(img[alt='Camera based scan']) {
display: none;
}
#qr-scanner {
color: black !important;
}
/* Change camera permission button text */
#qr-scanner :global(#html5-qrcode-button-camera-permission) {
visibility: hidden;
}
#qr-scanner :global(#html5-qrcode-button-camera-permission::after) {
position: absolute;
inset: auto 0 0;
display: block;
content: 'Allow camera access';
visibility: visible;
padding: 10px 0;
}
#qr-scanner :global(#qr-scanner__scan_region) {
min-height: auto !important;
aspect-ratio: 1 !important;
}
</style>