ngx-dsxlibrary 2.21.41 → 2.21.42

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.
@@ -1,4 +1,47 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable } from '@angular/core';
3
+ import QRCode from 'qrcode';
4
+
5
+ class QrService {
6
+ /**
7
+ * Genera un código QR como Blob usando qrcode
8
+ * Sin necesidad de llamadas HTTP externas, evita problemas de CORS
9
+ */
10
+ async getQrBlob(textToEncode) {
11
+ try {
12
+ // Genera el QR como Data URL
13
+ const dataUrl = await QRCode.toDataURL(textToEncode, {
14
+ errorCorrectionLevel: 'H',
15
+ type: 'image/png',
16
+ width: 300,
17
+ margin: 1,
18
+ color: {
19
+ dark: '#000000',
20
+ light: '#FFFFFF',
21
+ },
22
+ });
23
+ // Convierte Data URL a Blob
24
+ const response = await fetch(dataUrl);
25
+ return response.blob();
26
+ }
27
+ catch (err) {
28
+ console.error('Error generando QR:', err);
29
+ throw err;
30
+ }
31
+ }
32
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
33
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, providedIn: 'root' });
34
+ }
35
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, decorators: [{
36
+ type: Injectable,
37
+ args: [{
38
+ providedIn: 'root',
39
+ }]
40
+ }] });
41
+
1
42
  /**
2
43
  * Generated bundle index. Do not edit.
3
44
  */
45
+
46
+ export { QrService };
4
47
  //# sourceMappingURL=ngx-dsxlibrary-src-lib-services.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-dsxlibrary-src-lib-services.mjs","sources":["../../../projects/ngx-dsx/src/lib/services/ngx-dsxlibrary-src-lib-services.ts"],"sourcesContent":["/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;AAEG"}
