ngx-dsxlibrary 2.21.40 → 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';
@@ -3397,6 +3398,13 @@ class DsxButtonComponent {
3397
3398
  id = input(undefined, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
3398
3399
  requireIdInput = input(false, ...(ngDevMode ? [{ debugName: "requireIdInput" }] : /* istanbul ignore next */ []));
3399
3400
  requiresIdGreaterThanZero = input(false, ...(ngDevMode ? [{ debugName: "requiresIdGreaterThanZero" }] : /* istanbul ignore next */ []));
3401
+ /**
3402
+ * Modo opcional para `softDelete`:
3403
+ * - `true` => botón "Borrar"
3404
+ * - `false` => botón "Retornar" (activar registro)
3405
+ * - `undefined` => conserva la configuración por defecto
3406
+ */
3407
+ softDeleteMode = input(undefined, ...(ngDevMode ? [{ debugName: "softDeleteMode" }] : /* istanbul ignore next */ []));
3400
3408
  labelOverride = input(undefined, ...(ngDevMode ? [{ debugName: "labelOverride" }] : /* istanbul ignore next */ []));
3401
3409
  tooltipOverride = input(undefined, ...(ngDevMode ? [{ debugName: "tooltipOverride" }] : /* istanbul ignore next */ []));
3402
3410
  iconOverride = input(undefined, ...(ngDevMode ? [{ debugName: "iconOverride" }] : /* istanbul ignore next */ []));
@@ -3510,6 +3518,18 @@ class DsxButtonComponent {
3510
3518
  const cfg = ACTION_CONFIG[this.type()];
3511
3519
  const colorOverride = this.colorOverride();
3512
3520
  const outlinedOverride = this.outlinedOverride();
3521
+ if (this.type() === 'softDelete' && this.softDeleteMode() !== undefined) {
3522
+ const shouldDelete = this.softDeleteMode();
3523
+ return {
3524
+ ...cfg,
3525
+ label: shouldDelete ? 'Borrar' : 'Retornar',
3526
+ tooltip: shouldDelete ? 'Borrar registro' : 'Activar registro',
3527
+ icon: shouldDelete ? 'restore_from_trash' : 'published_with_changes',
3528
+ primeIcon: shouldDelete ? 'pi pi-trash' : 'pi pi-check-circle',
3529
+ colorToken: colorOverride ?? (shouldDelete ? 'warning' : 'success'),
3530
+ outlined: outlinedOverride ?? cfg.outlined,
3531
+ };
3532
+ }
3513
3533
  if (this.type() === 'saveOrUpdate') {
3514
3534
  const currentId = this.getNormalizedId();
3515
3535
  const isUpdate = typeof currentId === 'number' && currentId > 0;
@@ -3536,6 +3556,9 @@ class DsxButtonComponent {
3536
3556
  get icon() {
3537
3557
  return this.iconOverride() ?? this.config.icon;
3538
3558
  }
3559
+ get materialIcon() {
3560
+ return this.icon || 'file_export';
3561
+ }
3539
3562
  get primeIcon() {
3540
3563
  if (this.primeIconOverride()) {
3541
3564
  return this.primeIconOverride();
@@ -3678,15 +3701,15 @@ class DsxButtonComponent {
3678
3701
  return this._paramService.isParameterValue(parameterName, this.parameterExpectedValue(), this.parameterIndex());
3679
3702
  }
3680
3703
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DsxButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3681
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DsxButtonComponent, isStandalone: true, selector: "dsx-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerPath: { classPropertyName: "routerPath", publicName: "routerPath", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconOnlyWidth: { classPropertyName: "iconOnlyWidth", publicName: "iconOnlyWidth", isSignal: true, isRequired: false, transformFunction: null }, raised: { classPropertyName: "raised", publicName: "raised", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, parameterName: { classPropertyName: "parameterName", publicName: "parameterName", isSignal: true, isRequired: false, transformFunction: null }, parameterExpectedValue: { classPropertyName: "parameterExpectedValue", publicName: "parameterExpectedValue", isSignal: true, isRequired: false, transformFunction: null }, parameterIndex: { classPropertyName: "parameterIndex", publicName: "parameterIndex", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, requireIdInput: { classPropertyName: "requireIdInput", publicName: "requireIdInput", isSignal: true, isRequired: false, transformFunction: null }, requiresIdGreaterThanZero: { classPropertyName: "requiresIdGreaterThanZero", publicName: "requiresIdGreaterThanZero", isSignal: true, isRequired: false, transformFunction: null }, labelOverride: { classPropertyName: "labelOverride", publicName: "labelOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipOverride: { classPropertyName: "tooltipOverride", publicName: "tooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, iconOverride: { classPropertyName: "iconOverride", publicName: "iconOverride", isSignal: true, isRequired: false, transformFunction: null }, primeIconOverride: { classPropertyName: "primeIconOverride", publicName: "primeIconOverride", isSignal: true, isRequired: false, transformFunction: null }, colorOverride: { classPropertyName: "colorOverride", publicName: "colorOverride", isSignal: true, isRequired: false, transformFunction: null }, outlinedOverride: { classPropertyName: "outlinedOverride", publicName: "outlinedOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { properties: { "class.dsx-button-compact-host": "this.compactHostClass" } }, ngImport: i0, template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (showButton()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyle\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [raised]=\"isCompactIconButton ? false : raised()\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"primeIcon\"\r\n (click)=\"onButtonClick()\"\r\n></p-button>\r\n}\r\n", styles: [":host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}\n"], dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
3704
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DsxButtonComponent, isStandalone: true, selector: "dsx-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null }, routerPath: { classPropertyName: "routerPath", publicName: "routerPath", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, iconOnly: { classPropertyName: "iconOnly", publicName: "iconOnly", isSignal: true, isRequired: false, transformFunction: null }, iconOnlyWidth: { classPropertyName: "iconOnlyWidth", publicName: "iconOnlyWidth", isSignal: true, isRequired: false, transformFunction: null }, raised: { classPropertyName: "raised", publicName: "raised", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null }, parameterName: { classPropertyName: "parameterName", publicName: "parameterName", isSignal: true, isRequired: false, transformFunction: null }, parameterExpectedValue: { classPropertyName: "parameterExpectedValue", publicName: "parameterExpectedValue", isSignal: true, isRequired: false, transformFunction: null }, parameterIndex: { classPropertyName: "parameterIndex", publicName: "parameterIndex", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, requireIdInput: { classPropertyName: "requireIdInput", publicName: "requireIdInput", isSignal: true, isRequired: false, transformFunction: null }, requiresIdGreaterThanZero: { classPropertyName: "requiresIdGreaterThanZero", publicName: "requiresIdGreaterThanZero", isSignal: true, isRequired: false, transformFunction: null }, softDeleteMode: { classPropertyName: "softDeleteMode", publicName: "softDeleteMode", isSignal: true, isRequired: false, transformFunction: null }, labelOverride: { classPropertyName: "labelOverride", publicName: "labelOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipOverride: { classPropertyName: "tooltipOverride", publicName: "tooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, iconOverride: { classPropertyName: "iconOverride", publicName: "iconOverride", isSignal: true, isRequired: false, transformFunction: null }, primeIconOverride: { classPropertyName: "primeIconOverride", publicName: "primeIconOverride", isSignal: true, isRequired: false, transformFunction: null }, colorOverride: { classPropertyName: "colorOverride", publicName: "colorOverride", isSignal: true, isRequired: false, transformFunction: null }, outlinedOverride: { classPropertyName: "outlinedOverride", publicName: "outlinedOverride", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { properties: { "class.dsx-button-compact-host": "this.compactHostClass" } }, ngImport: i0, template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (showButton()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyle\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [raised]=\"isCompactIconButton ? false : raised()\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined\">{{ materialIcon }}</span>\r\n }\r\n</p-button>\r\n}\r\n", styles: [":host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}\n"], dependencies: [{ kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1$3.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }] });
3682
3705
  }
3683
3706
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DsxButtonComponent, decorators: [{
3684
3707
  type: Component,
3685
- args: [{ selector: 'dsx-button', imports: [Button, TooltipModule], template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (showButton()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyle\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [raised]=\"isCompactIconButton ? false : raised()\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"primeIcon\"\r\n (click)=\"onButtonClick()\"\r\n></p-button>\r\n}\r\n", styles: [":host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}\n"] }]
3708
+ args: [{ selector: 'dsx-button', imports: [Button, TooltipModule], template: "<!--Bot\u00F3n con las configuraciones din\u00E1micas para CRUD -->\r\n@if (showButton()) {\r\n<p-button\r\n [label]=\"buttonLabel\"\r\n [style]=\"buttonStyle\"\r\n [styleClass]=\"buttonStyleClass\"\r\n [pTooltip]=\"tooltip\"\r\n [tooltipDisabled]=\"disabled()\"\r\n tooltipPosition=\"top\"\r\n [raised]=\"isCompactIconButton ? false : raised()\"\r\n [rounded]=\"rounded()\"\r\n [text]=\"isCompactIconButton\"\r\n [size]=\"buttonSize\"\r\n severity=\"secondary\"\r\n [disabled]=\"disabled()\"\r\n [icon]=\"iconOnly() ? primeIcon : undefined\"\r\n (click)=\"onButtonClick()\"\r\n>\r\n @if (!iconOnly()) {\r\n <span class=\"material-symbols-outlined\">{{ materialIcon }}</span>\r\n }\r\n</p-button>\r\n}\r\n", styles: [":host{display:inline-flex;margin-bottom:.25rem}:host.dsx-button-compact-host{margin-bottom:0}:host ::ng-deep .p-button .p-button-label{font-family:Montserrat,Roboto,sans-serif;font-weight:500;letter-spacing:.01em}:host ::ng-deep .p-button.dsx-button-compact{min-height:2rem;padding-block:.2rem}:host ::ng-deep .p-button .material-symbols-outlined.p-button-icon{line-height:1;vertical-align:middle}:host ::ng-deep .p-button.dsx-button-compact .p-button-icon{margin:0;font-size:1.2rem;line-height:1}:host ::ng-deep .p-button.dsx-button-compact .material-symbols-outlined.p-button-icon{font-variation-settings:\"FILL\" 1,\"wght\" 500,\"GRAD\" 0,\"opsz\" 24}:host ::ng-deep .p-button:disabled,:host ::ng-deep .p-button.p-disabled{cursor:not-allowed!important;opacity:.45!important;filter:grayscale(.2) saturate(.75)}:host ::ng-deep .p-button:disabled *,:host ::ng-deep .p-button.p-disabled *{cursor:not-allowed!important}\n"] }]
3686
3709
  }], ctorParameters: () => [], propDecorators: { compactHostClass: [{
3687
3710
  type: HostBinding,
3688
3711
  args: ['class.dsx-button-compact-host']
3689
- }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], routerPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerPath", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], iconOnlyWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnlyWidth", required: false }] }], raised: [{ type: i0.Input, args: [{ isSignal: true, alias: "raised", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], parameterName: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterName", required: false }] }], parameterExpectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterExpectedValue", required: false }] }], parameterIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterIndex", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], requireIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireIdInput", required: false }] }], requiresIdGreaterThanZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiresIdGreaterThanZero", required: false }] }], labelOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelOverride", required: false }] }], tooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipOverride", required: false }] }], iconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOverride", required: false }] }], primeIconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "primeIconOverride", required: false }] }], colorOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorOverride", required: false }] }], outlinedOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "outlinedOverride", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
3712
+ }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], routerPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerPath", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], iconOnlyWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnlyWidth", required: false }] }], raised: [{ type: i0.Input, args: [{ isSignal: true, alias: "raised", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }], parameterName: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterName", required: false }] }], parameterExpectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterExpectedValue", required: false }] }], parameterIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameterIndex", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], requireIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "requireIdInput", required: false }] }], requiresIdGreaterThanZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiresIdGreaterThanZero", required: false }] }], softDeleteMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "softDeleteMode", required: false }] }], labelOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelOverride", required: false }] }], tooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipOverride", required: false }] }], iconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOverride", required: false }] }], primeIconOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "primeIconOverride", required: false }] }], colorOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorOverride", required: false }] }], outlinedOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "outlinedOverride", required: false }] }], action: [{ type: i0.Output, args: ["action"] }] } });
3690
3713
  const ACTION_CONFIG = {
3691
3714
  delete: {
3692
3715
  label: 'Eliminar',
@@ -3739,11 +3762,11 @@ const ACTION_CONFIG = {
3739
3762
  tooltip: 'Salvar datos',
3740
3763
  },
3741
3764
  refresh: {
3742
- label: 'Actualizar',
3743
- icon: 'update',
3765
+ label: 'Refrescar',
3766
+ icon: 'cloud_sync',
3744
3767
  primeIcon: 'pi pi-refresh',
3745
3768
  colorToken: 'info',
3746
- tooltip: 'Recargar datos',
3769
+ tooltip: 'Sincronizar datos',
3747
3770
  },
3748
3771
  create: {
3749
3772
  label: 'Agregar',
@@ -4855,6 +4878,267 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
4855
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"] }]
4856
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 }] }] } });
4857
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
+
4858
5142
  class TokenPurposeLogin {
4859
5143
  fb = inject(FormBuilder);
4860
5144
  _authorizeService = inject(AuthorizeService);
@@ -7017,5 +7301,5 @@ function minimumAgeValidator(minimumAge, referenceDate) {
7017
7301
  * Generated bundle index. Do not edit.
7018
7302
  */
7019
7303
 
7020
- 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 };
7021
7305
  //# sourceMappingURL=ngx-dsxlibrary.mjs.map