qr-scanner-app 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.editorconfig +17 -0
  2. package/.firebase/hosting.ZGlzdC9xci1zY2FubmVyLWFwcA.cache +7 -0
  3. package/.firebase/hosting.ZGlzdC9xci1zY2FubmVyLWFwcC9icm93c2Vy.cache +13 -0
  4. package/.vscode/extensions.json +4 -0
  5. package/.vscode/launch.json +20 -0
  6. package/.vscode/tasks.json +42 -0
  7. package/Archive.zip +0 -0
  8. package/angular.json +0 -3
  9. package/firebase.json +7 -1
  10. package/package.json +1 -1
  11. package/projects/ngx-custom-qr-scanner/package.json +1 -1
  12. package/projects/ngx-custom-qr-scanner/src/lib/ngx-custom-qr-scanner.component.ts +4 -2
  13. package/.angular/cache/19.2.20/ng-packagr/039402e1b9c57c1752092adbb22bb9ff42a9937e94fcb457669453df8a080420 +0 -1
  14. package/.angular/cache/19.2.20/ng-packagr/794eeabb50992d155b7b6ea28b0205f5d7449844a1dba48e699c81e15302a2e5 +0 -1
  15. package/.angular/cache/19.2.20/ng-packagr/tsbuildinfo/ngx-custom-qr-scanner.tsbuildinfo +0 -1
  16. package/.angular/cache/19.2.20/qr-scanner-app/.tsbuildinfo +0 -1
  17. package/.angular/cache/19.2.20/qr-scanner-app/angular-compiler.db +0 -0
  18. package/.angular/cache/19.2.20/qr-scanner-app/angular-compiler.db-lock +0 -0
  19. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_common.js +0 -200
  20. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_common.js.map +0 -7
  21. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_core.js +0 -1017
  22. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_core.js.map +0 -7
  23. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_platform-browser.js +0 -80
  24. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_platform-browser.js.map +0 -7
  25. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_router.js +0 -5987
  26. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/@angular_router.js.map +0 -7
  27. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/_metadata.json +0 -55
  28. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-ECSDJ7NH.js +0 -29956
  29. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-ECSDJ7NH.js.map +0 -7
  30. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-EDEOLW5S.js +0 -5154
  31. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-EDEOLW5S.js.map +0 -7
  32. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-GL2TQU2H.js +0 -4464
  33. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-GL2TQU2H.js.map +0 -7
  34. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-WDMUDEB6.js +0 -58
  35. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/chunk-WDMUDEB6.js.map +0 -7
  36. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/package.json +0 -3
  37. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/qr-scanner-worker.min-QCTCWOU3.js +0 -107
  38. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/qr-scanner-worker.min-QCTCWOU3.js.map +0 -7
  39. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/qr-scanner.js +0 -497
  40. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps/qr-scanner.js.map +0 -7
  41. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps_ssr/_metadata.json +0 -8
  42. package/.angular/cache/19.2.20/qr-scanner-app/vite/deps_ssr/package.json +0 -3
  43. package/dist/ngx-custom-qr-scanner/LICENSE +0 -21
  44. package/dist/ngx-custom-qr-scanner/README.md +0 -1
  45. package/dist/ngx-custom-qr-scanner/fesm2022/ngx-custom-qr-scanner.mjs +0 -227
  46. package/dist/ngx-custom-qr-scanner/fesm2022/ngx-custom-qr-scanner.mjs.map +0 -1
  47. package/dist/ngx-custom-qr-scanner/index.d.ts +0 -5
  48. package/dist/ngx-custom-qr-scanner/lib/ngx-custom-qr-scanner.component.d.ts +0 -19
  49. package/dist/ngx-custom-qr-scanner/lib/ngx-custom-qr-scanner.service.d.ts +0 -6
  50. package/dist/ngx-custom-qr-scanner/package.json +0 -42
  51. package/dist/ngx-custom-qr-scanner/public-api.d.ts +0 -2
  52. package/dist/qr-scanner-app/3rdpartylicenses.txt +0 -381
  53. package/dist/qr-scanner-app/browser/404.html +0 -33
  54. package/dist/qr-scanner-app/browser/assets/wasm/index.d.ts +0 -154
  55. package/dist/qr-scanner-app/browser/assets/wasm/index.js +0 -2
  56. package/dist/qr-scanner-app/browser/assets/wasm/index.js.map +0 -314
  57. package/dist/qr-scanner-app/browser/assets/wasm/index.mjs +0 -2
  58. package/dist/qr-scanner-app/browser/assets/wasm/index.mjs.map +0 -316
  59. package/dist/qr-scanner-app/browser/assets/wasm/ngx-scanner-qrcode.wasm +0 -0
  60. package/dist/qr-scanner-app/browser/chunk-2VMXMS7J.js +0 -1
  61. package/dist/qr-scanner-app/browser/chunk-6H7TWJR4.js +0 -98
  62. package/dist/qr-scanner-app/browser/favicon.ico +0 -0
  63. package/dist/qr-scanner-app/browser/index.html +0 -16
  64. package/dist/qr-scanner-app/browser/main-F3VZJFPT.js +0 -7
  65. package/dist/qr-scanner-app/browser/polyfills-B6TNHZQ6.js +0 -2
  66. package/dist/qr-scanner-app/browser/styles-5INURTSO.css +0 -0
  67. package/dist/qr-scanner-app/prerendered-routes.json +0 -3
  68. package/public/404.html +0 -33
  69. package/public/index.html +0 -89