1
+ {"version":3,"file":"ngx-dsxlibrary-src-lib-services.mjs","sources":["../../../projects/ngx-dsx/src/lib/services/src/qr.service.ts","../../../projects/ngx-dsx/src/lib/services/ngx-dsxlibrary-src-lib-services.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\nimport QRCode from 'qrcode';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class QrService {\r\n /**\r\n * Genera un código QR como Blob usando qrcode\r\n * Sin necesidad de llamadas HTTP externas, evita problemas de CORS\r\n */\r\n async getQrBlob(textToEncode: string): Promise<Blob> {\r\n try {\r\n // Genera el QR como Data URL\r\n const dataUrl = await QRCode.toDataURL(textToEncode, {\r\n errorCorrectionLevel: 'H',\r\n type: 'image/png',\r\n width: 300,\r\n margin: 1,\r\n color: {\r\n dark: '#000000',\r\n light: '#FFFFFF',\r\n },\r\n });\r\n\r\n // Convierte Data URL a Blob\r\n const response = await fetch(dataUrl);\r\n return response.blob();\r\n } catch (err) {\r\n console.error('Error generando QR:', err);\r\n throw err;\r\n }\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAMa,SAAS,CAAA;AACpB;;;AAGG;IACH,MAAM,SAAS,CAAC,YAAoB,EAAA;AAClC,QAAA,IAAI;;YAEF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE;AACnD,gBAAA,oBAAoB,EAAE,GAAG;AACzB,gBAAA,IAAI,EAAE,WAAW;AACjB,gBAAA,KAAK,EAAE,GAAG;AACV,gBAAA,MAAM,EAAE,CAAC;AACT,gBAAA,KAAK,EAAE;AACL,oBAAA,IAAI,EAAE,SAAS;AACf,oBAAA,KAAK,EAAE,SAAS;AACjB,iBAAA;AACF,aAAA,CAAC;;AAGF,YAAA,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC;AACrC,YAAA,OAAO,QAAQ,CAAC,IAAI,EAAE;QACxB;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC;AACzC,YAAA,MAAM,GAAG;QACX;IACF;wGA1BW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAT,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,SAAS,cAFR,MAAM,EAAA,CAAA;;4FAEP,SAAS,EAAA,UAAA,EAAA,CAAA;kBAHrB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACLD;;AAEG;;;;"}
@@ -40,6 +40,7 @@ import * as i4 from 'primeng/menubar';
40
40
  import { MenubarModule } from 'primeng/menubar';
41
41
  import { JwtHelperService } from '@auth0/angular-jwt';
42
42
  import { CookieService } from 'ngx-cookie-service';
43
+ import QRCode from 'qrcode';
43
44
  import * as i6 from 'primeng/floatlabel';
44
45
  import { FloatLabelModule } from 'primeng/floatlabel';
45
46
  import * as i7 from 'primeng/password';
@@ -4877,6 +4878,267 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4877
4878
  ], template: "<p-menubar>\r\n <ng-template #start>\r\n <p-image\r\n class=\"ms-15\"\r\n [src]=\"urlLogo()\"\r\n alt=\"Image\"\r\n [width]=\"logoWidth()\"\r\n />\r\n <span class=\"version-text\">{{ appVersion() }}</span>\r\n </ng-template>\r\n <ng-template #end>\r\n <div>\r\n <!-- Datos del usuario -->\r\n <div class=\"navbar-user-info\">\r\n <icon-dsx name=\"verified_user\" class=\"navbar-user-icon\"></icon-dsx>\r\n <div class=\"navbar-user-text\">\r\n <span class=\"navbar-user-name\">\r\n {{ _authorizeService.getTokenValues.userName }}\r\n </span>\r\n <span class=\"navbar-user-role\">\r\n {{ currentRole }}\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <!-- Componente de estado de red -->\r\n <app-network-status></app-network-status>\r\n\r\n <!-- Actualizaci\u00F3n de permisos -->\r\n <p-button\r\n class=\"mr-2\"\r\n label=\"Permisos\"\r\n variant=\"text\"\r\n severity=\"info\"\r\n (click)=\"actualizarSeguridadIT()\"\r\n >\r\n <span class=\"material-symbols-outlined mr-1\">local_police</span>\r\n </p-button>\r\n\r\n <label class=\"ui-switch\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"checked\"\r\n (click)=\"onThemeChange(!checked ? true : false)\"\r\n />\r\n <div class=\"slider\">\r\n <div class=\"circle\"></div>\r\n </div>\r\n </label>\r\n <!-- <p-inputSwitch\r\n [(ngModel)]=\"checked\"\r\n (onChange)=\"onThemeChange($event.checked)\"\r\n ></p-inputSwitch> -->\r\n </div>\r\n </ng-template>\r\n</p-menubar>\r\n", styles: [":host ::ng-deep .p-menubar{display:flex;align-items:center!important;padding:.25rem 1.5rem!important;border-radius:999px;border:1px solid rgba(255,255,255,.2);background:#ffffff1f!important;backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);box-shadow:0 10px 30px #0f172a14;margin-left:4rem;margin-right:2.5rem}:host ::ng-deep .p-menubar-end>*{display:flex;align-items:center}.version-text{font-size:1.3rem;font-family:Montserrat,sans-serif!important;margin-left:.5rem;font-weight:600;background-image:linear-gradient(to right,#38bdf8,#630cb4);-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 2px 4px rgba(0,0,0,.1);padding:.2rem 0}.navbar-user-info{display:flex;align-items:center;gap:.35rem;padding:0 .75rem;border-radius:999px;background-color:#00000005}.navbar-user-icon{font-size:1.1rem;color:#374151}.navbar-user-name{font-size:.8rem;font-weight:500;color:#374151;white-space:nowrap}.navbar-user-text{display:flex;flex-direction:column;line-height:1.1}.navbar-user-role{font-size:.7rem;color:#6b7280;white-space:nowrap}.ui-switch{--switch-bg: rgb(135, 150, 165);--switch-width: 48px;--switch-height: 20px;--circle-diameter: 32px;--circle-bg: rgb(232, 89, 15);--circle-inset: calc((var(--circle-diameter) - var(--switch-height)) / 2)}.ui-switch input{display:none}.slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--switch-width);height:var(--switch-height);background:var(--switch-bg);border-radius:999px;position:relative;cursor:pointer}.slider .circle{top:calc(var(--circle-inset) * -1);left:0;width:var(--circle-diameter);height:var(--circle-diameter);position:absolute;background:var(--circle-bg);border-radius:inherit;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTkuMzA1IDEuNjY3VjMuNzVoMS4zODlWMS42NjdoLTEuMzl6bS00LjcwNyAxLjk1bC0uOTgyLjk4Mkw1LjA5IDYuMDcybC45ODItLjk4Mi0xLjQ3My0xLjQ3M3ptMTAuODAyIDBMMTMuOTI3IDUuMDlsLjk4Mi45ODIgMS40NzMtMS40NzMtLjk4Mi0uOTgyek0xMCA1LjEzOWE0Ljg3MiA0Ljg3MiAwIDAwLTQuODYyIDQuODZBNC44NzIgNC44NzIgMCAwMDEwIDE0Ljg2MiA0Ljg3MiA0Ljg3MiAwIDAwMTQuODYgMTAgNC44NzIgNC44NzIgMCAwMDEwIDUuMTM5em0wIDEuMzg5QTMuNDYyIDMuNDYyIDAgMDExMy40NzEgMTBhMy40NjIgMy40NjIgMCAwMS0zLjQ3MyAzLjQ3MkEzLjQ2MiAzLjQ2MiAwIDAxNi41MjcgMTAgMy40NjIgMy40NjIgMCAwMTEwIDYuNTI4ek0xLjY2NSA5LjMwNXYxLjM5aDIuMDgzdi0xLjM5SDEuNjY2em0xNC41ODMgMHYxLjM5aDIuMDg0di0xLjM5aC0yLjA4NHpNNS4wOSAxMy45MjhMMy42MTYgMTUuNGwuOTgyLjk4MiAxLjQ3My0xLjQ3My0uOTgyLS45ODJ6bTkuODIgMGwtLjk4Mi45ODIgMS40NzMgMS40NzMuOTgyLS45ODItMS40NzMtMS40NzN6TTkuMzA1IDE2LjI1djIuMDgzaDEuMzg5VjE2LjI1aC0xLjM5eiIgLz4KPC9zdmc+);background-repeat:no-repeat;background-position:center center;-webkit-transition:left .15s cubic-bezier(.4,0,.2,1) 0ms,-webkit-transform .15s cubic-bezier(.4,0,.2,1) 0ms;-o-transition:left .15s cubic-bezier(.4,0,.2,1) 0ms,transform .15s cubic-bezier(.4,0,.2,1) 0ms;transition:left .15s cubic-bezier(.4,0,.2,1) 0ms,transform .15s cubic-bezier(.4,0,.2,1) 0ms,-webkit-transform .15s cubic-bezier(.4,0,.2,1) 0ms;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;box-shadow:0 2px 1px -1px #0003,0 1px 1px #00000024,0 1px 3px #0000001f}.slider .circle:before{content:\"\";position:absolute;width:100%;height:100%;background:#ffffffbf;border-radius:inherit;-webkit-transition:all .5s;-o-transition:all .5s;transition:all .5s;opacity:0}.ui-switch input:checked+.slider .circle{left:calc(100% - var(--circle-diameter));background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGZpbGw9IiNmZmYiCiAgICAgICAgZD0iTTQuMiAyLjVsLS43IDEuOC0xLjguNyAxLjguNy43IDEuOC42LTEuOEw2LjcgNWwtMS45LS43LS42LTEuOHptMTUgOC4zYTYuNyA2LjcgMCAxMS02LjYtNi42IDUuOCA1LjggMCAwMDYuNiA2LjZ6IiAvPgo8L3N2Zz4=);background-color:#003892}.ui-switch input:active+.slider .circle:before{-webkit-transition:0s;-o-transition:0s;transition:0s;opacity:1;width:0;height:0}\n"] }]