package/.editorconfig ADDED
@@ -0,0 +1,17 @@
1
+ # Editor configuration, see https://editorconfig.org
2
+ root = true
3
+
4
+ [*]
5
+ charset = utf-8
6
+ indent_style = space
7
+ indent_size = 2
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.ts]
12
+ quote_type = single
13
+ ij_typescript_use_double_quotes = false
14
+
15
+ [*.md]
16
+ max_line_length = off
17
+ trim_trailing_whitespace = false
@@ -0,0 +1,7 @@
1
+ browser/styles-5INURTSO.css,1770988179363,f1b651238a58fe290baec6c5e32f3bdb1943dd2bd582f02569231f7a757c7837
2
+ browser/index.html,1770988179364,d298e2708dc2f260f9f1891fb748aaee33584ac1309e3587015245aa43b31bdd
3
+ prerendered-routes.json,1770988179365,5c19cca0df6fbfe49815495e7145ec4551d30ac216520a6ce811ec2cca054a67
4
+ 3rdpartylicenses.txt,1770988179364,0327bcb868bf4fd5efa4b8257eea09d3623d81d58e25da91c7139b78bd5899b9
5
+ browser/polyfills-B6TNHZQ6.js,1770988179364,0d470d11ef45790298a0211b78859f53935f24a7d05c357a0bce142e2e12a925
6
+ browser/favicon.ico,1770988179363,8f1fc0f94ae643bb8757c3cb49f69bf6cb2228f632cb77c7e47d8ee3995d88a7
7
+ browser/main-VYJBJ3K3.js,1770988179365,78a6749820aba30057621fbe467750be97907dc329f5afd928cb63bb0ae62489
@@ -0,0 +1,13 @@
1
+ styles-5INURTSO.css,1771410818806,f1b651238a58fe290baec6c5e32f3bdb1943dd2bd582f02569231f7a757c7837
2
+ index.html,1771410818808,a53e7eb47c4ce1b09ba574e17aff2a15e676046ac46d991f2c0b19a17a5f2f62
3
+ chunk-2VMXMS7J.js,1771410818807,8f326e731f352307dfeb3085d7b33b00559f350cab254d5e8a180698dc9093e6
4
+ polyfills-B6TNHZQ6.js,1771410818808,0d470d11ef45790298a0211b78859f53935f24a7d05c357a0bce142e2e12a925
5
+ chunk-6H7TWJR4.js,1771410818807,6c12100c12753c2ef75ba236e57662da29199b2095cefac6446d5b69ddfe1adb
6
+ favicon.ico,1771410818806,8f1fc0f94ae643bb8757c3cb49f69bf6cb2228f632cb77c7e47d8ee3995d88a7
7
+ assets/wasm/index.d.ts,1771410818810,d666cf1980dca563d15a9f3d4ddfa2daefc56b1a75fe13865911e9caa755c185
8
+ assets/wasm/index.mjs,1771410818809,7173b80a747bfc839b92f9a5b684e93d2a70bb8536cbda8faef88a620e7ced8c
9
+ assets/wasm/index.js,1771410818811,42a66bdad28941e9162db3f486fcb3e9c5c26ba47812e58a9bdf4e86a39ff72a
10
+ assets/wasm/index.js.map,1771410818810,67bcabf551d05ba1431ec2d05a932ee73651585cd693b7dcb50f677c7fac17e0
11
+ assets/wasm/index.mjs.map,1771410818810,fde00a63e44377611b67351f627111f1fbd571d606da07a5de7de6945574db40
12
+ main-MBKMFYUE.js,1771410818807,911e1776e9cdc87561b7882eb41fed6c34f944df0068953b0356057689340423
13
+ assets/wasm/ngx-scanner-qrcode.wasm,1771410818813,e47e0b2b77ae1ad36cf44f0eeea5dec89996ff027412b3060f2fb9916d7ec632
@@ -0,0 +1,4 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3
+ "recommendations": ["angular.ng-template"]
4
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3
+ "version": "0.2.0",
4
+ "configurations": [
5
+ {
6
+ "name": "ng serve",
7
+ "type": "chrome",
8
+ "request": "launch",
9
+ "preLaunchTask": "npm: start",
10
+ "url": "http://localhost:4200/"
11
+ },
12
+ {
13
+ "name": "ng test",
14
+ "type": "chrome",
15
+ "request": "launch",
16
+ "preLaunchTask": "npm: test",
17
+ "url": "http://localhost:9876/debug.html"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3
+ "version": "2.0.0",
4
+ "tasks": [
5
+ {
6
+ "type": "npm",
7
+ "script": "start",
8
+ "isBackground": true,
9
+ "problemMatcher": {
10
+ "owner": "typescript",
11
+ "pattern": "$tsc",
12
+ "background": {
13
+ "activeOnStart": true,
14
+ "beginsPattern": {
15
+ "regexp": "(.*?)"
16
+ },
17
+ "endsPattern": {
18
+ "regexp": "bundle generation complete"
19
+ }
20
+ }
21
+ }
22
+ },
23
+ {
24
+ "type": "npm",
25
+ "script": "test",
26
+ "isBackground": true,
27
+ "problemMatcher": {
28
+ "owner": "typescript",
29
+ "pattern": "$tsc",
30
+ "background": {
31
+ "activeOnStart": true,
32
+ "beginsPattern": {
33
+ "regexp": "(.*?)"
34
+ },
35
+ "endsPattern": {
36
+ "regexp": "bundle generation complete"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ]
42
+ }
package/Archive.zip ADDED
Binary file
package/angular.json CHANGED
@@ -130,8 +130,5 @@
130
130
  }
131
131
  }
132
132
  }
133
- },
134
- "cli": {
135
- "analytics": false
136
133
  }
137
134
  }
package/firebase.json CHANGED
@@ -5,6 +5,12 @@
5
5
  "firebase.json",
6
6
  "**/.*",
7
7
  "**/node_modules/**"
8
+ ],
9
+ "rewrites": [
10
+ {
11
+ "source": "**",
12
+ "destination": "/index.html"
13
+ }
8
14
  ]
9
15
  }
10
- }
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qr-scanner-app",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "scripts": {
5
5
  "ng": "ng",
6
6
  "start": "ng serve",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-custom-qr-scanner",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "A reusable Angular QR scanner library",