4878
4879
  }], propDecorators: { appVersion: [{ type: i0.Input, args: [{ isSignal: true, alias: "appVersion", required: false }] }], logoWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoWidth", required: false }] }], urlLogo: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlLogo", required: false }] }] } });
4879
4880
 
4881
+ class QrService {
4882
+ /**
4883
+ * Genera un código QR como Blob usando qrcode
4884
+ * Sin necesidad de llamadas HTTP externas, evita problemas de CORS
4885
+ */
4886
+ async getQrBlob(textToEncode) {
4887
+ try {
4888
+ // Genera el QR como Data URL
4889
+ const dataUrl = await QRCode.toDataURL(textToEncode, {
4890
+ errorCorrectionLevel: 'H',
4891
+ type: 'image/png',
4892
+ width: 300,
4893
+ margin: 1,
4894
+ color: {
4895
+ dark: '#000000',
4896
+ light: '#FFFFFF',
4897
+ },
4898
+ });
4899
+ // Convierte Data URL a Blob
4900
+ const response = await fetch(dataUrl);
4901
+ return response.blob();
4902
+ }
4903
+ catch (err) {
4904
+ console.error('Error generando QR:', err);
4905
+ throw err;
4906
+ }
4907
+ }
4908
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
4909
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, providedIn: 'root' });
4910
+ }
4911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrService, decorators: [{
4912
+ type: Injectable,
4913
+ args: [{
4914
+ providedIn: 'root',
4915
+ }]
4916
+ }] });
4917
+
4918
+ class QrGenerator {
4919
+ qrService = inject(QrService);
4920
+ sanitizer = inject(DomSanitizer);
4921
+ // Inputs del padre
4922
+ codigoQr = input(null, ...(ngDevMode ? [{ debugName: "codigoQr" }] : /* istanbul ignore next */ [])); // Contenido a codificar en el QR
4923
+ labelQr = input('SCAN ME', ...(ngDevMode ? [{ debugName: "labelQr" }] : /* istanbul ignore next */ [])); // Texto del banner inferior
4924
+ // Señales internas (copias escribibles de los inputs)
4925
+ qrImageUrl = signal(null, ...(ngDevMode ? [{ debugName: "qrImageUrl" }] : /* istanbul ignore next */ []));
4926
+ labelText = signal('SCAN ME', ...(ngDevMode ? [{ debugName: "labelText" }] : /* istanbul ignore next */ []));
4927
+ textToEncode = signal('', ...(ngDevMode ? [{ debugName: "textToEncode" }] : /* istanbul ignore next */ []));
4928
+ constructor() {
4929
+ effect(() => {
4930
+ // Sincronizar labelQr → labelText
4931
+ this.labelText.set(this.labelQr());
4932
+ // Sincronizar codigoQr → textToEncode y generar el QR
4933
+ if (this.codigoQr()) {
4934
+ this.textToEncode.set(this.codigoQr());
4935
+ setTimeout(() => this.generateQrCode(), 100);
4936
+ }
4937
+ });
4938
+ }
4939
+ currentRawBlob = null;
4940
+ generateQrCode() {
4941
+ if (!this.textToEncode())
4942
+ return;
4943
+ this.qrService
4944
+ .getQrBlob(this.textToEncode())
4945
+ .then((blob) => {
4946
+ this.currentRawBlob = blob;
4947
+ this.generateDesignImage();
4948
+ })
4949
+ .catch((err) => console.error('Error generando QR:', err));
4950
+ }
4951
+ onLabelChange(value) {
4952
+ this.labelText.set(value);
4953
+ // Regenera la imagen de preview con la nueva etiqueta
4954
+ this.generateDesignImage();
4955
+ }
4956
+ generateDesignImage() {
4957
+ if (!this.currentRawBlob)
4958
+ return;
4959
+ const qrImage = new Image();
4960
+ const qrUrl = URL.createObjectURL(this.currentRawBlob);
4961
+ qrImage.src = qrUrl;
4962
+ qrImage.onload = () => {
4963
+ const qrSize = qrImage.width || 300;
4964
+ const padding = 40;
4965
+ const labelAreaHeight = 70;
4966
+ const canvas = document.createElement('canvas');
4967
+ canvas.width = qrSize + padding * 2;
4968
+ canvas.height = qrSize + labelAreaHeight + padding;
4969
+ const ctx = canvas.getContext('2d');
4970
+ if (!ctx)
4971
+ return;
4972
+ // Fondo blanco
4973
+ ctx.fillStyle = '#FFFFFF';
4974
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
4975
+ // DIBUJAR LAS ESQUINAS DE ENFOQUE
4976
+ ctx.strokeStyle = '#000000';
4977
+ ctx.lineWidth = 5;
4978
+ const lineLength = 25;
4979
+ const xMin = padding - 10;
4980
+ const yMin = padding - 10;
4981
+ const xMax = padding + qrSize + 10;
4982
+ const yMax = padding + qrSize + 10;
4983
+ // Esquinas
4984
+ ctx.beginPath();
4985
+ ctx.moveTo(xMin + lineLength, yMin);
4986
+ ctx.lineTo(xMin, yMin);
4987
+ ctx.lineTo(xMin, yMin + lineLength);
4988
+ ctx.stroke();
4989
+ ctx.beginPath();
4990
+ ctx.moveTo(xMax - lineLength, yMin);
4991
+ ctx.lineTo(xMax, yMin);
4992
+ ctx.lineTo(xMax, yMin + lineLength);
4993
+ ctx.stroke();
4994
+ ctx.beginPath();
4995
+ ctx.moveTo(xMin + lineLength, yMax);
4996
+ ctx.lineTo(xMin, yMax);
4997
+ ctx.lineTo(xMin, yMax - lineLength);
4998
+ ctx.stroke();
4999
+ ctx.beginPath();
5000
+ ctx.moveTo(xMax - lineLength, yMax);
5001
+ ctx.lineTo(xMax, yMax);
5002
+ ctx.lineTo(xMax, yMax - lineLength);
5003
+ ctx.stroke();
5004
+ // Dibujar el código QR
5005
+ ctx.drawImage(qrImage, padding, padding, qrSize, qrSize);
5006
+ // Configuración del banner
5007
+ const rectWidth = qrSize * 0.8;
5008
+ const rectHeight = 45;
5009
+ const rectX = padding + (qrSize - rectWidth) / 2;
5010
+ const rectY = yMax + 20;
5011
+ // Caja negra
5012
+ ctx.fillStyle = '#000000';
5013
+ ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
5014
+ // Triángulo indicador
5015
+ ctx.beginPath();
5016
+ ctx.moveTo(canvas.width / 2, rectY - 8);
5017
+ ctx.lineTo(canvas.width / 2 - 10, rectY);
5018
+ ctx.lineTo(canvas.width / 2 + 10, rectY);
5019
+ ctx.closePath();
5020
+ ctx.fill();
5021
+ // Texto
5022
+ ctx.fillStyle = '#FFFFFF';
5023
+ ctx.font = 'bold 18px sans-serif';
5024
+ ctx.textAlign = 'center';
5025
+ ctx.textBaseline = 'middle';
5026
+ ctx.fillText(this.labelText().toUpperCase(), canvas.width / 2, rectY + rectHeight / 2);
5027
+ // Convertir a URL para mostrar en preview
5028
+ canvas.toBlob((blob) => {
5029
+ if (blob) {
5030
+ const previewUrl = URL.createObjectURL(blob);
5031
+ this.qrImageUrl.set(this.sanitizer.bypassSecurityTrustUrl(previewUrl));
5032
+ }
5033
+ }, 'image/png');
5034
+ };
5035
+ }
5036
+ downloadWithLabel() {
5037
+ if (!this.currentRawBlob)
5038
+ return;
5039
+ const qrImage = new Image();
5040
+ const qrUrl = URL.createObjectURL(this.currentRawBlob);
5041
+ qrImage.src = qrUrl;
5042
+ qrImage.onload = () => {
5043
+ const qrSize = qrImage.width || 300;
5044
+ const padding = 40; // Aumentamos el margen para las esquinas de enfoque
5045
+ const labelAreaHeight = 70;
5046
+ const canvas = document.createElement('canvas');
5047
+ canvas.width = qrSize + padding * 2;
5048
+ canvas.height = qrSize + labelAreaHeight + padding;
5049
+ const ctx = canvas.getContext('2d');
5050
+ if (!ctx)
5051
+ return;
5052
+ // Fondo blanco
5053
+ ctx.fillStyle = '#FFFFFF';
5054
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
5055
+ // DIBUJAR LAS ESQUINAS DE ENFOQUE (Estilo de tu imagen de referencia)
5056
+ ctx.strokeStyle = '#000000'; // Color negro para las líneas de enfoque
5057
+ ctx.lineWidth = 5; // Grosor de las esquinas
5058
+ const lineLength = 25; // Largo de cada segmento de la esquina
5059
+ // Área delimitadora donde se posicionará el QR
5060
+ const xMin = padding - 10;
5061
+ const yMin = padding - 10;
5062
+ const xMax = padding + qrSize + 10;
5063
+ const yMax = padding + qrSize + 10;
5064
+ // Esquina Superior Izquierda
5065
+ ctx.beginPath();
5066
+ ctx.moveTo(xMin + lineLength, yMin);
5067
+ ctx.lineTo(xMin, yMin);
5068
+ ctx.lineTo(xMin, yMin + lineLength);
5069
+ ctx.stroke();
5070
+ // Esquina Superior Derecha
5071
+ ctx.beginPath();
5072
+ ctx.moveTo(xMax - lineLength, yMin);
5073
+ ctx.lineTo(xMax, yMin);
5074
+ ctx.lineTo(xMax, yMin + lineLength);
5075
+ ctx.stroke();
5076
+ // Esquina Inferior Izquierda
5077
+ ctx.beginPath();
5078
+ ctx.moveTo(xMin + lineLength, yMax);
5079
+ ctx.lineTo(xMin, yMax);
5080
+ ctx.lineTo(xMin, yMax + lineLength);
5081
+ ctx.stroke();
5082
+ // Esquina Inferior Derecha
5083
+ ctx.beginPath();
5084
+ ctx.moveTo(xMax - lineLength, yMax);
5085
+ ctx.lineTo(xMax, yMax);
5086
+ ctx.lineTo(xMax, yMax + lineLength);
5087
+ ctx.stroke();
5088
+ // Dibujar el código QR original obtenido desde qrcoder.co.uk
5089
+ ctx.drawImage(qrImage, padding, padding, qrSize, qrSize);
5090
+ // Configuración geométrica de la etiqueta negra inferior
5091
+ const rectWidth = qrSize * 0.8;
5092
+ const rectHeight = 45;
5093
+ const rectX = padding + (qrSize - rectWidth) / 2;
5094
+ const rectY = yMax + 20; // Separado adecuadamente de la línea de enfoque inferior
5095
+ // Dibujar caja contenedora de texto
5096
+ ctx.fillStyle = '#000000';
5097
+ ctx.fillRect(rectX, rectY, rectWidth, rectHeight);
5098
+ // Pequeño triángulo indicador (Flecha superior de la caja)
5099
+ ctx.beginPath();
5100
+ ctx.moveTo(canvas.width / 2, rectY - 8);
5101
+ ctx.lineTo(canvas.width / 2 - 10, rectY);
5102
+ ctx.lineTo(canvas.width / 2 + 10, rectY);
5103
+ ctx.closePath();
5104
+ ctx.fill();
5105
+ // Renderizar Texto de Referencia
5106
+ ctx.fillStyle = '#FFFFFF';
5107
+ ctx.font = 'bold 18px sans-serif';
5108
+ ctx.textAlign = 'center';
5109
+ ctx.textBaseline = 'middle';
5110
+ ctx.fillText(this.labelText().toUpperCase(), canvas.width / 2, rectY + rectHeight / 2);
5111
+ // Conversión final y descarga en JPEG
5112
+ canvas.toBlob((finalBlob) => {
5113
+ if (finalBlob) {
5114
+ const downloadUrl = URL.createObjectURL(finalBlob);
5115
+ const link = document.createElement('a');
5116
+ link.href = downloadUrl;
5117
+ const now = new Date();
5118
+ const timestamp = now.getFullYear().toString() +
5119
+ (now.getMonth() + 1).toString().padStart(2, '0') +
5120
+ now.getDate().toString().padStart(2, '0') +
5121
+ now.getHours().toString().padStart(2, '0') +
5122
+ now.getMinutes().toString().padStart(2, '0') +
5123
+ now.getSeconds().toString().padStart(2, '0');
5124
+ link.download = `qr-${timestamp}.jpg`;
5125
+ document.body.appendChild(link);
5126
+ link.click();
5127
+ document.body.removeChild(link);
5128
+ URL.revokeObjectURL(downloadUrl);
5129
+ URL.revokeObjectURL(qrUrl);
5130
+ }
5131
+ }, 'image/jpeg', 0.95);
5132
+ };
5133
+ }
5134
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrGenerator, deps: [], target: i0.ɵɵFactoryTarget.Component });
5135
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: QrGenerator, isStandalone: true, selector: "dsx-qr-generator", inputs: { codigoQr: { classPropertyName: "codigoQr", publicName: "codigoQr", isSignal: true, isRequired: false, transformFunction: null }, labelQr: { classPropertyName: "labelQr", publicName: "labelQr", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"w-full max-w-xs mx-auto text-center\">\r\n <!-- Encabezado -->\r\n <h2 class=\"text-sm font-semibold text-gray-700 mb-2\">\r\n Generador de C\u00F3digo QR\r\n </h2>\r\n\r\n <!-- Valor recibido como validaci\u00F3n (solo lectura) -->\r\n <p class=\"text-xs text-gray-400 mb-3 truncate\">\r\n <span class=\"font-medium text-gray-500\">Contenido: </span>{{ textToEncode()\r\n }}\r\n </p>\r\n\r\n <!-- Preview del QR con dise\u00F1o -->\r\n @if (qrImageUrl()) {\r\n <div class=\"flex flex-col items-center gap-3\">\r\n <!-- Imagen generada con esquinas y banner -->\r\n <div\r\n class=\"rounded-xl border border-gray-200 bg-white p-1 shadow-md inline-block\"\r\n >\r\n <img\r\n [src]=\"qrImageUrl()\"\r\n alt=\"C\u00F3digo QR\"\r\n class=\"w-44 h-auto block rounded\"\r\n />\r\n </div>\r\n\r\n <!-- Bot\u00F3n descarga -->\r\n <button\r\n style=\"\r\n background: #059669;\r\n color: #fff;\r\n font-size: 0.8rem;\r\n padding: 0.4rem 1rem;\r\n border-radius: 0.5rem;\r\n \"\r\n class=\"font-semibold hover:opacity-90 transition-opacity flex items-center justify-center gap-1\"\r\n (click)=\"downloadWithLabel()\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n style=\"width: 1rem; height: 1rem; flex-shrink: 0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2M7 10l5 5 5-5M12 15V3\"\r\n />\r\n </svg>\r\n Descargar JPEG\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: FormsModule }] });
5136
+ }
5137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: QrGenerator, decorators: [{
5138
+ type: Component,
5139
+ args: [{ selector: 'dsx-qr-generator', imports: [FormsModule], template: "<div class=\"w-full max-w-xs mx-auto text-center\">\r\n <!-- Encabezado -->\r\n <h2 class=\"text-sm font-semibold text-gray-700 mb-2\">\r\n Generador de C\u00F3digo QR\r\n </h2>\r\n\r\n <!-- Valor recibido como validaci\u00F3n (solo lectura) -->\r\n <p class=\"text-xs text-gray-400 mb-3 truncate\">\r\n <span class=\"font-medium text-gray-500\">Contenido: </span>{{ textToEncode()\r\n }}\r\n </p>\r\n\r\n <!-- Preview del QR con dise\u00F1o -->\r\n @if (qrImageUrl()) {\r\n <div class=\"flex flex-col items-center gap-3\">\r\n <!-- Imagen generada con esquinas y banner -->\r\n <div\r\n class=\"rounded-xl border border-gray-200 bg-white p-1 shadow-md inline-block\"\r\n >\r\n <img\r\n [src]=\"qrImageUrl()\"\r\n alt=\"C\u00F3digo QR\"\r\n class=\"w-44 h-auto block rounded\"\r\n />\r\n </div>\r\n\r\n <!-- Bot\u00F3n descarga -->\r\n <button\r\n style=\"\r\n background: #059669;\r\n color: #fff;\r\n font-size: 0.8rem;\r\n padding: 0.4rem 1rem;\r\n border-radius: 0.5rem;\r\n \"\r\n class=\"font-semibold hover:opacity-90 transition-opacity flex items-center justify-center gap-1\"\r\n (click)=\"downloadWithLabel()\"\r\n >\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n style=\"width: 1rem; height: 1rem; flex-shrink: 0\"\r\n fill=\"none\"\r\n viewBox=\"0 0 24 24\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n d=\"M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2M7 10l5 5 5-5M12 15V3\"\r\n />\r\n </svg>\r\n Descargar JPEG\r\n </button>\r\n </div>\r\n }\r\n</div>\r\n" }]
5140
+ }], ctorParameters: () => [], propDecorators: { codigoQr: [{ type: i0.Input, args: [{ isSignal: true, alias: "codigoQr", required: false }] }], labelQr: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelQr", required: false }] }] } });
5141
+
4880
5142
  class TokenPurposeLogin {
4881
5143
  fb = inject(FormBuilder);
4882
5144
  _authorizeService = inject(AuthorizeService);
@@ -7039,5 +7301,5 @@ function minimumAgeValidator(minimumAge, referenceDate) {
7039
7301
  * Generated bundle index. Do not edit.
7040
7302
  */
7041
7303
 
7042
- export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, ArrowNavigationDirective, AuthorizeService, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxButtonComponent, DsxEnableDisable, DsxStatusToggle, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, GTQFormatter, HttpHelpersService, INITIAL_PARAMETERS, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, SWEET_ALERT_THEMES, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, getZeroBasedRolIndex, guardTokenPurposeGuard, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, templateVariablesValidator, validateEnvironmentConfig };
7304
+ export { ACTION_TYPES, AlertaService, AppMessageErrorComponent, ArrowNavigationDirective, AuthorizeService, BaseCRUDService, CACHE_KEYS, CacheService, CssV2Component, DSX_PALETTE, DateIndicator, DocxPreviewComponent, DsxAddToolsModule, DsxButtonComponent, DsxEnableDisable, DsxStatusToggle, DteService, ENVIRONMENT, EndpointService, ErrorHandlerService, FileComponent, GTQFormatter, HttpHelpersService, INITIAL_PARAMETERS, IconDsxComponent, JoinByPipe, JsonHighlightPipe, JsonValuesDebujComponent, JsonViewerComponent, KpicardComponent, LoadingComponent, LoadingLottieComponent, LogoDsxComponent, MasterDetailChangeService, NavbarDsxComponent, NetworkStatusComponent, OnlyRangoPatternDirective, ParameterValuesService, PdfPreviewComponent, PrimeNgModule, QrGenerator, QrService, SWEET_ALERT_THEMES, SecurityService, SelectAllOnFocusDirective, SpinnerLoadingService, TemplateHighlight, TokenPurposeLogin, TruncatePipe, UtilityAddService, asyncExistsValidator, atLeastOneFieldRequiredValidator, chainControlGroups, createCurrencyFormatter, createInitialCache, createTypedCacheProvider, cuiValidator, dateMinMaxValidator, dateRangeValidator, dateRangeValidatorFromTo, developmentEnvironment, getZeroBasedRolIndex, guardTokenPurposeGuard, httpAuthorizeInterceptor, minimumAgeValidator, nitValidator, productionEnvironment, provideEnvironment, templateVariablesValidator, validateEnvironmentConfig };
7043
7305
  //# sourceMappingURL=ngx-dsxlibrary.mjs.map