5
5
  "keywords": [
6
6
  "angular",
@@ -1,6 +1,6 @@
1
- import { Component, AfterViewInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
1
+ import { Component, AfterViewInit, OnDestroy, ViewChild, ElementRef, Output, EventEmitter } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
- import QrScanner from 'qr-scanner';
3
+ import QrScanner from 'qr-scanner';
4
4
  // Make sure you have installed: npm install qr-scanner
5
5
 
6
6
  @Component({
@@ -285,6 +285,7 @@ import QrScanner from 'qr-scanner';
285
285
  })
286
286
  export class NgxCustomQrScannerComponent implements AfterViewInit, OnDestroy {
287
287
  @ViewChild('video', { static: true }) videoRef!: ElementRef<HTMLVideoElement>;
288
+ @Output() qrdata = new EventEmitter<string>();
288
289
 
289
290
  // --- LOGIC STARTS HERE (Preserved exactly as requested) ---
290
291
  qrScanner!: QrScanner;
@@ -298,6 +299,7 @@ export class NgxCustomQrScannerComponent implements AfterViewInit, OnDestroy {
298
299
  this.videoRef.nativeElement,
299
300
  (result: { data: string }) => {
300
301
  console.log('✅ QR Scanned: ' + result.data);
302
+ this.qrdata.emit(result.data);
301
303
  // Optional: Trigger UI success state
302
304
  this.scanSuccess = true;
303
305
  setTimeout(() => this.scanSuccess = false, 1000);
@@ -1 +0,0 @@
1
- {"hash":"47422515c1b3d9033ccb2632bf917c48eb9485828e444c512f5988ead7b1704d","fesm2022":[{"exports":["NgxCustomQrScannerComponent","NgxCustomQrScannerService"],"facadeModuleId":"/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/ngx-custom-qr-scanner.mjs","isDynamicEntry":false,"isEntry":true,"isImplicitEntry":false,"moduleIds":["/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/lib/ngx-custom-qr-scanner.service.mjs","/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/lib/ngx-custom-qr-scanner.component.mjs","/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/public-api.mjs","/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/ngx-custom-qr-scanner.mjs"],"name":"ngx-custom-qr-scanner","type":"chunk","dynamicImports":[],"fileName":"ngx-custom-qr-scanner.mjs","implicitlyLoadedBefore":[],"importedBindings":{"@angular/core":["*","Injectable","ViewChild","Component"],"@angular/common":["CommonModule","*"],"qr-scanner":["default"]},"imports":["@angular/core","@angular/common","qr-scanner"],"modules":{"/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/lib/ngx-custom-qr-scanner.service.mjs":{"code":"class NgxCustomQrScannerService {\n constructor() { }\n static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });\n static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, providedIn: 'root' });\n}\ni0.ɵɵngDeclareClassMetadata({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, decorators: [{\n type: Injectable,\n args: [{\n providedIn: 'root'\n }]\n }], ctorParameters: () => [] });","originalLength":1557,"removedExports":[],"renderedExports":["NgxCustomQrScannerService"],"renderedLength":682},"/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/lib/ngx-custom-qr-scanner.component.mjs":{"code":"// Make sure you have installed: npm install qr-scanner\nclass NgxCustomQrScannerComponent {\n videoRef;\n // --- LOGIC STARTS HERE (Preserved exactly as requested) ---\n qrScanner;\n flashOn = false;\n zoom = 1;\n maxZoom = 5;\n scanSuccess = false; // Added this property for UI feedback\n async ngAfterViewInit() {\n this.qrScanner = new QrScanner(this.videoRef.nativeElement, (result) => {\n console.log('✅ QR Scanned: ' + result.data);\n // Optional: Trigger UI success state\n this.scanSuccess = true;\n setTimeout(() => this.scanSuccess = false, 1000);\n }, {\n preferredCamera: 'environment',\n highlightScanRegion: true,\n highlightCodeOutline: true,\n });\n this.qrScanner.setInversionMode('both');\n // Some versions of qr-scanner might not support this method depending on update\n // If it throws error, remove it. Kept as per your original code.\n // this.qrScanner.setInversionMode('both'); \n try {\n await this.qrScanner.start();\n await this.initZoom();\n }\n catch (err) {\n console.error(err);\n }\n }\n async toggleFlash() {\n if (await this.qrScanner.hasFlash()) {\n this.qrScanner.toggleFlash(); // no arguments\n this.flashOn = !this.flashOn;\n }\n }\n getVideoTrack() {\n // Access internal video element securely\n // @ts-ignore\n const video = this.qrScanner.$video;\n if (video?.srcObject instanceof MediaStream) {\n return video.srcObject.getVideoTracks()[0];\n }\n return null;\n }\n async initZoom() {\n const track = this.getVideoTrack();\n if (track) {\n const caps = track.getCapabilities();\n if (caps.zoom) {\n this.maxZoom = caps.zoom.max || 5;\n this.zoom = caps.zoom.min || 1;\n }\n }\n }\n async onZoomChange(event) {\n const value = parseFloat(event.target.value);\n this.zoom = value;\n const track = this.getVideoTrack();\n if (track) {\n const caps = track.getCapabilities();\n if (caps.zoom) {\n // clamp value\n const z = Math.max(caps.zoom.min, Math.min(value, caps.zoom.max));\n await track.applyConstraints({ advanced: [{ zoom: z }] });\n }\n }\n }\n ngOnDestroy() {\n this.qrScanner?.stop();\n this.qrScanner?.destroy();\n }\n static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });\n static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: \"14.0.0\", version: \"19.2.18\", type: NgxCustomQrScannerComponent, isStandalone: true, selector: \"ngx-custom-qr-scanner\", viewQueries: [{ propertyName: \"videoRef\", first: true, predicate: [\"video\"], descendants: true, static: true }], ngImport: i0, template: `\n <div class=\"main-wrapper\">\n \n <header class=\"header-red\">\n <div class=\"logo-box\">\n <span>🖼️</span>\n </div>\n <div class=\"title-text\">TYRE QR SCAN</div>\n </header>\n\n <div class=\"camera-body\">\n <video #video playsinline></video>\n\n <div class=\"scan-overlay\">\n <div class=\"scanner-box\" [class.success]=\"scanSuccess\">\n <div class=\"corner tl\"></div>\n <div class=\"corner tr\"></div>\n <div class=\"corner bl\"></div>\n <div class=\"corner br\"></div>\n <div class=\"laser-line\"></div>\n </div>\n\n <div class=\"hint-toast\">\n Only Tire-care and touch the barcode mount with full interest\n </div>\n </div>\n </div>\n\n <footer class=\"footer-red\">\n \n <div class=\"control-group\">\n <span class=\"label\">Torch</span>\n <button class=\"torch-circle\" \n (click)=\"toggleFlash()\" \n [class.active]=\"flashOn\">\n ⚡\n </button>\n </div>\n\n <div class=\"control-group zoom-group\">\n <div class=\"zoom-header\">\n <span class=\"label\">Zoom Slider</span>\n <span class=\"zoom-val\">{{ zoom | number:'1.0-1' }}x</span>\n </div>\n \n <input type=\"range\" \n class=\"modern-slider\"\n min=\"1\" \n [max]=\"maxZoom\" \n step=\"0.1\" \n [value]=\"zoom\"\n (input)=\"onZoomChange($event)\">\n </div>\n\n </footer>\n\n </div>\n `, isInline: true, styles: [\":host{display:block;margin:0;padding:0;font-family:Inter,Segoe UI,sans-serif}.main-wrapper{display:flex;flex-direction:column;height:100dvh;width:100%;background:#000;overflow:hidden}.header-red{height:60px;background:#e61e25;display:flex;align-items:center;padding:0 15px;gap:15px;z-index:10;box-shadow:0 2px 10px #0000004d}.logo-box{width:36px;height:36px;border:2px solid white;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.2rem}.title-text{color:#fff;font-weight:800;letter-spacing:2px;font-size:1.1rem;white-space:nowrap}.camera-body{flex:1;position:relative;background:#000;overflow:hidden}video{width:100%;height:100%;object-fit:cover}.scan-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0000001a}.scanner-box{width:260px;height:200px;position:relative;box-shadow:0 0 0 9999px #00000080;border-radius:12px}.scanner-box.success{box-shadow:0 0 0 9999px #00000080,inset 0 0 30px #0f9;border-color:#0f9}.corner{position:absolute;width:30px;height:30px;border:4px solid #fff}.tl{top:-2px;left:-2px;border-right:0;border-bottom:0}.tr{top:-2px;right:-2px;border-left:0;border-bottom:0}.bl{bottom:-2px;left:-2px;border-right:0;border-top:0}.br{bottom:-2px;right:-2px;border-left:0;border-top:0}.laser-line{width:100%;height:2px;background:#0ff;position:absolute;top:50%;box-shadow:0 0 10px #0ff;animation:scan 2s infinite ease-in-out}@keyframes scan{0%,to{top:10%;opacity:.5}50%{top:90%;opacity:1}}.hint-toast{margin-top:30px;background:#ffffff40;backdrop-filter:blur(8px);padding:10px 20px;border-radius:20px;color:#fff;font-size:.85rem;text-align:center;max-width:80%;text-shadow:0 1px 2px rgba(0,0,0,.5)}.footer-red{background:#e61e25;padding:15px 20px 35px;display:flex;align-items:center;justify-content:space-between;gap:20px;z-index:10}.control-group{display:flex;flex-direction:column;align-items:center;gap:8px;color:#fff}.zoom-group{flex:1;align-items:stretch;padding-left:10px}.label{font-size:.75rem;font-weight:700;text-transform:uppercase;opacity:.9}.torch-circle{width:50px;height:50px;border-radius:50%;border:2px solid white;background:#ffffff1a;color:#fff;font-size:1.4rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.torch-circle.active{background:#fff;color:#e61e25;box-shadow:0 0 15px #ffffff80}.zoom-header{display:flex;justify-content:space-between;margin-bottom:5px}.zoom-val{font-weight:700;font-size:.9rem}.modern-slider{-webkit-appearance:none;width:100%;height:6px;background:#0003;border-radius:3px;outline:none}.modern-slider::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;background:#fff;border-radius:50%;cursor:pointer;box-shadow:0 2px 5px #0000004d}\\n\"], dependencies: [{ kind: \"ngmodule\", type: CommonModule }, { kind: \"pipe\", type: i1.DecimalPipe, name: \"number\" }] });\n}\ni0.ɵɵngDeclareClassMetadata({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerComponent, decorators: [{\n type: Component,\n args: [{ selector: 'ngx-custom-qr-scanner', standalone: true, imports: [CommonModule], template: `\n <div class=\"main-wrapper\">\n \n <header class=\"header-red\">\n <div class=\"logo-box\">\n <span>🖼️</span>\n </div>\n <div class=\"title-text\">TYRE QR SCAN</div>\n </header>\n\n <div class=\"camera-body\">\n <video #video playsinline></video>\n\n <div class=\"scan-overlay\">\n <div class=\"scanner-box\" [class.success]=\"scanSuccess\">\n <div class=\"corner tl\"></div>\n <div class=\"corner tr\"></div>\n <div class=\"corner bl\"></div>\n <div class=\"corner br\"></div>\n <div class=\"laser-line\"></div>\n </div>\n\n <div class=\"hint-toast\">\n Only Tire-care and touch the barcode mount with full interest\n </div>\n </div>\n </div>\n\n <footer class=\"footer-red\">\n \n <div class=\"control-group\">\n <span class=\"label\">Torch</span>\n <button class=\"torch-circle\" \n (click)=\"toggleFlash()\" \n [class.active]=\"flashOn\">\n ⚡\n </button>\n </div>\n\n <div class=\"control-group zoom-group\">\n <div class=\"zoom-header\">\n <span class=\"label\">Zoom Slider</span>\n <span class=\"zoom-val\">{{ zoom | number:'1.0-1' }}x</span>\n </div>\n \n <input type=\"range\" \n class=\"modern-slider\"\n min=\"1\" \n [max]=\"maxZoom\" \n step=\"0.1\" \n [value]=\"zoom\"\n (input)=\"onZoomChange($event)\">\n </div>\n\n </footer>\n\n </div>\n `, styles: [\":host{display:block;margin:0;padding:0;font-family:Inter,Segoe UI,sans-serif}.main-wrapper{display:flex;flex-direction:column;height:100dvh;width:100%;background:#000;overflow:hidden}.header-red{height:60px;background:#e61e25;display:flex;align-items:center;padding:0 15px;gap:15px;z-index:10;box-shadow:0 2px 10px #0000004d}.logo-box{width:36px;height:36px;border:2px solid white;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.2rem}.title-text{color:#fff;font-weight:800;letter-spacing:2px;font-size:1.1rem;white-space:nowrap}.camera-body{flex:1;position:relative;background:#000;overflow:hidden}video{width:100%;height:100%;object-fit:cover}.scan-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0000001a}.scanner-box{width:260px;height:200px;position:relative;box-shadow:0 0 0 9999px #00000080;border-radius:12px}.scanner-box.success{box-shadow:0 0 0 9999px #00000080,inset 0 0 30px #0f9;border-color:#0f9}.corner{position:absolute;width:30px;height:30px;border:4px solid #fff}.tl{top:-2px;left:-2px;border-right:0;border-bottom:0}.tr{top:-2px;right:-2px;border-left:0;border-bottom:0}.bl{bottom:-2px;left:-2px;border-right:0;border-top:0}.br{bottom:-2px;right:-2px;border-left:0;border-top:0}.laser-line{width:100%;height:2px;background:#0ff;position:absolute;top:50%;box-shadow:0 0 10px #0ff;animation:scan 2s infinite ease-in-out}@keyframes scan{0%,to{top:10%;opacity:.5}50%{top:90%;opacity:1}}.hint-toast{margin-top:30px;background:#ffffff40;backdrop-filter:blur(8px);padding:10px 20px;border-radius:20px;color:#fff;font-size:.85rem;text-align:center;max-width:80%;text-shadow:0 1px 2px rgba(0,0,0,.5)}.footer-red{background:#e61e25;padding:15px 20px 35px;display:flex;align-items:center;justify-content:space-between;gap:20px;z-index:10}.control-group{display:flex;flex-direction:column;align-items:center;gap:8px;color:#fff}.zoom-group{flex:1;align-items:stretch;padding-left:10px}.label{font-size:.75rem;font-weight:700;text-transform:uppercase;opacity:.9}.torch-circle{width:50px;height:50px;border-radius:50%;border:2px solid white;background:#ffffff1a;color:#fff;font-size:1.4rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.torch-circle.active{background:#fff;color:#e61e25;box-shadow:0 0 15px #ffffff80}.zoom-header{display:flex;justify-content:space-between;margin-bottom:5px}.zoom-val{font-weight:700;font-size:.9rem}.modern-slider{-webkit-appearance:none;width:100%;height:6px;background:#0003;border-radius:3px;outline:none}.modern-slider::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;background:#fff;border-radius:50%;cursor:pointer;box-shadow:0 2px 5px #0000004d}\\n\"] }]\n }], propDecorators: { videoRef: [{\n type: ViewChild,\n args: ['video', { static: true }]\n }] } });","originalLength":29626,"removedExports":[],"renderedExports":["NgxCustomQrScannerComponent"],"renderedLength":12370},"/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/public-api.mjs":{"code":"/*\n * Public API Surface of ngx-custom-qr-scanner\n */","originalLength":740,"removedExports":[],"renderedExports":[],"renderedLength":53},"/home/user/archive/dist/ngx-custom-qr-scanner/esm2022/ngx-custom-qr-scanner.mjs":{"code":"/**\n * Generated bundle index. Do not edit.\n */","originalLength":540,"removedExports":[],"renderedExports":[],"renderedLength":47}},"referencedFiles":[],"code":"import * as i0 from '@angular/core';\nimport { Injectable, ViewChild, Component } from '@angular/core';\nimport * as i1 from '@angular/common';\nimport { CommonModule } from '@angular/common';\nimport QrScanner from 'qr-scanner';\n\nclass NgxCustomQrScannerService {\n constructor() { }\n static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });\n static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, providedIn: 'root' });\n}\ni0.ɵɵngDeclareClassMetadata({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerService, decorators: [{\n type: Injectable,\n args: [{\n providedIn: 'root'\n }]\n }], ctorParameters: () => [] });\n\n// Make sure you have installed: npm install qr-scanner\nclass NgxCustomQrScannerComponent {\n videoRef;\n // --- LOGIC STARTS HERE (Preserved exactly as requested) ---\n qrScanner;\n flashOn = false;\n zoom = 1;\n maxZoom = 5;\n scanSuccess = false; // Added this property for UI feedback\n async ngAfterViewInit() {\n this.qrScanner = new QrScanner(this.videoRef.nativeElement, (result) => {\n console.log('✅ QR Scanned: ' + result.data);\n // Optional: Trigger UI success state\n this.scanSuccess = true;\n setTimeout(() => this.scanSuccess = false, 1000);\n }, {\n preferredCamera: 'environment',\n highlightScanRegion: true,\n highlightCodeOutline: true,\n });\n this.qrScanner.setInversionMode('both');\n // Some versions of qr-scanner might not support this method depending on update\n // If it throws error, remove it. Kept as per your original code.\n // this.qrScanner.setInversionMode('both'); \n try {\n await this.qrScanner.start();\n await this.initZoom();\n }\n catch (err) {\n console.error(err);\n }\n }\n async toggleFlash() {\n if (await this.qrScanner.hasFlash()) {\n this.qrScanner.toggleFlash(); // no arguments\n this.flashOn = !this.flashOn;\n }\n }\n getVideoTrack() {\n // Access internal video element securely\n // @ts-ignore\n const video = this.qrScanner.$video;\n if (video?.srcObject instanceof MediaStream) {\n return video.srcObject.getVideoTracks()[0];\n }\n return null;\n }\n async initZoom() {\n const track = this.getVideoTrack();\n if (track) {\n const caps = track.getCapabilities();\n if (caps.zoom) {\n this.maxZoom = caps.zoom.max || 5;\n this.zoom = caps.zoom.min || 1;\n }\n }\n }\n async onZoomChange(event) {\n const value = parseFloat(event.target.value);\n this.zoom = value;\n const track = this.getVideoTrack();\n if (track) {\n const caps = track.getCapabilities();\n if (caps.zoom) {\n // clamp value\n const z = Math.max(caps.zoom.min, Math.min(value, caps.zoom.max));\n await track.applyConstraints({ advanced: [{ zoom: z }] });\n }\n }\n }\n ngOnDestroy() {\n this.qrScanner?.stop();\n this.qrScanner?.destroy();\n }\n static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });\n static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: \"14.0.0\", version: \"19.2.18\", type: NgxCustomQrScannerComponent, isStandalone: true, selector: \"ngx-custom-qr-scanner\", viewQueries: [{ propertyName: \"videoRef\", first: true, predicate: [\"video\"], descendants: true, static: true }], ngImport: i0, template: `\n <div class=\"main-wrapper\">\n \n <header class=\"header-red\">\n <div class=\"logo-box\">\n <span>🖼️</span>\n </div>\n <div class=\"title-text\">TYRE QR SCAN</div>\n </header>\n\n <div class=\"camera-body\">\n <video #video playsinline></video>\n\n <div class=\"scan-overlay\">\n <div class=\"scanner-box\" [class.success]=\"scanSuccess\">\n <div class=\"corner tl\"></div>\n <div class=\"corner tr\"></div>\n <div class=\"corner bl\"></div>\n <div class=\"corner br\"></div>\n <div class=\"laser-line\"></div>\n </div>\n\n <div class=\"hint-toast\">\n Only Tire-care and touch the barcode mount with full interest\n </div>\n </div>\n </div>\n\n <footer class=\"footer-red\">\n \n <div class=\"control-group\">\n <span class=\"label\">Torch</span>\n <button class=\"torch-circle\" \n (click)=\"toggleFlash()\" \n [class.active]=\"flashOn\">\n ⚡\n </button>\n </div>\n\n <div class=\"control-group zoom-group\">\n <div class=\"zoom-header\">\n <span class=\"label\">Zoom Slider</span>\n <span class=\"zoom-val\">{{ zoom | number:'1.0-1' }}x</span>\n </div>\n \n <input type=\"range\" \n class=\"modern-slider\"\n min=\"1\" \n [max]=\"maxZoom\" \n step=\"0.1\" \n [value]=\"zoom\"\n (input)=\"onZoomChange($event)\">\n </div>\n\n </footer>\n\n </div>\n `, isInline: true, styles: [\":host{display:block;margin:0;padding:0;font-family:Inter,Segoe UI,sans-serif}.main-wrapper{display:flex;flex-direction:column;height:100dvh;width:100%;background:#000;overflow:hidden}.header-red{height:60px;background:#e61e25;display:flex;align-items:center;padding:0 15px;gap:15px;z-index:10;box-shadow:0 2px 10px #0000004d}.logo-box{width:36px;height:36px;border:2px solid white;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.2rem}.title-text{color:#fff;font-weight:800;letter-spacing:2px;font-size:1.1rem;white-space:nowrap}.camera-body{flex:1;position:relative;background:#000;overflow:hidden}video{width:100%;height:100%;object-fit:cover}.scan-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0000001a}.scanner-box{width:260px;height:200px;position:relative;box-shadow:0 0 0 9999px #00000080;border-radius:12px}.scanner-box.success{box-shadow:0 0 0 9999px #00000080,inset 0 0 30px #0f9;border-color:#0f9}.corner{position:absolute;width:30px;height:30px;border:4px solid #fff}.tl{top:-2px;left:-2px;border-right:0;border-bottom:0}.tr{top:-2px;right:-2px;border-left:0;border-bottom:0}.bl{bottom:-2px;left:-2px;border-right:0;border-top:0}.br{bottom:-2px;right:-2px;border-left:0;border-top:0}.laser-line{width:100%;height:2px;background:#0ff;position:absolute;top:50%;box-shadow:0 0 10px #0ff;animation:scan 2s infinite ease-in-out}@keyframes scan{0%,to{top:10%;opacity:.5}50%{top:90%;opacity:1}}.hint-toast{margin-top:30px;background:#ffffff40;backdrop-filter:blur(8px);padding:10px 20px;border-radius:20px;color:#fff;font-size:.85rem;text-align:center;max-width:80%;text-shadow:0 1px 2px rgba(0,0,0,.5)}.footer-red{background:#e61e25;padding:15px 20px 35px;display:flex;align-items:center;justify-content:space-between;gap:20px;z-index:10}.control-group{display:flex;flex-direction:column;align-items:center;gap:8px;color:#fff}.zoom-group{flex:1;align-items:stretch;padding-left:10px}.label{font-size:.75rem;font-weight:700;text-transform:uppercase;opacity:.9}.torch-circle{width:50px;height:50px;border-radius:50%;border:2px solid white;background:#ffffff1a;color:#fff;font-size:1.4rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.torch-circle.active{background:#fff;color:#e61e25;box-shadow:0 0 15px #ffffff80}.zoom-header{display:flex;justify-content:space-between;margin-bottom:5px}.zoom-val{font-weight:700;font-size:.9rem}.modern-slider{-webkit-appearance:none;width:100%;height:6px;background:#0003;border-radius:3px;outline:none}.modern-slider::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;background:#fff;border-radius:50%;cursor:pointer;box-shadow:0 2px 5px #0000004d}\\n\"], dependencies: [{ kind: \"ngmodule\", type: CommonModule }, { kind: \"pipe\", type: i1.DecimalPipe, name: \"number\" }] });\n}\ni0.ɵɵngDeclareClassMetadata({ minVersion: \"12.0.0\", version: \"19.2.18\", ngImport: i0, type: NgxCustomQrScannerComponent, decorators: [{\n type: Component,\n args: [{ selector: 'ngx-custom-qr-scanner', standalone: true, imports: [CommonModule], template: `\n <div class=\"main-wrapper\">\n \n <header class=\"header-red\">\n <div class=\"logo-box\">\n <span>🖼️</span>\n </div>\n <div class=\"title-text\">TYRE QR SCAN</div>\n </header>\n\n <div class=\"camera-body\">\n <video #video playsinline></video>\n\n <div class=\"scan-overlay\">\n <div class=\"scanner-box\" [class.success]=\"scanSuccess\">\n <div class=\"corner tl\"></div>\n <div class=\"corner tr\"></div>\n <div class=\"corner bl\"></div>\n <div class=\"corner br\"></div>\n <div class=\"laser-line\"></div>\n </div>\n\n <div class=\"hint-toast\">\n Only Tire-care and touch the barcode mount with full interest\n </div>\n </div>\n </div>\n\n <footer class=\"footer-red\">\n \n <div class=\"control-group\">\n <span class=\"label\">Torch</span>\n <button class=\"torch-circle\" \n (click)=\"toggleFlash()\" \n [class.active]=\"flashOn\">\n ⚡\n </button>\n </div>\n\n <div class=\"control-group zoom-group\">\n <div class=\"zoom-header\">\n <span class=\"label\">Zoom Slider</span>\n <span class=\"zoom-val\">{{ zoom | number:'1.0-1' }}x</span>\n </div>\n \n <input type=\"range\" \n class=\"modern-slider\"\n min=\"1\" \n [max]=\"maxZoom\" \n step=\"0.1\" \n [value]=\"zoom\"\n (input)=\"onZoomChange($event)\">\n </div>\n\n </footer>\n\n </div>\n `, styles: [\":host{display:block;margin:0;padding:0;font-family:Inter,Segoe UI,sans-serif}.main-wrapper{display:flex;flex-direction:column;height:100dvh;width:100%;background:#000;overflow:hidden}.header-red{height:60px;background:#e61e25;display:flex;align-items:center;padding:0 15px;gap:15px;z-index:10;box-shadow:0 2px 10px #0000004d}.logo-box{width:36px;height:36px;border:2px solid white;display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.2rem}.title-text{color:#fff;font-weight:800;letter-spacing:2px;font-size:1.1rem;white-space:nowrap}.camera-body{flex:1;position:relative;background:#000;overflow:hidden}video{width:100%;height:100%;object-fit:cover}.scan-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#0000001a}.scanner-box{width:260px;height:200px;position:relative;box-shadow:0 0 0 9999px #00000080;border-radius:12px}.scanner-box.success{box-shadow:0 0 0 9999px #00000080,inset 0 0 30px #0f9;border-color:#0f9}.corner{position:absolute;width:30px;height:30px;border:4px solid #fff}.tl{top:-2px;left:-2px;border-right:0;border-bottom:0}.tr{top:-2px;right:-2px;border-left:0;border-bottom:0}.bl{bottom:-2px;left:-2px;border-right:0;border-top:0}.br{bottom:-2px;right:-2px;border-left:0;border-top:0}.laser-line{width:100%;height:2px;background:#0ff;position:absolute;top:50%;box-shadow:0 0 10px #0ff;animation:scan 2s infinite ease-in-out}@keyframes scan{0%,to{top:10%;opacity:.5}50%{top:90%;opacity:1}}.hint-toast{margin-top:30px;background:#ffffff40;backdrop-filter:blur(8px);padding:10px 20px;border-radius:20px;color:#fff;font-size:.85rem;text-align:center;max-width:80%;text-shadow:0 1px 2px rgba(0,0,0,.5)}.footer-red{background:#e61e25;padding:15px 20px 35px;display:flex;align-items:center;justify-content:space-between;gap:20px;z-index:10}.control-group{display:flex;flex-direction:column;align-items:center;gap:8px;color:#fff}.zoom-group{flex:1;align-items:stretch;padding-left:10px}.label{font-size:.75rem;font-weight:700;text-transform:uppercase;opacity:.9}.torch-circle{width:50px;height:50px;border-radius:50%;border:2px solid white;background:#ffffff1a;color:#fff;font-size:1.4rem;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s}.torch-circle.active{background:#fff;color:#e61e25;box-shadow:0 0 15px #ffffff80}.zoom-header{display:flex;justify-content:space-between;margin-bottom:5px}.zoom-val{font-weight:700;font-size:.9rem}.modern-slider{-webkit-appearance:none;width:100%;height:6px;background:#0003;border-radius:3px;outline:none}.modern-slider::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;background:#fff;border-radius:50%;cursor:pointer;box-shadow:0 2px 5px #0000004d}\\n\"] }]\n }], propDecorators: { videoRef: [{\n type: ViewChild,\n args: ['video', { static: true }]\n }] } });\n\n/*\n * Public API Surface of ngx-custom-qr-scanner\n */\n\n/**\n * Generated bundle index. Do not edit.\n */\n\nexport { NgxCustomQrScannerComponent, NgxCustomQrScannerService };\n//# sourceMappingURL=ngx-custom-qr-scanner.mjs.map\n","map":null,"preliminaryFileName":"ngx-custom-qr-scanner.mjs","sourcemapFileName":"ngx-custom-qr-scanner.mjs.map"},{"fileName":"ngx-custom-qr-scanner.mjs.map","names":[],"needsCodeReference":false,"originalFileName":null,"originalFileNames":[],"source":"{\"version\":3,\"file\":\"ngx-custom-qr-scanner.mjs\",\"sources\":[\"../../../projects/ngx-custom-qr-scanner/src/lib/ngx-custom-qr-scanner.service.ts\",\"../../../projects/ngx-custom-qr-scanner/src/lib/ngx-custom-qr-scanner.component.ts\",\"../../../projects/ngx-custom-qr-scanner/src/public-api.ts\",\"../../../projects/ngx-custom-qr-scanner/src/ngx-custom-qr-scanner.ts\"],\"sourcesContent\":[\"import { Injectable } from '@angular/core';\\n\\n@Injectable({\\n providedIn: 'root'\\n})\\nexport class NgxCustomQrScannerService {\\n\\n constructor() { }\\n}\\n\",\"import { Component, AfterViewInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';\\nimport { CommonModule } from '@angular/common';\\nimport QrScanner from 'qr-scanner'; \\n// Make sure you have installed: npm install qr-scanner\\n\\n@Component({\\n selector: 'ngx-custom-qr-scanner',\\n standalone: true,\\n imports: [CommonModule],\\n template: `\\n <div class=\\\"main-wrapper\\\">\\n \\n <header class=\\\"header-red\\\">\\n <div class=\\\"logo-box\\\">\\n <span>🖼️</span>\\n </div>\\n <div class=\\\"title-text\\\">TYRE QR SCAN</div>\\n </header>\\n\\n <div class=\\\"camera-body\\\">\\n <video #video playsinline></video>\\n\\n <div class=\\\"scan-overlay\\\">\\n <div class=\\\"scanner-box\\\" [class.success]=\\\"scanSuccess\\\">\\n <div class=\\\"corner tl\\\"></div>\\n <div class=\\\"corner tr\\\"></div>\\n <div class=\\\"corner bl\\\"></div>\\n <div class=\\\"corner br\\\"></div>\\n <div class=\\\"laser-line\\\"></div>\\n </div>\\n\\n <div class=\\\"hint-toast\\\">\\n Only Tire-care and touch the barcode mount with full interest\\n </div>\\n </div>\\n </div>\\n\\n <footer class=\\\"footer-red\\\">\\n \\n <div class=\\\"control-group\\\">\\n <span class=\\\"label\\\">Torch</span>\\n <button class=\\\"torch-circle\\\" \\n (click)=\\\"toggleFlash()\\\" \\n [class.active]=\\\"flashOn\\\">\\n ⚡\\n </button>\\n </div>\\n\\n <div class=\\\"control-group zoom-group\\\">\\n <div class=\\\"zoom-header\\\">\\n <span class=\\\"label\\\">Zoom Slider</span>\\n <span class=\\\"zoom-val\\\">{{ zoom | number:'1.0-1' }}x</span>\\n </div>\\n \\n <input type=\\\"range\\\" \\n class=\\\"modern-slider\\\"\\n min=\\\"1\\\" \\n [max]=\\\"maxZoom\\\" \\n step=\\\"0.1\\\" \\n [value]=\\\"zoom\\\"\\n (input)=\\\"onZoomChange($event)\\\">\\n </div>\\n\\n </footer>\\n\\n </div>\\n `,\\n styles: [`\\n /* Global Reset for this component */\\n :host {\\n display: block;\\n margin: 0;\\n padding: 0;\\n font-family: 'Inter', 'Segoe UI', sans-serif;\\n }\\n\\n /* MAIN LAYOUT CONTAINER \\n Uses 100dvh (Dynamic Height) to fix the \\\"cut off\\\" issue on mobile \\n */\\n .main-wrapper {\\n display: flex;\\n flex-direction: column;\\n height: 100dvh; \\n width: 100%;\\n background: black;\\n overflow: hidden;\\n }\\n\\n /* --- HEADER STYLES --- */\\n .header-red {\\n height: 60px;\\n background: #e61e25; /* Match your red */\\n display: flex;\\n align-items: center;\\n padding: 0 15px;\\n gap: 15px;\\n z-index: 10;\\n box-shadow: 0 2px 10px rgba(0,0,0,0.3);\\n }\\n\\n .logo-box {\\n width: 36px;\\n height: 36px;\\n border: 2px solid white;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n color: white;\\n font-size: 1.2rem;\\n }\\n\\n .title-text {\\n color: white;\\n font-weight: 800;\\n letter-spacing: 2px;\\n font-size: 1.1rem;\\n white-space: nowrap;\\n }\\n\\n /* --- CAMERA BODY STYLES --- */\\n .camera-body {\\n flex: 1; /* Fills all available space between header and footer */\\n position: relative;\\n background: #000;\\n overflow: hidden;\\n }\\n\\n video {\\n width: 100%;\\n height: 100%;\\n object-fit: cover;\\n }\\n\\n .scan-overlay {\\n position: absolute;\\n inset: 0;\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n background: rgba(0,0,0,0.1); /* Slight dim */\\n }\\n\\n /* Viewfinder Rectangle */\\n .scanner-box {\\n width: 260px;\\n height: 200px;\\n position: relative;\\n box-shadow: 0 0 0 9999px rgba(0,0,0,0.5); /* Darken outside */\\n border-radius: 12px;\\n }\\n\\n .scanner-box.success {\\n box-shadow: 0 0 0 9999px rgba(0,0,0,0.5), inset 0 0 30px #00ff99;\\n border-color: #00ff99;\\n }\\n\\n /* Corners */\\n .corner {\\n position: absolute;\\n width: 30px;\\n height: 30px;\\n border: 4px solid #fff;\\n }\\n .tl { top: -2px; left: -2px; border-right: 0; border-bottom: 0; }\\n .tr { top: -2px; right: -2px; border-left: 0; border-bottom: 0; }\\n .bl { bottom: -2px; left: -2px; border-right: 0; border-top: 0; }\\n .br { bottom: -2px; right: -2px; border-left: 0; border-top: 0; }\\n\\n /* Laser Line Animation */\\n .laser-line {\\n width: 100%;\\n height: 2px;\\n background: #00ffff;\\n position: absolute;\\n top: 50%;\\n box-shadow: 0 0 10px #00ffff;\\n animation: scan 2s infinite ease-in-out;\\n }\\n\\n @keyframes scan {\\n 0%, 100% { top: 10%; opacity: 0.5; }\\n 50% { top: 90%; opacity: 1; }\\n }\\n\\n .hint-toast {\\n margin-top: 30px;\\n background: rgba(255,255,255,0.25);\\n backdrop-filter: blur(8px);\\n padding: 10px 20px;\\n border-radius: 20px;\\n color: white;\\n font-size: 0.85rem;\\n text-align: center;\\n max-width: 80%;\\n text-shadow: 0 1px 2px rgba(0,0,0,0.5);\\n }\\n\\n /* --- FOOTER STYLES --- */\\n .footer-red {\\n background: #e61e25;\\n /* Padding bottom ensures content isn't covered by iPhone home bar */\\n padding: 15px 20px 35px 20px; \\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 20px;\\n z-index: 10;\\n }\\n\\n .control-group {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n gap: 8px;\\n color: white;\\n }\\n\\n .zoom-group {\\n flex: 1; /* Slider takes remaining width */\\n align-items: stretch;\\n padding-left: 10px;\\n }\\n\\n .label {\\n font-size: 0.75rem;\\n font-weight: 700;\\n text-transform: uppercase;\\n opacity: 0.9;\\n }\\n\\n /* Torch Button */\\n .torch-circle {\\n width: 50px;\\n height: 50px;\\n border-radius: 50%;\\n border: 2px solid white;\\n background: rgba(255,255,255,0.1);\\n color: white;\\n font-size: 1.4rem;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: pointer;\\n transition: all 0.2s;\\n }\\n\\n .torch-circle.active {\\n background: white;\\n color: #e61e25;\\n box-shadow: 0 0 15px rgba(255,255,255,0.5);\\n }\\n\\n /* Zoom Slider */\\n .zoom-header {\\n display: flex;\\n justify-content: space-between;\\n margin-bottom: 5px;\\n }\\n\\n .zoom-val {\\n font-weight: bold;\\n font-size: 0.9rem;\\n }\\n\\n .modern-slider {\\n -webkit-appearance: none;\\n width: 100%;\\n height: 6px;\\n background: rgba(0,0,0,0.2);\\n border-radius: 3px;\\n outline: none;\\n }\\n\\n .modern-slider::-webkit-slider-thumb {\\n -webkit-appearance: none;\\n width: 20px;\\n height: 20px;\\n background: white;\\n border-radius: 50%;\\n cursor: pointer;\\n box-shadow: 0 2px 5px rgba(0,0,0,0.3);\\n }\\n `]\\n})\\nexport class NgxCustomQrScannerComponent implements AfterViewInit, OnDestroy {\\n @ViewChild('video', { static: true }) videoRef!: ElementRef<HTMLVideoElement>;\\n\\n // --- LOGIC STARTS HERE (Preserved exactly as requested) ---\\n qrScanner!: QrScanner;\\n flashOn = false;\\n zoom = 1;\\n maxZoom = 5;\\n scanSuccess = false; // Added this property for UI feedback\\n\\n async ngAfterViewInit() {\\n this.qrScanner = new QrScanner(\\n this.videoRef.nativeElement,\\n (result: { data: string }) => {\\n console.log('✅ QR Scanned: ' + result.data);\\n // Optional: Trigger UI success state\\n this.scanSuccess = true;\\n setTimeout(() => this.scanSuccess = false, 1000);\\n },\\n {\\n preferredCamera: 'environment',\\n highlightScanRegion: true,\\n highlightCodeOutline: true,\\n }\\n );\\n this.qrScanner.setInversionMode('both');\\n\\n // Some versions of qr-scanner might not support this method depending on update\\n // If it throws error, remove it. Kept as per your original code.\\n // this.qrScanner.setInversionMode('both'); \\n\\n try {\\n await this.qrScanner.start();\\n await this.initZoom();\\n } catch (err) {\\n console.error(err);\\n }\\n }\\n\\n async toggleFlash() {\\n if (await this.qrScanner.hasFlash()) {\\n this.qrScanner.toggleFlash(); // no arguments\\n this.flashOn = !this.flashOn;\\n }\\n }\\n\\n private getVideoTrack(): MediaStreamTrack | null {\\n // Access internal video element securely\\n // @ts-ignore\\n const video: HTMLVideoElement = this.qrScanner.$video;\\n if (video?.srcObject instanceof MediaStream) {\\n return video.srcObject.getVideoTracks()[0];\\n }\\n return null;\\n }\\n\\n async initZoom() {\\n const track = this.getVideoTrack();\\n if (track) {\\n const caps = track.getCapabilities() as any;\\n if (caps.zoom) {\\n this.maxZoom = caps.zoom.max || 5;\\n this.zoom = caps.zoom.min || 1;\\n }\\n }\\n }\\n\\n async onZoomChange(event: any) {\\n const value = parseFloat(event.target.value);\\n this.zoom = value;\\n\\n const track = this.getVideoTrack();\\n if (track) {\\n const caps = track.getCapabilities() as any;\\n if (caps.zoom) {\\n // clamp value\\n const z = Math.max(caps.zoom.min, Math.min(value, caps.zoom.max));\\n await track.applyConstraints({ advanced: [{ zoom: z }] } as any);\\n }\\n }\\n }\\n\\n ngOnDestroy() {\\n this.qrScanner?.stop();\\n this.qrScanner?.destroy();\\n }\\n}\",\"/*\\n * Public API Surface of ngx-custom-qr-scanner\\n */\\n\\nexport * from './lib/ngx-custom-qr-scanner.service';\\nexport * from './lib/ngx-custom-qr-scanner.component';\\n\",\"/**\\n * Generated bundle index. Do not edit.\\n */\\n\\nexport * from './public-api';\\n\"],\"names\":[],\"mappings\":\"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\"}","type":"asset"}]}