@c80/ui 1.0.50 → 1.0.51

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 (43) hide show
  1. package/esm2022/lib/card-level/card-level.component.js +12 -14
  2. package/esm2022/lib/card-level/card-level.component.js.map +1 -1
  3. package/esm2022/lib/icon/icon.component.js +3 -3
  4. package/esm2022/lib/icon/icon.component.js.map +1 -1
  5. package/esm2022/lib/icon/icon.constants.js +71 -13
  6. package/esm2022/lib/icon/icon.constants.js.map +1 -1
  7. package/esm2022/lib/icon/icon.types.js.map +1 -1
  8. package/esm2022/lib/modal/modal.component.js +7 -7
  9. package/esm2022/lib/modal/modal.component.js.map +1 -1
  10. package/esm2022/lib/modal/modal.service.js +2 -2
  11. package/esm2022/lib/modal/modal.service.js.map +1 -1
  12. package/esm2022/lib/select/select.component.js +2 -3
  13. package/esm2022/lib/select/select.component.js.map +1 -1
  14. package/esm2022/lib/snackbar/snackbar.component.js +8 -3
  15. package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
  16. package/esm2022/lib/snackbar/snackbar.service.js +2 -3
  17. package/esm2022/lib/snackbar/snackbar.service.js.map +1 -1
  18. package/esm2022/lib/stat-card/stat-card.component.js +3 -3
  19. package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
  20. package/esm2022/lib/table/table-column-visibility.service.js.map +1 -1
  21. package/esm2022/lib/table/table-crud-state.service.js.map +1 -1
  22. package/esm2022/lib/table/table-data-converter.service.js.map +1 -1
  23. package/esm2022/lib/table/table-data-utils.service.js.map +1 -1
  24. package/esm2022/lib/table/table-selection.service.js.map +1 -1
  25. package/esm2022/lib/table/table.component.js +4 -4
  26. package/esm2022/lib/table/table.component.js.map +1 -1
  27. package/esm2022/lib/table/table.utils.js +2 -2
  28. package/esm2022/lib/table/table.utils.js.map +1 -1
  29. package/lib/card-level/card-level.component.d.ts +4 -5
  30. package/lib/icon/icon.component.d.ts +1 -1
  31. package/lib/icon/icon.constants.d.ts +12 -2
  32. package/lib/icon/icon.types.d.ts +1 -1
  33. package/lib/modal/modal.service.d.ts +1 -1
  34. package/lib/select/select.component.d.ts +2 -2
  35. package/lib/snackbar/snackbar.component.d.ts +1 -0
  36. package/lib/stat-card/stat-card.component.d.ts +1 -1
  37. package/lib/table/table-column-visibility.service.d.ts +1 -1
  38. package/lib/table/table-crud-state.service.d.ts +1 -1
  39. package/lib/table/table-data-converter.service.d.ts +1 -1
  40. package/lib/table/table-data-utils.service.d.ts +1 -1
  41. package/lib/table/table-selection.service.d.ts +1 -1
  42. package/lib/table/table.component.d.ts +3 -3
  43. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { Component, computed, effect, inject } from '@angular/core';
1
+ import { Component, computed, effect, inject, ChangeDetectionStrategy } from '@angular/core';
2
2
  import { ModalService } from './modal.service';
3
3
  import { C80IconComponent } from './../icon';
4
4
  import * as i0 from "@angular/core";
@@ -65,22 +65,22 @@ export class C80ModalComponent {
65
65
  return this.config().type === 'info';
66
66
  }
67
67
  getConfirmText() {
68
- return this.config().confirmText || 'Confirmar';
68
+ return this.config().confirmText ?? 'Confirmar';
69
69
  }
70
70
  getCancelText() {
71
- return this.config().cancelText || 'Cancelar';
71
+ return this.config().cancelText ?? 'Cancelar';
72
72
  }
73
73
  getYesText() {
74
- return this.config().yesText || 'Sí';
74
+ return this.config().yesText ?? 'Sí';
75
75
  }
76
76
  getNoText() {
77
- return this.config().noText || 'No';
77
+ return this.config().noText ?? 'No';
78
78
  }
79
79
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80ModalComponent, isStandalone: true, selector: "c80-modal", ngImport: i0, template: "<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1050;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;border:none;max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid #e5e7eb;background:#f8f9fa}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:#1f2937;line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:#374151;white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:#f8f9fa;border-top:1px solid #e5e7eb}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.8) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes modalFadeOut{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.8) translateY(-20px)}}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }] });
80
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80ModalComponent, isStandalone: true, selector: "c80-modal", ngImport: i0, template: "<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1050;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;border:none;max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid #e5e7eb;background:#f8f9fa}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:#1f2937;line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:#374151;white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:#f8f9fa;border-top:1px solid #e5e7eb}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.8) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes modalFadeOut{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.8) translateY(-20px)}}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
81
81
  }
82
82
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80ModalComponent, decorators: [{
83
83
  type: Component,
84
- args: [{ selector: 'c80-modal', standalone: true, imports: [C80IconComponent], template: "<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1050;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;border:none;max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid #e5e7eb;background:#f8f9fa}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:#1f2937;line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:#374151;white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:#f8f9fa;border-top:1px solid #e5e7eb}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.8) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes modalFadeOut{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.8) translateY(-20px)}}\n"] }]
84
+ args: [{ selector: 'c80-modal', standalone: true, imports: [C80IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1050;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:#fff;border-radius:8px;box-shadow:0 4px 20px #00000026;border:none;max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid #e5e7eb;background:#f8f9fa}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:#1f2937;line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:#374151;white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:#f8f9fa;border-top:1px solid #e5e7eb}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}@keyframes modalFadeIn{0%{opacity:0;transform:scale(.8) translateY(-20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes modalFadeOut{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.8) translateY(-20px)}}\n"] }]
85
85
  }], ctorParameters: () => [] });
86
86
  //# sourceMappingURL=modal.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.component.ts","../../../../../libs/ui/src/lib/modal/modal.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;;AA4B7C,MAAM,OAAO,iBAAiB;IACX,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAE5C,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC;IAC7C,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC;IAC7C,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,qDAAC,CAAC;IAEnD;QACE,MAAM,CAAC,GAAG,EAAE;YACV,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;gBAClB,iDAAiD;gBACjD,UAAU,CAAC,GAAG,EAAE;oBACd,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CACrC,iBAAiB,CACH,CAAC;oBACjB,IAAI,QAAQ,EAAE,CAAC;wBACb,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACnB,CAAC;gBACH,CAAC,EAAE,GAAG,CAAC,CAAC;YACV,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS;QACP,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,IAAI;QACF,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,UAAU;QACR,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC;IACjC,CAAC;IAED,eAAe,CAAC,KAAY;QAC1B,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE,CAAC;YACzC,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,qBAAqB;QACnB,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAClC,QAAQ,WAAW,CAAC,IAAI,EAAE,CAAC;YACzB,KAAK,SAAS;gBACZ,OAAO,aAAa,CAAC;YACvB,KAAK,OAAO;gBACV,OAAO,YAAY,CAAC;YACtB,KAAK,SAAS,CAAC;YACf,KAAK,OAAO;gBACV,OAAO,aAAa,CAAC;YACvB;gBACE,OAAO,UAAU,CAAC;QACtB,CAAC;IACH,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC;IACxC,CAAC;IAED,kBAAkB;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAChC,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,OAAO,CAAC;IACtE,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,KAAK,MAAM,CAAC;IACvC,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,IAAI,WAAW,CAAC;IAClD,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,IAAI,UAAU,CAAC;IAChD,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,IAAI,IAAI,CAAC;IACvC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC;IACtC,CAAC;uGA3FU,iBAAiB;2FAAjB,iBAAiB,qEC9B9B,20DAyCC,ssDDfW,gBAAgB;;2FAIf,iBAAiB;kBAR7B,SAAS;+BAEE,WAAW,cACT,IAAI,WACP,CAAC,gBAAgB,CAAC","sourcesContent":["import { Component, computed, effect, inject } from '@angular/core';\r\nimport { ModalService } from './modal.service';\r\nimport { C80IconComponent } from './../icon';\r\n\r\nexport type ModalType = 'info' | 'confirm' | 'yesNo' | 'warning' | 'error';\r\n\r\nexport interface ModalConfig {\r\n title: string;\r\n message: string;\r\n type?: ModalType;\r\n confirmText?: string;\r\n cancelText?: string;\r\n yesText?: string;\r\n noText?: string;\r\n showCancel?: boolean;\r\n}\r\n\r\nexport interface ModalResult {\r\n action: 'confirm' | 'cancel' | 'yes' | 'no';\r\n confirmed: boolean;\r\n}\r\n\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'c80-modal',\r\n standalone: true,\r\n imports: [C80IconComponent],\r\n templateUrl: './modal.component.html',\r\n styleUrl: './modal.component.scss',\r\n})\r\nexport class C80ModalComponent {\r\n private readonly modalService = inject(ModalService);\r\n\r\n readonly isOpen = this.modalService.modalState.isOpen;\r\n readonly config = this.modalService.modalState.config;\r\n readonly isVisible = computed(() => this.isOpen());\r\n\r\n constructor() {\r\n effect(() => {\r\n if (this.isOpen()) {\r\n // Auto-focus modal when opened for accessibility\r\n setTimeout(() => {\r\n const backdrop = document.querySelector(\r\n '.modal-backdrop'\r\n ) as HTMLElement;\r\n if (backdrop) {\r\n backdrop.focus();\r\n }\r\n }, 100);\r\n }\r\n });\r\n }\r\n\r\n onConfirm() {\r\n this.modalService.handleResult({ action: 'confirm', confirmed: true });\r\n }\r\n\r\n onCancel() {\r\n this.modalService.handleResult({ action: 'cancel', confirmed: false });\r\n }\r\n\r\n onYes() {\r\n this.modalService.handleResult({ action: 'yes', confirmed: true });\r\n }\r\n\r\n onNo() {\r\n this.modalService.handleResult({ action: 'no', confirmed: false });\r\n }\r\n\r\n closeModal() {\r\n this.modalService.closeModal();\r\n }\r\n\r\n onBackdropClick(event: Event) {\r\n if (event.target === event.currentTarget) {\r\n this.closeModal();\r\n }\r\n }\r\n\r\n getPrimaryButtonClass(): string {\r\n const configValue = this.config();\r\n switch (configValue.type) {\r\n case 'warning':\r\n return 'btn-warning';\r\n case 'error':\r\n return 'btn-danger';\r\n case 'confirm':\r\n case 'yesNo':\r\n return 'btn-primary';\r\n default:\r\n return 'btn-info';\r\n }\r\n }\r\n\r\n showYesNoButtons(): boolean {\r\n return this.config().type === 'yesNo';\r\n }\r\n\r\n showConfirmButtons(): boolean {\r\n const type = this.config().type;\r\n return type === 'confirm' || type === 'warning' || type === 'error';\r\n }\r\n\r\n showOkButton(): boolean {\r\n return this.config().type === 'info';\r\n }\r\n\r\n getConfirmText(): string {\r\n return this.config().confirmText || 'Confirmar';\r\n }\r\n\r\n getCancelText(): string {\r\n return this.config().cancelText || 'Cancelar';\r\n }\r\n\r\n getYesText(): string {\r\n return this.config().yesText || 'Sí';\r\n }\r\n\r\n getNoText(): string {\r\n return this.config().noText || 'No';\r\n }\r\n}\r\n","<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}"]}
1
+ {"version":3,"file":"modal.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.component.ts","../../../../../libs/ui/src/lib/modal/modal.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, effect, inject, ChangeDetectionStrategy } from '@angular/core';\nimport { ModalService } from './modal.service';\nimport { C80IconComponent } from './../icon';\n\nexport type ModalType = 'info' | 'confirm' | 'yesNo' | 'warning' | 'error';\n\nexport interface ModalConfig {\n title: string;\n message: string;\n type?: ModalType;\n confirmText?: string;\n cancelText?: string;\n yesText?: string;\n noText?: string;\n showCancel?: boolean;\n}\n\nexport interface ModalResult {\n action: 'confirm' | 'cancel' | 'yes' | 'no';\n confirmed: boolean;\n}\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-modal',\n standalone: true,\n imports: [C80IconComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class C80ModalComponent {\n private readonly modalService = inject(ModalService);\n\n readonly isOpen = this.modalService.modalState.isOpen;\n readonly config = this.modalService.modalState.config;\n readonly isVisible = computed(() => this.isOpen());\n\n constructor() {\n effect(() => {\n if (this.isOpen()) {\n // Auto-focus modal when opened for accessibility\n setTimeout(() => {\n const backdrop = document.querySelector(\n '.modal-backdrop'\n ) as HTMLElement;\n if (backdrop) {\n backdrop.focus();\n }\n }, 100);\n }\n });\n }\n\n onConfirm() {\n this.modalService.handleResult({ action: 'confirm', confirmed: true });\n }\n\n onCancel() {\n this.modalService.handleResult({ action: 'cancel', confirmed: false });\n }\n\n onYes() {\n this.modalService.handleResult({ action: 'yes', confirmed: true });\n }\n\n onNo() {\n this.modalService.handleResult({ action: 'no', confirmed: false });\n }\n\n closeModal() {\n this.modalService.closeModal();\n }\n\n onBackdropClick(event: Event) {\n if (event.target === event.currentTarget) {\n this.closeModal();\n }\n }\n\n getPrimaryButtonClass(): string {\n const configValue = this.config();\n switch (configValue.type) {\n case 'warning':\n return 'btn-warning';\n case 'error':\n return 'btn-danger';\n case 'confirm':\n case 'yesNo':\n return 'btn-primary';\n default:\n return 'btn-info';\n }\n }\n\n showYesNoButtons(): boolean {\n return this.config().type === 'yesNo';\n }\n\n showConfirmButtons(): boolean {\n const type = this.config().type;\n return type === 'confirm' || type === 'warning' || type === 'error';\n }\n\n showOkButton(): boolean {\n return this.config().type === 'info';\n }\n\n getConfirmText(): string {\n return this.config().confirmText ?? 'Confirmar';\n }\n\n getCancelText(): string {\n return this.config().cancelText ?? 'Cancelar';\n }\n\n getYesText(): string {\n return this.config().yesText ?? 'Sí';\n }\n\n getNoText(): string {\n return this.config().noText ?? 'No';\n }\n}\n","<!-- Modal Backdrop -->\r\n@if (isOpen()) {\r\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\r\n\r\n <!-- Modal Container -->\r\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\r\n\r\n <!-- Modal Header -->\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\r\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" />\r\n </div>\r\n\r\n <!-- Modal Body -->\r\n <div class=\"modal-body\">\r\n <p class=\"modal-message\">{{ config().message }}</p>\r\n </div>\r\n\r\n <!-- Modal Footer -->\r\n <div class=\"modal-footer\">\r\n\r\n <!-- Info Modal - Solo OK -->\r\n @if (showOkButton()) {\r\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Yes/No Modal -->\r\n @if (showYesNoButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"secondary\" (iconClick)=\"onNo()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" color=\"primary\" (iconClick)=\"onYes()\" [border]=\"true\" />\r\n }\r\n\r\n <!-- Confirm Modal -->\r\n @if (showConfirmButtons()) {\r\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"secondary\" (iconClick)=\"onCancel()\" [border]=\"true\" />\r\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" color=\"primary\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\r\n }\r\n\r\n </div>\r\n </dialog>\r\n</div>\r\n}"]}
@@ -12,7 +12,7 @@ export class ModalService {
12
12
  isOpen: this.isOpen.asReadonly(),
13
13
  config: this.config.asReadonly(),
14
14
  };
15
- showModal(config) {
15
+ async showModal(config) {
16
16
  this.config.set(config);
17
17
  this.isOpen.set(true);
18
18
  return new Promise((resolve) => {
@@ -37,7 +37,7 @@ export class ModalService {
37
37
  noText,
38
38
  }).then((result) => result.action === 'yes');
39
39
  }
40
- info(title, message) {
40
+ async info(title, message) {
41
41
  return this.showModal({
42
42
  title,
43
43
  message,
@@ -1 +1 @@
1
- {"version":3,"file":"modal.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, signal } from '@angular/core';\r\nimport { ModalConfig, ModalResult } from './modal.component';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ModalService {\r\n private readonly isOpen = signal(false);\r\n private readonly config = signal<ModalConfig>({\r\n title: '',\r\n message: '',\r\n type: 'info',\r\n });\r\n\r\n private resolvePromise?: (result: ModalResult) => void;\r\n\r\n readonly modalState = {\r\n isOpen: this.isOpen.asReadonly(),\r\n config: this.config.asReadonly(),\r\n };\r\n\r\n showModal(config: ModalConfig): Promise<ModalResult> {\r\n this.config.set(config);\r\n this.isOpen.set(true);\r\n\r\n return new Promise<ModalResult>((resolve) => {\r\n this.resolvePromise = resolve;\r\n });\r\n }\r\n\r\n async confirm(\r\n title: string,\r\n message: string,\r\n confirmText = 'Confirmar',\r\n cancelText = 'Cancelar'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'confirm',\r\n confirmText,\r\n cancelText,\r\n }).then((result) => result.confirmed);\r\n }\r\n\r\n async yesNo(\r\n title: string,\r\n message: string,\r\n yesText = 'Sí',\r\n noText = 'No'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'yesNo',\r\n yesText,\r\n noText,\r\n }).then((result) => result.action === 'yes');\r\n }\r\n\r\n info(title: string, message: string): Promise<void> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'info',\r\n }).then(() => void 0);\r\n }\r\n\r\n async warning(\r\n title: string,\r\n message: string,\r\n confirmText = 'Entendido',\r\n cancelText = 'Cancelar'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'warning',\r\n confirmText,\r\n cancelText,\r\n }).then((result) => result.confirmed);\r\n }\r\n\r\n async error(\r\n title: string,\r\n message: string,\r\n confirmText = 'Entendido'\r\n ): Promise<void> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'error',\r\n confirmText,\r\n }).then(() => void 0);\r\n }\r\n\r\n handleResult(result: ModalResult) {\r\n if (this.resolvePromise) {\r\n this.resolvePromise(result);\r\n this.resolvePromise = undefined;\r\n }\r\n this.closeModal();\r\n }\r\n\r\n closeModal() {\r\n this.isOpen.set(false);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"modal.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, signal } from '@angular/core';\r\nimport type { ModalConfig, ModalResult } from './modal.component';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ModalService {\r\n private readonly isOpen = signal(false);\r\n private readonly config = signal<ModalConfig>({\r\n title: '',\r\n message: '',\r\n type: 'info',\r\n });\r\n\r\n private resolvePromise?: (result: ModalResult) => void;\r\n\r\n readonly modalState = {\r\n isOpen: this.isOpen.asReadonly(),\r\n config: this.config.asReadonly(),\r\n };\r\n\r\n async showModal(config: ModalConfig): Promise<ModalResult> {\r\n this.config.set(config);\r\n this.isOpen.set(true);\r\n\r\n return new Promise<ModalResult>((resolve) => {\r\n this.resolvePromise = resolve;\r\n });\r\n }\r\n\r\n async confirm(\r\n title: string,\r\n message: string,\r\n confirmText = 'Confirmar',\r\n cancelText = 'Cancelar'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'confirm',\r\n confirmText,\r\n cancelText,\r\n }).then((result) => result.confirmed);\r\n }\r\n\r\n async yesNo(\r\n title: string,\r\n message: string,\r\n yesText = 'Sí',\r\n noText = 'No'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'yesNo',\r\n yesText,\r\n noText,\r\n }).then((result) => result.action === 'yes');\r\n }\r\n\r\n async info(title: string, message: string): Promise<void> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'info',\r\n }).then(() => void 0);\r\n }\r\n\r\n async warning(\r\n title: string,\r\n message: string,\r\n confirmText = 'Entendido',\r\n cancelText = 'Cancelar'\r\n ): Promise<boolean> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'warning',\r\n confirmText,\r\n cancelText,\r\n }).then((result) => result.confirmed);\r\n }\r\n\r\n async error(\r\n title: string,\r\n message: string,\r\n confirmText = 'Entendido'\r\n ): Promise<void> {\r\n return this.showModal({\r\n title,\r\n message,\r\n type: 'error',\r\n confirmText,\r\n }).then(() => void 0);\r\n }\r\n\r\n handleResult(result: ModalResult) {\r\n if (this.resolvePromise) {\r\n this.resolvePromise(result);\r\n this.resolvePromise = undefined;\r\n }\r\n this.closeModal();\r\n }\r\n\r\n closeModal() {\r\n this.isOpen.set(false);\r\n }\r\n}\r\n"]}
@@ -1,5 +1,4 @@
1
1
  import { ChangeDetectionStrategy, Component, computed, input, output, signal, viewChild } from '@angular/core';
2
- import { NgClass } from '@angular/common';
3
2
  import * as i0 from "@angular/core";
4
3
  let uniqueIdCounter = 0;
5
4
  export class SelectComponent {
@@ -71,10 +70,10 @@ export class SelectComponent {
71
70
  this.searchTerm.set('');
72
71
  }
73
72
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
74
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SelectComponent, isStandalone: true, selector: "c80-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", opened: "opened" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"k-select\" [ngClass]=\"{ 'k-select--disabled': disabled(), 'k-select--open': isOpen() }\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [ngClass]=\"{ 'k-select__value--placeholder': value() === null }\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [ngClass]=\"{ 'k-select__arrow--up': isOpen() }\">\u25BC</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [ngClass]=\"{\n 'k-select__option--selected': option.value === value(),\n 'k-select__option--disabled': option.disabled\n }\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\" (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>", styles: [".k-select{position:relative;width:100%;font-family:inherit}.k-select--disabled{opacity:.6;pointer-events:none}.k-select__control{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;min-height:40px;padding:8px 12px;border:1px solid rgba(0,0,0,.23);border-radius:4px;background-color:#fff;cursor:pointer;transition:all .2s;text-align:left}.k-select__control:hover:not(:disabled){border-color:#000000de}.k-select__control:disabled{cursor:not-allowed;opacity:.6}.k-select--open .k-select__control{border-color:#3f51b5;border-width:2px;padding:7px 11px}.k-select__value{flex:1;font-size:.875rem;color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-select__value--placeholder{color:#00000061}.k-select__arrow{font-size:.5rem;color:#0000008a;transition:transform .2s;margin-left:6px;flex-shrink:0}.k-select__arrow--up{transform:rotate(180deg)}.k-select__backdrop{position:fixed;inset:0;z-index:999;background-color:transparent}.k-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;background-color:#fff;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;z-index:1000;animation:fadeIn .15s ease-out}.k-select__search{position:sticky;top:0;padding:8px;background-color:#fff;border-bottom:1px solid rgba(0,0,0,.12);z-index:1}.k-select__search-input{width:100%;padding:6px 10px;font-size:.875rem;border:1px solid rgba(0,0,0,.23);border-radius:4px;outline:none;transition:border-color .2s}.k-select__search-input:focus{border-color:#3f51b5}.k-select__search-input::placeholder{color:#00000061}.k-select__option{width:100%;padding:8px 12px;font-size:.875rem;color:#000000de;cursor:pointer;transition:background-color .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none;background-color:transparent;text-align:left}.k-select__option:hover:not(.k-select__option--disabled):not(:disabled){background-color:#0000000a}.k-select__option--selected{background-color:#3f51b51f;font-weight:500}.k-select__option--selected:hover:not(:disabled){background-color:#3f51b529}.k-select__option--disabled{color:#00000061;cursor:default}.k-select__option:disabled{cursor:not-allowed;opacity:.6}@keyframes fadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
73
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SelectComponent, isStandalone: true, selector: "c80-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, filterable: { classPropertyName: "filterable", publicName: "filterable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", opened: "opened" }, viewQueries: [{ propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"k-select\" [class.k-select--disabled]=\"disabled()\" [class.k-select--open]=\"isOpen()\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [class.k-select__value--placeholder]=\"value() === null\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [class.k-select__arrow--up]=\"isOpen()\">\u25BC</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [class.k-select__option--selected]=\"option.value === value()\" [class.k-select__option--disabled]=\"option.disabled\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\"\n (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>", styles: [".k-select{position:relative;width:100%;font-family:inherit}.k-select--disabled{opacity:.6;pointer-events:none}.k-select__control{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;min-height:40px;padding:8px 12px;border:1px solid rgba(0,0,0,.23);border-radius:4px;background-color:#fff;cursor:pointer;transition:all .2s;text-align:left}.k-select__control:hover:not(:disabled){border-color:#000000de}.k-select__control:disabled{cursor:not-allowed;opacity:.6}.k-select--open .k-select__control{border-color:#3f51b5;border-width:2px;padding:7px 11px}.k-select__value{flex:1;font-size:.875rem;color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-select__value--placeholder{color:#00000061}.k-select__arrow{font-size:.5rem;color:#0000008a;transition:transform .2s;margin-left:6px;flex-shrink:0}.k-select__arrow--up{transform:rotate(180deg)}.k-select__backdrop{position:fixed;inset:0;z-index:999;background-color:transparent}.k-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;background-color:#fff;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;z-index:1000;animation:fadeIn .15s ease-out}.k-select__search{position:sticky;top:0;padding:8px;background-color:#fff;border-bottom:1px solid rgba(0,0,0,.12);z-index:1}.k-select__search-input{width:100%;padding:6px 10px;font-size:.875rem;border:1px solid rgba(0,0,0,.23);border-radius:4px;outline:none;transition:border-color .2s}.k-select__search-input:focus{border-color:#3f51b5}.k-select__search-input::placeholder{color:#00000061}.k-select__option{width:100%;padding:8px 12px;font-size:.875rem;color:#000000de;cursor:pointer;transition:background-color .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none;background-color:transparent;text-align:left}.k-select__option:hover:not(.k-select__option--disabled):not(:disabled){background-color:#0000000a}.k-select__option--selected{background-color:#3f51b51f;font-weight:500}.k-select__option--selected:hover:not(:disabled){background-color:#3f51b529}.k-select__option--disabled{color:#00000061;cursor:default}.k-select__option:disabled{cursor:not-allowed;opacity:.6}@keyframes fadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
75
74
  }
76
75
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SelectComponent, decorators: [{
77
76
  type: Component,
78
- args: [{ selector: 'c80-select', standalone: true, imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"k-select\" [ngClass]=\"{ 'k-select--disabled': disabled(), 'k-select--open': isOpen() }\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [ngClass]=\"{ 'k-select__value--placeholder': value() === null }\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [ngClass]=\"{ 'k-select__arrow--up': isOpen() }\">\u25BC</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [ngClass]=\"{\n 'k-select__option--selected': option.value === value(),\n 'k-select__option--disabled': option.disabled\n }\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\" (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>", styles: [".k-select{position:relative;width:100%;font-family:inherit}.k-select--disabled{opacity:.6;pointer-events:none}.k-select__control{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;min-height:40px;padding:8px 12px;border:1px solid rgba(0,0,0,.23);border-radius:4px;background-color:#fff;cursor:pointer;transition:all .2s;text-align:left}.k-select__control:hover:not(:disabled){border-color:#000000de}.k-select__control:disabled{cursor:not-allowed;opacity:.6}.k-select--open .k-select__control{border-color:#3f51b5;border-width:2px;padding:7px 11px}.k-select__value{flex:1;font-size:.875rem;color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-select__value--placeholder{color:#00000061}.k-select__arrow{font-size:.5rem;color:#0000008a;transition:transform .2s;margin-left:6px;flex-shrink:0}.k-select__arrow--up{transform:rotate(180deg)}.k-select__backdrop{position:fixed;inset:0;z-index:999;background-color:transparent}.k-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;background-color:#fff;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;z-index:1000;animation:fadeIn .15s ease-out}.k-select__search{position:sticky;top:0;padding:8px;background-color:#fff;border-bottom:1px solid rgba(0,0,0,.12);z-index:1}.k-select__search-input{width:100%;padding:6px 10px;font-size:.875rem;border:1px solid rgba(0,0,0,.23);border-radius:4px;outline:none;transition:border-color .2s}.k-select__search-input:focus{border-color:#3f51b5}.k-select__search-input::placeholder{color:#00000061}.k-select__option{width:100%;padding:8px 12px;font-size:.875rem;color:#000000de;cursor:pointer;transition:background-color .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none;background-color:transparent;text-align:left}.k-select__option:hover:not(.k-select__option--disabled):not(:disabled){background-color:#0000000a}.k-select__option--selected{background-color:#3f51b51f;font-weight:500}.k-select__option--selected:hover:not(:disabled){background-color:#3f51b529}.k-select__option--disabled{color:#00000061;cursor:default}.k-select__option:disabled{cursor:not-allowed;opacity:.6}@keyframes fadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}\n"] }]
77
+ args: [{ selector: 'c80-select', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"k-select\" [class.k-select--disabled]=\"disabled()\" [class.k-select--open]=\"isOpen()\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [class.k-select__value--placeholder]=\"value() === null\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [class.k-select__arrow--up]=\"isOpen()\">\u25BC</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [class.k-select__option--selected]=\"option.value === value()\" [class.k-select__option--disabled]=\"option.disabled\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\"\n (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>", styles: [".k-select{position:relative;width:100%;font-family:inherit}.k-select--disabled{opacity:.6;pointer-events:none}.k-select__control{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;min-height:40px;padding:8px 12px;border:1px solid rgba(0,0,0,.23);border-radius:4px;background-color:#fff;cursor:pointer;transition:all .2s;text-align:left}.k-select__control:hover:not(:disabled){border-color:#000000de}.k-select__control:disabled{cursor:not-allowed;opacity:.6}.k-select--open .k-select__control{border-color:#3f51b5;border-width:2px;padding:7px 11px}.k-select__value{flex:1;font-size:.875rem;color:#000000de;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.k-select__value--placeholder{color:#00000061}.k-select__arrow{font-size:.5rem;color:#0000008a;transition:transform .2s;margin-left:6px;flex-shrink:0}.k-select__arrow--up{transform:rotate(180deg)}.k-select__backdrop{position:fixed;inset:0;z-index:999;background-color:transparent}.k-select__dropdown{position:absolute;top:calc(100% + 4px);left:0;right:0;overflow-y:auto;background-color:#fff;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;z-index:1000;animation:fadeIn .15s ease-out}.k-select__search{position:sticky;top:0;padding:8px;background-color:#fff;border-bottom:1px solid rgba(0,0,0,.12);z-index:1}.k-select__search-input{width:100%;padding:6px 10px;font-size:.875rem;border:1px solid rgba(0,0,0,.23);border-radius:4px;outline:none;transition:border-color .2s}.k-select__search-input:focus{border-color:#3f51b5}.k-select__search-input::placeholder{color:#00000061}.k-select__option{width:100%;padding:8px 12px;font-size:.875rem;color:#000000de;cursor:pointer;transition:background-color .15s;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none;background-color:transparent;text-align:left}.k-select__option:hover:not(.k-select__option--disabled):not(:disabled){background-color:#0000000a}.k-select__option--selected{background-color:#3f51b51f;font-weight:500}.k-select__option--selected:hover:not(:disabled){background-color:#3f51b529}.k-select__option--disabled{color:#00000061;cursor:default}.k-select__option:disabled{cursor:not-allowed;opacity:.6}@keyframes fadeIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}\n"] }]
79
78
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], filterable: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterable", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }] } });
80
79
  //# sourceMappingURL=select.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"select.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/select/select.component.ts","../../../../../libs/ui/src/lib/select/select.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectionStrategy, Component, computed, input, output, signal, viewChild, ElementRef } from '@angular/core';\nimport { NgClass } from '@angular/common';\nimport { SelectOption } from './select.model';\n\nlet uniqueIdCounter = 0;\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-select',\n standalone: true,\n imports: [NgClass],\n templateUrl: './select.component.html',\n styleUrl: './select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SelectComponent<T = string> {\n readonly label = input.required<string>();\n readonly placeholder = input<string>('Seleccionar');\n readonly value = input<T | null>(null);\n readonly options = input<SelectOption<T>[]>([]);\n readonly disabled = input<boolean>(false);\n readonly loading = input<boolean>(false);\n readonly emptyMessage = input<string>('No hay opciones disponibles');\n readonly maxHeight = input<string>('300px');\n readonly filterable = input<boolean>(false);\n\n readonly valueChange = output<T | null>();\n readonly opened = output<void>();\n\n readonly isOpen = signal(false);\n readonly searchTerm = signal<string>('');\n readonly controlId = `c80-select-${++uniqueIdCounter}`;\n readonly searchInput = viewChild<ElementRef<HTMLInputElement>>('searchInput');\n\n readonly filteredOptions = computed(() => {\n const term = this.searchTerm().toLowerCase().trim();\n if (!term || !this.filterable()) {\n return this.options();\n }\n return this.options().filter(opt =>\n opt.label.toLowerCase().includes(term)\n );\n });\n\n toggleDropdown(): void {\n if (this.disabled() || this.loading()) {\n return;\n }\n\n const wasOpen = this.isOpen();\n this.isOpen.set(!wasOpen);\n\n if (wasOpen) {\n this.clearSearch();\n } else {\n this.opened.emit();\n if (this.filterable()) {\n setTimeout(() => this.searchInput()?.nativeElement.focus(), 0);\n }\n }\n }\n\n selectOption(option: SelectOption<T>): void {\n if (option.disabled) {\n return;\n }\n\n this.valueChange.emit(option.value);\n this.isOpen.set(false);\n }\n\n selectNull(): void {\n this.valueChange.emit(null);\n this.isOpen.set(false);\n }\n\n getSelectedLabel(): string {\n const currentValue = this.value();\n if (currentValue === null || currentValue === undefined) {\n return this.placeholder();\n }\n\n const selected = this.options().find(opt => opt.value === currentValue);\n return selected?.label ?? this.placeholder();\n }\n\n closeDropdown(): void {\n this.isOpen.set(false);\n this.clearSearch();\n }\n\n onSearchChange(term: string): void {\n this.searchTerm.set(term);\n }\n\n clearSearch(): void {\n this.searchTerm.set('');\n }\n}\n","<div class=\"k-select\" [ngClass]=\"{ 'k-select--disabled': disabled(), 'k-select--open': isOpen() }\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [ngClass]=\"{ 'k-select__value--placeholder': value() === null }\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [ngClass]=\"{ 'k-select__arrow--up': isOpen() }\">▼</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [ngClass]=\"{\n 'k-select__option--selected': option.value === value(),\n 'k-select__option--disabled': option.disabled\n }\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\" (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>"]}
1
+ {"version":3,"file":"select.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/select/select.component.ts","../../../../../libs/ui/src/lib/select/select.component.html"],"names":[],"mappings":"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","sourcesContent":["import { type ElementRef, ChangeDetectionStrategy, Component, computed, input, output, signal, viewChild } from '@angular/core';\nimport type { SelectOption } from './select.model';\n\nlet uniqueIdCounter = 0;\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-select',\n standalone: true,\n imports: [],\n templateUrl: './select.component.html',\n styleUrl: './select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SelectComponent<T = string> {\n readonly label = input.required<string>();\n readonly placeholder = input<string>('Seleccionar');\n readonly value = input<T | null>(null);\n readonly options = input<SelectOption<T>[]>([]);\n readonly disabled = input<boolean>(false);\n readonly loading = input<boolean>(false);\n readonly emptyMessage = input<string>('No hay opciones disponibles');\n readonly maxHeight = input<string>('300px');\n readonly filterable = input<boolean>(false);\n\n readonly valueChange = output<T | null>();\n readonly opened = output<void>();\n\n readonly isOpen = signal(false);\n readonly searchTerm = signal<string>('');\n readonly controlId = `c80-select-${++uniqueIdCounter}`;\n readonly searchInput = viewChild<ElementRef<HTMLInputElement>>('searchInput');\n\n readonly filteredOptions = computed(() => {\n const term = this.searchTerm().toLowerCase().trim();\n if (!term || !this.filterable()) {\n return this.options();\n }\n return this.options().filter(opt =>\n opt.label.toLowerCase().includes(term)\n );\n });\n\n toggleDropdown(): void {\n if (this.disabled() || this.loading()) {\n return;\n }\n\n const wasOpen = this.isOpen();\n this.isOpen.set(!wasOpen);\n\n if (wasOpen) {\n this.clearSearch();\n } else {\n this.opened.emit();\n if (this.filterable()) {\n setTimeout(() => this.searchInput()?.nativeElement.focus(), 0);\n }\n }\n }\n\n selectOption(option: SelectOption<T>): void {\n if (option.disabled) {\n return;\n }\n\n this.valueChange.emit(option.value);\n this.isOpen.set(false);\n }\n\n selectNull(): void {\n this.valueChange.emit(null);\n this.isOpen.set(false);\n }\n\n getSelectedLabel(): string {\n const currentValue = this.value();\n if (currentValue === null || currentValue === undefined) {\n return this.placeholder();\n }\n\n const selected = this.options().find(opt => opt.value === currentValue);\n return selected?.label ?? this.placeholder();\n }\n\n closeDropdown(): void {\n this.isOpen.set(false);\n this.clearSearch();\n }\n\n onSearchChange(term: string): void {\n this.searchTerm.set(term);\n }\n\n clearSearch(): void {\n this.searchTerm.set('');\n }\n}\n","<div class=\"k-select\" [class.k-select--disabled]=\"disabled()\" [class.k-select--open]=\"isOpen()\">\n <button type=\"button\" class=\"k-select__control\" [attr.id]=\"controlId\" [attr.aria-label]=\"label()\" [attr.aria-expanded]=\"isOpen()\" [disabled]=\"disabled() || loading()\" (click)=\"toggleDropdown()\" (keydown.enter)=\"toggleDropdown()\"\n (keydown.space)=\"$event.preventDefault(); toggleDropdown()\">\n <span class=\"k-select__value\" [class.k-select__value--placeholder]=\"value() === null\">\n @if (loading()) {\n Cargando...\n } @else {\n {{ getSelectedLabel() }}\n }\n </span>\n <span class=\"k-select__arrow\" [class.k-select__arrow--up]=\"isOpen()\">▼</span>\n </button>\n\n @if (isOpen()) {\n <div class=\"k-select__backdrop\" tabindex=\"-1\" (click)=\"closeDropdown()\" (keydown.escape)=\"closeDropdown()\"></div>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"k-select__dropdown\" [style.max-height]=\"maxHeight()\">\n @if (filterable()) {\n <div class=\"k-select__search\">\n <input type=\"text\" class=\"k-select__search-input\" [value]=\"searchTerm()\" (input)=\"onSearchChange($any($event.target).value)\" placeholder=\"Buscar...\" (click)=\"$event.stopPropagation()\" (keydown.escape)=\"closeDropdown()\" #searchInput />\n </div>\n }\n\n <button type=\"button\" class=\"k-select__option\" (click)=\"selectNull()\" (keydown.enter)=\"selectNull()\">\n -- {{ placeholder() }} --\n </button>\n\n @if (loading()) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n Cargando...\n </button>\n } @else if (filteredOptions().length === 0) {\n <button type=\"button\" class=\"k-select__option k-select__option--disabled\" disabled>\n {{ searchTerm() ? 'No se encontraron resultados' : emptyMessage() }}\n </button>\n } @else {\n @for (option of filteredOptions(); track option.value) {\n <button type=\"button\" class=\"k-select__option\" [class.k-select__option--selected]=\"option.value === value()\" [class.k-select__option--disabled]=\"option.disabled\" [disabled]=\"option.disabled\" (click)=\"selectOption(option)\"\n (keydown.enter)=\"selectOption(option)\">\n {{ option.label }}\n </button>\n }\n }\n </div>\n }\n</div>"]}
@@ -1,8 +1,9 @@
1
- import { Component, computed, signal, ElementRef, inject, Renderer2 } from '@angular/core';
1
+ import { Component, computed, signal, ElementRef, inject, Renderer2, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export class SnackbarComponent {
4
4
  elementRef = inject(ElementRef);
5
5
  renderer = inject(Renderer2);
6
+ cdr = inject(ChangeDetectorRef);
6
7
  data = signal(null, ...(ngDevMode ? [{ debugName: "data" }] : []));
7
8
  visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : []));
8
9
  timerId;
@@ -12,6 +13,8 @@ export class SnackbarComponent {
12
13
  this.data.set(data);
13
14
  this.applyPosition(data.config);
14
15
  this.visible.set(true);
16
+ // Marcar para revisión de cambios con OnPush
17
+ this.cdr.markForCheck();
15
18
  if (data.config.duration > 0) {
16
19
  this.timerId = setTimeout(() => this.dismiss(), data.config.duration);
17
20
  }
@@ -19,6 +22,8 @@ export class SnackbarComponent {
19
22
  dismiss() {
20
23
  this.visible.set(false);
21
24
  this.clearTimer();
25
+ // Marcar para revisión de cambios con OnPush
26
+ this.cdr.markForCheck();
22
27
  }
23
28
  clearTimer() {
24
29
  if (this.timerId !== undefined) {
@@ -43,10 +48,10 @@ export class SnackbarComponent {
43
48
  }
44
49
  }
45
50
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
46
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SnackbarComponent, isStandalone: true, selector: "k-snackbar", ngImport: i0, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:#323232;color:#fff;border-radius:.25rem;box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024;pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:#90caf9;cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:#ffffff1a}.notification-success{background:#4caf50}.notification-error{background:#f44336}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"] });
51
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: SnackbarComponent, isStandalone: true, selector: "k-snackbar", ngImport: i0, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:#323232;color:#fff;border-radius:.25rem;box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024;pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:#90caf9;cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:#ffffff1a}.notification-success{background:#4caf50}.notification-error{background:#f44336}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
47
52
  }
48
53
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SnackbarComponent, decorators: [{
49
54
  type: Component,
50
- args: [{ selector: 'k-snackbar', standalone: true, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:#323232;color:#fff;border-radius:.25rem;box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024;pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:#90caf9;cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:#ffffff1a}.notification-success{background:#4caf50}.notification-error{background:#f44336}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
55
+ args: [{ selector: 'k-snackbar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:#323232;color:#fff;border-radius:.25rem;box-shadow:0 3px 5px -1px #0003,0 6px 10px #00000024;pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:#90caf9;cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:#ffffff1a}.notification-success{background:#4caf50}.notification-error{background:#f44336}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
51
56
  }] });
52
57
  //# sourceMappingURL=snackbar.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"snackbar.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.component.ts","../../../../../libs/ui/src/lib/snackbar/snackbar.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;;AAS3F,MAAM,OAAO,iBAAiB;IACX,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAErC,IAAI,GAAG,MAAM,CAAsB,IAAI,gDAAC,CAAC;IACzC,OAAO,GAAG,MAAM,CAAC,KAAK,mDAAC,CAAC;IAEzB,OAAO,CAAiC;IAEvC,YAAY,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,wDAAC,CAAC;IAEvF,IAAI,CAAC,IAAkB;QACrB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEvB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC/B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,aAAa,CAAC,MAA8B;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAC3C,MAAM,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAAC;QAExD,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAClE,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;QAEvD,IAAI,kBAAkB,KAAK,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YAC5C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;uGAnDU,iBAAiB;2FAAjB,iBAAiB,sECT9B,oUASC;;2FDAY,iBAAiB;kBAN7B,SAAS;+BACE,YAAY,cACV,IAAI","sourcesContent":["import { Component, computed, signal, ElementRef, inject, Renderer2 } from '@angular/core';\nimport type { SnackbarData } from './snackbar.model';\n\n@Component({\n selector: 'k-snackbar',\n standalone: true,\n templateUrl: './snackbar.component.html',\n styleUrl: './snackbar.component.scss',\n})\nexport class SnackbarComponent {\n private readonly elementRef = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n\n readonly data = signal<SnackbarData | null>(null);\n readonly visible = signal(false);\n\n private timerId?: ReturnType<typeof setTimeout>;\n\n readonly panelClasses = computed(() => this.data()?.config.panelClass.join(' ') ?? '');\n\n show(data: SnackbarData): void {\n this.clearTimer();\n this.data.set(data);\n this.applyPosition(data.config);\n this.visible.set(true);\n\n if (data.config.duration > 0) {\n this.timerId = setTimeout(() => this.dismiss(), data.config.duration);\n }\n }\n\n dismiss(): void {\n this.visible.set(false);\n this.clearTimer();\n }\n\n private clearTimer(): void {\n if (this.timerId !== undefined) {\n clearTimeout(this.timerId);\n this.timerId = undefined;\n }\n }\n\n private applyPosition(config: SnackbarData['config']): void {\n const host = this.elementRef.nativeElement;\n const { verticalPosition, horizontalPosition } = config;\n\n const positions = ['top', 'bottom', 'left', 'right', 'transform'];\n for (const pos of positions) {\n this.renderer.removeStyle(host, pos);\n }\n\n this.renderer.setStyle(host, verticalPosition, '1rem');\n\n if (horizontalPosition === 'center') {\n this.renderer.setStyle(host, 'left', '50%');\n this.renderer.setStyle(host, 'transform', 'translateX(-50%)');\n } else {\n this.renderer.setStyle(host, horizontalPosition, '1rem');\n }\n }\n}\n","@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}"]}
1
+ {"version":3,"file":"snackbar.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.component.ts","../../../../../libs/ui/src/lib/snackbar/snackbar.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, signal, ElementRef, inject, Renderer2, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';\nimport type { SnackbarData } from './snackbar.model';\n\n@Component({\n selector: 'k-snackbar',\n standalone: true,\n templateUrl: './snackbar.component.html',\n styleUrl: './snackbar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SnackbarComponent {\n private readonly elementRef = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly cdr = inject(ChangeDetectorRef);\n\n readonly data = signal<SnackbarData | null>(null);\n readonly visible = signal(false);\n\n private timerId?: ReturnType<typeof setTimeout>;\n\n readonly panelClasses = computed(() => this.data()?.config.panelClass.join(' ') ?? '');\n\n show(data: SnackbarData): void {\n this.clearTimer();\n this.data.set(data);\n this.applyPosition(data.config);\n this.visible.set(true);\n\n // Marcar para revisión de cambios con OnPush\n this.cdr.markForCheck();\n\n if (data.config.duration > 0) {\n this.timerId = setTimeout(() => this.dismiss(), data.config.duration);\n }\n }\n\n dismiss(): void {\n this.visible.set(false);\n this.clearTimer();\n\n // Marcar para revisión de cambios con OnPush\n this.cdr.markForCheck();\n }\n\n private clearTimer(): void {\n if (this.timerId !== undefined) {\n clearTimeout(this.timerId);\n this.timerId = undefined;\n }\n }\n\n private applyPosition(config: SnackbarData['config']): void {\n const host = this.elementRef.nativeElement;\n const { verticalPosition, horizontalPosition } = config;\n\n const positions = ['top', 'bottom', 'left', 'right', 'transform'];\n for (const pos of positions) {\n this.renderer.removeStyle(host, pos);\n }\n\n this.renderer.setStyle(host, verticalPosition, '1rem');\n\n if (horizontalPosition === 'center') {\n this.renderer.setStyle(host, 'left', '50%');\n this.renderer.setStyle(host, 'transform', 'translateX(-50%)');\n } else {\n this.renderer.setStyle(host, horizontalPosition, '1rem');\n }\n }\n}\n","@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}"]}
@@ -1,4 +1,4 @@
1
- import { Injectable, inject, ApplicationRef, createComponent, EnvironmentInjector, } from '@angular/core';
1
+ import { Injectable, inject, ApplicationRef, createComponent, EnvironmentInjector } from '@angular/core';
2
2
  import { SnackbarComponent } from './snackbar.component';
3
3
  import * as i0 from "@angular/core";
4
4
  export class SnackbarService {
@@ -6,7 +6,7 @@ export class SnackbarService {
6
6
  injector = inject(EnvironmentInjector);
7
7
  componentRef;
8
8
  defaultConfig = {
9
- duration: 3000,
9
+ duration: 2000,
10
10
  horizontalPosition: 'right',
11
11
  verticalPosition: 'top',
12
12
  panelClass: [],
@@ -30,7 +30,6 @@ export class SnackbarService {
30
30
  document.body.appendChild(this.componentRef.location.nativeElement);
31
31
  }
32
32
  this.componentRef.instance.show(data);
33
- this.componentRef.changeDetectorRef.detectChanges();
34
33
  }
35
34
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SnackbarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
36
35
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SnackbarService, providedIn: 'root' });
@@ -1 +1 @@
1
- {"version":3,"file":"snackbar.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,MAAM,EACN,cAAc,EACd,eAAe,EACf,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;AAMzD,MAAM,OAAO,eAAe;IACT,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAChC,QAAQ,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAChD,YAAY,CAAmC;IAEtC,aAAa,GAA6B;QACzD,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,OAAO;QAC3B,gBAAgB,EAAE,KAAK;QACvB,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,IAAI,CAAC,OAAe,EAAE,MAAe,EAAE,MAAuB;QAC5D,MAAM,YAAY,GAA6B;YAC7C,GAAG,IAAI,CAAC,aAAa;YACrB,GAAG,MAAM;YACT,UAAU,EAAE,MAAM,EAAE,UAAU,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU;SAChE,CAAC;QAEF,MAAM,IAAI,GAAiB;YACzB,OAAO;YACP,MAAM;YACN,MAAM,EAAE,YAAY;SACrB,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC,iBAAiB,EAAE;gBACrD,mBAAmB,EAAE,IAAI,CAAC,QAAQ;aACnC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACnD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,aAAa,EAAE,CAAC;IACtD,CAAC;uGApCU,eAAe;2GAAf,eAAe,cAFd,MAAM;;2FAEP,eAAe;kBAH3B,UAAU;mBAAC;oBACV,UAAU,EAAE,MAAM;iBACnB","sourcesContent":["import {\n Injectable,\n inject,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n ComponentRef,\n} from '@angular/core';\nimport { SnackbarComponent } from './snackbar.component';\nimport type { SnackbarConfig, SnackbarData } from './snackbar.model';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SnackbarService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n private componentRef?: ComponentRef<SnackbarComponent>;\n\n private readonly defaultConfig: Required<SnackbarConfig> = {\n duration: 3000,\n horizontalPosition: 'right',\n verticalPosition: 'top',\n panelClass: [],\n };\n\n open(message: string, action?: string, config?: SnackbarConfig): void {\n const mergedConfig: Required<SnackbarConfig> = {\n ...this.defaultConfig,\n ...config,\n panelClass: config?.panelClass ?? this.defaultConfig.panelClass,\n };\n\n const data: SnackbarData = {\n message,\n action,\n config: mergedConfig,\n };\n\n if (!this.componentRef) {\n this.componentRef = createComponent(SnackbarComponent, {\n environmentInjector: this.injector,\n });\n\n this.appRef.attachView(this.componentRef.hostView);\n document.body.appendChild(this.componentRef.location.nativeElement);\n }\n\n this.componentRef.instance.show(data);\n this.componentRef.changeDetectorRef.detectChanges();\n }\n}\n"]}
1
+ {"version":3,"file":"snackbar.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,UAAU,EACV,MAAM,EACN,cAAc,EACd,eAAe,EACf,mBAAmB,EACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;AAMzD,MAAM,OAAO,eAAe;IACT,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAChC,QAAQ,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAChD,YAAY,CAAmC;IAEtC,aAAa,GAA6B;QACzD,QAAQ,EAAE,IAAI;QACd,kBAAkB,EAAE,OAAO;QAC3B,gBAAgB,EAAE,KAAK;QACvB,UAAU,EAAE,EAAE;KACf,CAAC;IAEF,IAAI,CAAC,OAAe,EAAE,MAAe,EAAE,MAAuB;QAC5D,MAAM,YAAY,GAA6B;YAC7C,GAAG,IAAI,CAAC,aAAa;YACrB,GAAG,MAAM;YACT,UAAU,EAAE,MAAM,EAAE,UAAU,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU;SAChE,CAAC;QAEF,MAAM,IAAI,GAAiB;YACzB,OAAO;YACP,MAAM;YACN,MAAM,EAAE,YAAY;SACrB,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC,iBAAiB,EAAE;gBACrD,mBAAmB,EAAE,IAAI,CAAC,QAAQ;aACnC,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACnD,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;uGAnCU,eAAe;2GAAf,eAAe,cAFd,MAAM;;2FAEP,eAAe;kBAH3B,UAAU;mBAAC;oBACV,UAAU,EAAE,MAAM;iBACnB","sourcesContent":["import {\n type ComponentRef,\n Injectable,\n inject,\n ApplicationRef,\n createComponent,\n EnvironmentInjector\n} from '@angular/core';\nimport { SnackbarComponent } from './snackbar.component';\nimport type { SnackbarConfig, SnackbarData } from './snackbar.model';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class SnackbarService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n private componentRef?: ComponentRef<SnackbarComponent>;\n\n private readonly defaultConfig: Required<SnackbarConfig> = {\n duration: 2000,\n horizontalPosition: 'right',\n verticalPosition: 'top',\n panelClass: [],\n };\n\n open(message: string, action?: string, config?: SnackbarConfig): void {\n const mergedConfig: Required<SnackbarConfig> = {\n ...this.defaultConfig,\n ...config,\n panelClass: config?.panelClass ?? this.defaultConfig.panelClass,\n };\n\n const data: SnackbarData = {\n message,\n action,\n config: mergedConfig,\n };\n\n if (!this.componentRef) {\n this.componentRef = createComponent(SnackbarComponent, {\n environmentInjector: this.injector,\n });\n\n this.appRef.attachView(this.componentRef.hostView);\n document.body.appendChild(this.componentRef.location.nativeElement);\n }\n\n this.componentRef.instance.show(data);\n }\n}\n"]}
@@ -1,13 +1,13 @@
1
- import { Component, input } from '@angular/core';
1
+ import { Component, input, ChangeDetectionStrategy } from '@angular/core';
2
2
  import { C80IconComponent } from '../icon';
3
3
  import * as i0 from "@angular/core";
4
4
  export class C80StatCardComponent {
5
5
  cards = input([], ...(ngDevMode ? [{ debugName: "cards" }] : []));
6
6
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80StatCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80StatCardComponent, isStandalone: true, selector: "c80-stat-card", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\"></c80-icon>\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>", styles: [".stats-section{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.stats-section .stat-card{flex:1;min-width:200px;box-shadow:0 2px 8px #0000001a;transition:box-shadow .3s ease;border-left:4px solid transparent;background:#fff;color:#000000de;border-radius:4px;display:block;position:relative;padding:0;overflow:hidden}.stats-section .stat-card:hover{box-shadow:0 4px 12px #00000026}.stats-section .stat-card-content{display:block;padding:16px}.stat-content{display:flex;align-items:center;gap:12px}.stat-info .stat-number{font-size:24px;font-weight:700;line-height:1;margin-bottom:4px;color:#6b7280}.stat-info .stat-label{font-size:12px;color:#666;text-transform:uppercase;letter-spacing:.5px}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }] });
7
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: C80StatCardComponent, isStandalone: true, selector: "c80-stat-card", inputs: { cards: { classPropertyName: "cards", publicName: "cards", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\" />\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>", styles: [".stats-section{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.stats-section .stat-card{flex:1;min-width:200px;box-shadow:0 2px 8px #0000001a;transition:box-shadow .3s ease;border-left:4px solid transparent;background:#fff;color:#000000de;border-radius:4px;display:block;position:relative;padding:0;overflow:hidden}.stats-section .stat-card:hover{box-shadow:0 4px 12px #00000026}.stats-section .stat-card-content{display:block;padding:16px}.stat-content{display:flex;align-items:center;gap:12px}.stat-info .stat-number{font-size:24px;font-weight:700;line-height:1;margin-bottom:4px;color:#6b7280}.stat-info .stat-label{font-size:12px;color:#666;text-transform:uppercase;letter-spacing:.5px}\n"], dependencies: [{ kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight"], outputs: ["iconClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8
8
  }
9
9
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: C80StatCardComponent, decorators: [{
10
10
  type: Component,
11
- args: [{ selector: 'c80-stat-card', standalone: true, imports: [C80IconComponent], template: "<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\"></c80-icon>\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>", styles: [".stats-section{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.stats-section .stat-card{flex:1;min-width:200px;box-shadow:0 2px 8px #0000001a;transition:box-shadow .3s ease;border-left:4px solid transparent;background:#fff;color:#000000de;border-radius:4px;display:block;position:relative;padding:0;overflow:hidden}.stats-section .stat-card:hover{box-shadow:0 4px 12px #00000026}.stats-section .stat-card-content{display:block;padding:16px}.stat-content{display:flex;align-items:center;gap:12px}.stat-info .stat-number{font-size:24px;font-weight:700;line-height:1;margin-bottom:4px;color:#6b7280}.stat-info .stat-label{font-size:12px;color:#666;text-transform:uppercase;letter-spacing:.5px}\n"] }]
11
+ args: [{ selector: 'c80-stat-card', standalone: true, imports: [C80IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\" />\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>", styles: [".stats-section{display:flex;flex-direction:row;flex-wrap:wrap;gap:16px}.stats-section .stat-card{flex:1;min-width:200px;box-shadow:0 2px 8px #0000001a;transition:box-shadow .3s ease;border-left:4px solid transparent;background:#fff;color:#000000de;border-radius:4px;display:block;position:relative;padding:0;overflow:hidden}.stats-section .stat-card:hover{box-shadow:0 4px 12px #00000026}.stats-section .stat-card-content{display:block;padding:16px}.stat-content{display:flex;align-items:center;gap:12px}.stat-info .stat-number{font-size:24px;font-weight:700;line-height:1;margin-bottom:4px;color:#6b7280}.stat-info .stat-label{font-size:12px;color:#666;text-transform:uppercase;letter-spacing:.5px}\n"] }]
12
12
  }], propDecorators: { cards: [{ type: i0.Input, args: [{ isSignal: true, alias: "cards", required: false }] }] } });
13
13
  //# sourceMappingURL=stat-card.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/stat-card/stat-card.component.ts","../../../../../libs/ui/src/lib/stat-card/stat-card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;;AAkB3C,MAAM,OAAO,oBAAoB;IACtB,KAAK,GAAG,KAAK,CAAY,EAAE,iDAAC,CAAC;uGAD3B,oBAAoB;2FAApB,oBAAoB,6MCnBjC,yhBAcM,uvBDCM,gBAAgB;;2FAIf,oBAAoB;kBARhC,SAAS;+BAEE,eAAe,cACb,IAAI,WACP,CAAC,gBAAgB,CAAC","sourcesContent":["import { Component, input } from '@angular/core';\r\nimport { C80IconComponent } from '../icon';\r\nimport { IconType } from '../icon/icon.types';\r\n\r\nexport interface CardDef {\r\n color: string; // Acepta cualquier color CSS\r\n icon: IconType;\r\n text: string;\r\n count: number;\r\n}\r\n\r\n@Component({\r\n // eslint-disable-next-line @angular-eslint/component-selector\r\n selector: 'c80-stat-card',\r\n standalone: true,\r\n imports: [C80IconComponent],\r\n templateUrl: './stat-card.component.html',\r\n styleUrls: ['./stat-card.component.scss'],\r\n})\r\nexport class C80StatCardComponent {\r\n readonly cards = input<CardDef[]>([]);\r\n}\r\n","<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\"></c80-icon>\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>"]}
1
+ {"version":3,"file":"stat-card.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/stat-card/stat-card.component.ts","../../../../../libs/ui/src/lib/stat-card/stat-card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;;AAmB3C,MAAM,OAAO,oBAAoB;IACtB,KAAK,GAAG,KAAK,CAAY,EAAE,iDAAC,CAAC;uGAD3B,oBAAoB;2FAApB,oBAAoB,6MCpBjC,+lBAeM,uvBDAM,gBAAgB;;2FAKf,oBAAoB;kBAThC,SAAS;+BAEE,eAAe,cACb,IAAI,WACP,CAAC,gBAAgB,CAAC,mBAGV,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, ChangeDetectionStrategy } from '@angular/core';\nimport { C80IconComponent } from '../icon';\nimport type { IconType } from '../icon/icon.types';\n\nexport interface CardDef {\n color: string; // Acepta cualquier color CSS\n icon: IconType;\n text: string;\n count: number;\n}\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-stat-card',\n standalone: true,\n imports: [C80IconComponent],\n templateUrl: './stat-card.component.html',\n styleUrls: ['./stat-card.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class C80StatCardComponent {\n readonly cards = input<CardDef[]>([]);\n}\n","<div class=\"stats-section py-4\">\n @for (card of cards(); track card.text) {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <div class=\"stat-card\" [style.border-left-color]=\"card.color\">\n <div class=\"stat-card-content\">\n <div class=\"stat-content\">\n <c80-icon [icon]=\"card.icon\" [color]=\"'secondary'\" [size]=\"1.1\" />\n <div class=\"stat-info\">\n <div class=\"stat-number\">{{ card.count }}</div>\n <div class=\"stat-label\">{{ card.text }}</div>\n </div>\n </div>\n </div>\n </div>\n }\n</div>"]}
@@ -1 +1 @@
1
- {"version":3,"file":"table-column-visibility.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-column-visibility.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;;AAEnE;;;;;;;GAOG;AAIH,MAAM,OAAO,4BAA4B;IAEtB,aAAa,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAClD,SAAS,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAE3D;;;;;;;OAOG;IACH,iBAAiB,CACf,OAAyB,EACzB,IAAS,EACT,QAAiB,EACjB,OAAsB;QAEtB,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC1C,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAC3D,CAAC;QACF,OAAO,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;OAOG;IACH,eAAe,CACb,MAAsB,EACtB,IAAS,EACT,UAKI,EAAE;QAEN,oFAAoF;QACpF,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,sDAAsD;QACtD,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kGAAkG;QAClG,kDAAkD;QAElD,0BAA0B;QAC1B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,mEAAmE;YACnE,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;YAChC,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC5E,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YACrD,CAAC;YACD,oDAAoD;YACpD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4BAA4B;QAC5B,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9E,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3E,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;YACrD,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,uEAAuE;QACvE,OAAO,CAAC,IAAI,CAAC,uBAAuB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,uBAAuB,CACrB,MAAsB,EACtB,IAAS,EACT,QAAiB,EACjB,OAAsB;QAEtB,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED;;;OAGG;IACH,qBAAqB,CACnB,MAAsB,EACtB,GAAM,EACN,IAAS,EACT,OAAsB;QAEtB,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED;;OAEG;IACK,uBAAuB,CAC7B,MAAsB,EACtB,IAAS;QAET,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;YACtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChE,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC;uGA3HU,4BAA4B;2GAA5B,4BAA4B,cAF3B,MAAM;;2FAEP,4BAA4B;kBAHxC,UAAU;mBAAC;oBACV,UAAU,EAAE,MAAM;iBACnB","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport { C80TableColDef } from './table.types';\nimport { TableDataConverterService } from './table-data-converter.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\n\n/**\n * Servicio para gestionar la lógica de visibilidad de columnas en tablas C80\n *\n * Maneja las reglas complejas de visibilidad basadas en:\n * - Configuración explícita (visible: false)\n * - Ocultación automática (hideIfAllValuesAreNull)\n * - Estado de creación y edición\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableColumnVisibilityService {\n\n private readonly dataConverter = inject(TableDataConverterService);\n private readonly dataUtils = inject(TableDataUtilsService);\n\n /**\n * Actualiza las keys de columnas visibles basándose en el estado actual\n * @param columns - Definiciones de columnas\n * @param data - Datos actuales de la tabla\n * @param creating - Si está en modo creación\n * @param editing - ID de fila en edición (null si no hay edición)\n * @returns Array de accessors de columnas visibles\n */\n updateVisibleKeys<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[],\n creating: boolean,\n editing: string | null\n ): string[] {\n const visibleColumns = columns.filter(col =>\n this.isColumnVisibleInHeader(col, data, creating, editing)\n );\n return visibleColumns.map(col => col.accessor);\n }\n\n /**\n * Determina si una columna debe ser visible basándose en su configuración y datos\n * Método unificado que maneja todos los casos de visibilidad\n * @param column - La definición de la columna\n * @param data - Datos actuales de la tabla\n * @param options - Opciones de contexto (creación, edición, fila específica)\n * @returns true si la columna debe ser visible\n */\n isColumnVisible<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[],\n options: {\n forceShowInCreation?: boolean;\n creating?: boolean;\n editing?: string | null;\n row?: T;\n } = {}\n ): boolean {\n // PRIORIDAD 1: Si visible está explícitamente establecido en false, SIEMPRE ocultar\n if (column.visible === false) {\n return false;\n }\n\n // Si no tiene hideIfAllValuesAreNull, mostrar siempre\n if (!column.hideIfAllValuesAreNull) {\n return true;\n }\n\n // PRIORIDAD 2: Para columnas con hideIfAllValuesAreNull, ocultar si el valor es falsy (excepto 0)\n // Esto aplica tanto en modo creación como edición\n\n // CONTEXTO: Modo creación\n if (options.creating) {\n // En creación, verificar el valor de la fila en creación si existe\n const creatingRow = options.row;\n if (creatingRow) {\n const cellValue = this.dataUtils.getCellValue(creatingRow, column.accessor);\n return !this.dataConverter.isValueEmpty(cellValue);\n }\n // Si no hay fila, ocultar (valor vacío por defecto)\n return false;\n }\n\n // CONTEXTO: Fila en edición\n if (options.editing !== undefined && options.editing !== null) {\n const editingRow = options.row ?? data.find(r => r['id'] === options.editing);\n if (editingRow) {\n const cellValue = this.dataUtils.getCellValue(editingRow, column.accessor);\n return !this.dataConverter.isValueEmpty(cellValue);\n }\n return false;\n }\n\n // CONTEXTO: Vista normal - verificar si todos los valores están vacíos\n return !this.areAllColumnValuesEmpty(column, data);\n }\n\n /**\n * Determina si una columna debe ser visible en los headers\n * Wrapper para mantener compatibilidad con API existente\n */\n isColumnVisibleInHeader<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[],\n creating: boolean,\n editing: string | null\n ): boolean {\n return this.isColumnVisible(column, data, { creating, editing });\n }\n\n /**\n * Determina si una columna debe ser visible en una fila específica\n * Wrapper para mantener compatibilidad con API existente\n */\n isColumnVisibleForRow<T extends Record<string, unknown>>(\n column: C80TableColDef,\n row: T,\n data: T[],\n editing: string | null\n ): boolean {\n return this.isColumnVisible(column, data, { editing, row });\n }\n\n /**\n * Verifica si todos los valores de una columna están vacíos/nulos\n */\n private areAllColumnValuesEmpty<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[]\n ): boolean {\n if (data.length === 0) {\n return true;\n }\n\n return data.every(row => {\n const value = this.dataUtils.getCellValue(row, column.accessor);\n return this.dataConverter.isValueEmpty(value);\n });\n }\n}\n"]}
1
+ {"version":3,"file":"table-column-visibility.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-column-visibility.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport type { C80TableColDef } from './table.types';\nimport { TableDataConverterService } from './table-data-converter.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\n\n/**\n * Servicio para gestionar la lógica de visibilidad de columnas en tablas C80\n *\n * Maneja las reglas complejas de visibilidad basadas en:\n * - Configuración explícita (visible: false)\n * - Ocultación automática (hideIfAllValuesAreNull)\n * - Estado de creación y edición\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableColumnVisibilityService {\n\n private readonly dataConverter = inject(TableDataConverterService);\n private readonly dataUtils = inject(TableDataUtilsService);\n\n /**\n * Actualiza las keys de columnas visibles basándose en el estado actual\n * @param columns - Definiciones de columnas\n * @param data - Datos actuales de la tabla\n * @param creating - Si está en modo creación\n * @param editing - ID de fila en edición (null si no hay edición)\n * @returns Array de accessors de columnas visibles\n */\n updateVisibleKeys<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[],\n creating: boolean,\n editing: string | null\n ): string[] {\n const visibleColumns = columns.filter(col =>\n this.isColumnVisibleInHeader(col, data, creating, editing)\n );\n return visibleColumns.map(col => col.accessor);\n }\n\n /**\n * Determina si una columna debe ser visible basándose en su configuración y datos\n * Método unificado que maneja todos los casos de visibilidad\n * @param column - La definición de la columna\n * @param data - Datos actuales de la tabla\n * @param options - Opciones de contexto (creación, edición, fila específica)\n * @returns true si la columna debe ser visible\n */\n isColumnVisible<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[],\n options: {\n forceShowInCreation?: boolean;\n creating?: boolean;\n editing?: string | null;\n row?: T;\n } = {}\n ): boolean {\n // PRIORIDAD 1: Si visible está explícitamente establecido en false, SIEMPRE ocultar\n if (column.visible === false) {\n return false;\n }\n\n // Si no tiene hideIfAllValuesAreNull, mostrar siempre\n if (!column.hideIfAllValuesAreNull) {\n return true;\n }\n\n // PRIORIDAD 2: Para columnas con hideIfAllValuesAreNull, ocultar si el valor es falsy (excepto 0)\n // Esto aplica tanto en modo creación como edición\n\n // CONTEXTO: Modo creación\n if (options.creating) {\n // En creación, verificar el valor de la fila en creación si existe\n const creatingRow = options.row;\n if (creatingRow) {\n const cellValue = this.dataUtils.getCellValue(creatingRow, column.accessor);\n return !this.dataConverter.isValueEmpty(cellValue);\n }\n // Si no hay fila, ocultar (valor vacío por defecto)\n return false;\n }\n\n // CONTEXTO: Fila en edición\n if (options.editing !== undefined && options.editing !== null) {\n const editingRow = options.row ?? data.find(r => r['id'] === options.editing);\n if (editingRow) {\n const cellValue = this.dataUtils.getCellValue(editingRow, column.accessor);\n return !this.dataConverter.isValueEmpty(cellValue);\n }\n return false;\n }\n\n // CONTEXTO: Vista normal - verificar si todos los valores están vacíos\n return !this.areAllColumnValuesEmpty(column, data);\n }\n\n /**\n * Determina si una columna debe ser visible en los headers\n * Wrapper para mantener compatibilidad con API existente\n */\n isColumnVisibleInHeader<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[],\n creating: boolean,\n editing: string | null\n ): boolean {\n return this.isColumnVisible(column, data, { creating, editing });\n }\n\n /**\n * Determina si una columna debe ser visible en una fila específica\n * Wrapper para mantener compatibilidad con API existente\n */\n isColumnVisibleForRow<T extends Record<string, unknown>>(\n column: C80TableColDef,\n row: T,\n data: T[],\n editing: string | null\n ): boolean {\n return this.isColumnVisible(column, data, { editing, row });\n }\n\n /**\n * Verifica si todos los valores de una columna están vacíos/nulos\n */\n private areAllColumnValuesEmpty<T extends Record<string, unknown>>(\n column: C80TableColDef,\n data: T[]\n ): boolean {\n if (data.length === 0) {\n return true;\n }\n\n return data.every(row => {\n const value = this.dataUtils.getCellValue(row, column.accessor);\n return this.dataConverter.isValueEmpty(value);\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"table-crud-state.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-crud-state.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, signal, inject } from '@angular/core';\nimport { C80TableColDef } from './table.types';\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\n\n/**\n * Servicio para gestionar el estado CRUD (Crear, Leer, Actualizar, Eliminar) en tablas C80\n *\n * Maneja:\n * - Estado de creación y edición\n * - Gestión de datos temporales (newRow, editRow)\n * - Aplicación de valores dinámicos\n * - Validación y conversión de datos\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableCrudStateService {\n\n private readonly visibilityService = inject(TableColumnVisibilityService);\n private readonly dataUtils = inject(TableDataUtilsService);\n\n /**\n * Filtra columnas visibles y editables\n */\n private getEditableColumns<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[],\n includeHiddenIfNull: boolean\n ): C80TableColDef[] {\n return columns.filter(\n col => this.visibilityService.isColumnVisible(col, data, { forceShowInCreation: includeHiddenIfNull }) && !col.readOnly\n );\n }\n\n /**\n * Inicializa row para creación con valores por defecto\n */\n private initializeNewRow<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[]\n ): Partial<T> {\n const row: Partial<T> = {};\n for (const col of this.getEditableColumns(columns, data, true)) {\n const defaultValue = col.default === undefined ? '' : col.default;\n (row as Record<string, unknown>)[col.accessor] = defaultValue;\n }\n return row;\n }\n\n /**\n * Inicializa row para edición con valores actuales\n */\n private initializeEditRow<T extends Record<string, unknown>>(\n row: T,\n columns: C80TableColDef[],\n data: T[]\n ): Partial<T> {\n const edit: Partial<T> = {};\n for (const col of this.getEditableColumns(columns, data, true)) {\n const value = this.dataUtils.getCellValue(row, col.accessor);\n (edit as Record<string, unknown>)[col.accessor] = value;\n }\n return edit;\n }\n\n /**\n * Inicializa el estado CRUD para una nueva tabla\n * @returns Objeto con signals y métodos para gestión CRUD\n */\n createCrudState<T extends Record<string, unknown>>() {\n const creating = signal(false);\n const newRow = signal<Partial<T> | null>(null);\n const editing = signal<string | null>(null);\n const editRow = signal<Partial<T> | null>(null);\n\n return {\n creating: creating.asReadonly(),\n newRow: newRow.asReadonly(),\n editing: editing.asReadonly(),\n editRow: editRow.asReadonly(),\n startCreate: (columns: C80TableColDef[], data: T[]) => this.startCreate(creating, newRow, columns, data),\n cancelCreate: () => this.cancelCreate(creating, newRow),\n updateNewRow: (key: string, value: unknown) => this.updateRow(newRow, key, value),\n startEdit: (row: T, columns: C80TableColDef[], data: T[]) => this.startEdit({ editing, editRow }, row, columns, data),\n cancelEdit: () => this.cancelEdit(editing, editRow),\n updateEditRow: (key: string, value: unknown) => this.updateRow(editRow, key, value),\n applyInputValues: (partialValues: Partial<T>) => this.applyInputValues({ creating, newRow, editing, editRow }, partialValues),\n };\n }\n\n private startCreate<T extends Record<string, unknown>>(\n creating: ReturnType<typeof signal<boolean>>,\n newRow: ReturnType<typeof signal<Partial<T> | null>>,\n columns: C80TableColDef[],\n data: T[]\n ): void {\n creating.set(true);\n newRow.set(this.initializeNewRow(columns, data));\n }\n\n private cancelCreate<T extends Record<string, unknown>>(\n creating: ReturnType<typeof signal<boolean>>,\n newRow: ReturnType<typeof signal<Partial<T> | null>>\n ): void {\n creating.set(false);\n newRow.set(null);\n }\n\n private updateRow<T extends Record<string, unknown>>(\n rowSignal: ReturnType<typeof signal<Partial<T> | null>>,\n key: string,\n value: unknown\n ): void {\n const current = rowSignal();\n if (!current) return;\n rowSignal.set({ ...current, [key]: value });\n }\n\n private startEdit<T extends Record<string, unknown>>(\n signals: {\n editing: ReturnType<typeof signal<string | null>>;\n editRow: ReturnType<typeof signal<Partial<T> | null>>;\n },\n row: T,\n columns: C80TableColDef[],\n data: T[]\n ): void {\n signals.editing.set(row['id'] as string);\n signals.editRow.set(this.initializeEditRow(row, columns, data));\n }\n\n private cancelEdit<T extends Record<string, unknown>>(\n editing: ReturnType<typeof signal<string | null>>,\n editRow: ReturnType<typeof signal<Partial<T> | null>>\n ): void {\n editing.set(null);\n editRow.set(null);\n }\n\n private applyInputValues<T extends Record<string, unknown>>(\n signals: {\n creating: ReturnType<typeof signal<boolean>>;\n newRow: ReturnType<typeof signal<Partial<T> | null>>;\n editing: ReturnType<typeof signal<string | null>>;\n editRow: ReturnType<typeof signal<Partial<T> | null>>;\n },\n partialValues: Partial<T>\n ): void {\n if (!signals.creating() && signals.editing() === null) return;\n\n if (signals.creating()) {\n const currentRow = signals.newRow();\n if (currentRow) {\n signals.newRow.set({ ...currentRow, ...partialValues });\n }\n } else {\n const currentEditRow = signals.editRow();\n if (currentEditRow) {\n signals.editRow.set({ ...currentEditRow, ...partialValues });\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"table-crud-state.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-crud-state.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, signal, inject } from '@angular/core';\nimport type { C80TableColDef } from './table.types';\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\n\n/**\n * Servicio para gestionar el estado CRUD (Crear, Leer, Actualizar, Eliminar) en tablas C80\n *\n * Maneja:\n * - Estado de creación y edición\n * - Gestión de datos temporales (newRow, editRow)\n * - Aplicación de valores dinámicos\n * - Validación y conversión de datos\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableCrudStateService {\n\n private readonly visibilityService = inject(TableColumnVisibilityService);\n private readonly dataUtils = inject(TableDataUtilsService);\n\n /**\n * Filtra columnas visibles y editables\n */\n private getEditableColumns<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[],\n includeHiddenIfNull: boolean\n ): C80TableColDef[] {\n return columns.filter(\n col => this.visibilityService.isColumnVisible(col, data, { forceShowInCreation: includeHiddenIfNull }) && !col.readOnly\n );\n }\n\n /**\n * Inicializa row para creación con valores por defecto\n */\n private initializeNewRow<T extends Record<string, unknown>>(\n columns: C80TableColDef[],\n data: T[]\n ): Partial<T> {\n const row: Partial<T> = {};\n for (const col of this.getEditableColumns(columns, data, true)) {\n const defaultValue = col.default === undefined ? '' : col.default;\n (row as Record<string, unknown>)[col.accessor] = defaultValue;\n }\n return row;\n }\n\n /**\n * Inicializa row para edición con valores actuales\n */\n private initializeEditRow<T extends Record<string, unknown>>(\n row: T,\n columns: C80TableColDef[],\n data: T[]\n ): Partial<T> {\n const edit: Partial<T> = {};\n for (const col of this.getEditableColumns(columns, data, true)) {\n const value = this.dataUtils.getCellValue(row, col.accessor);\n (edit as Record<string, unknown>)[col.accessor] = value;\n }\n return edit;\n }\n\n /**\n * Inicializa el estado CRUD para una nueva tabla\n * @returns Objeto con signals y métodos para gestión CRUD\n */\n createCrudState<T extends Record<string, unknown>>() {\n const creating = signal(false);\n const newRow = signal<Partial<T> | null>(null);\n const editing = signal<string | null>(null);\n const editRow = signal<Partial<T> | null>(null);\n\n return {\n creating: creating.asReadonly(),\n newRow: newRow.asReadonly(),\n editing: editing.asReadonly(),\n editRow: editRow.asReadonly(),\n startCreate: (columns: C80TableColDef[], data: T[]) => this.startCreate(creating, newRow, columns, data),\n cancelCreate: () => this.cancelCreate(creating, newRow),\n updateNewRow: (key: string, value: unknown) => this.updateRow(newRow, key, value),\n startEdit: (row: T, columns: C80TableColDef[], data: T[]) => this.startEdit({ editing, editRow }, row, columns, data),\n cancelEdit: () => this.cancelEdit(editing, editRow),\n updateEditRow: (key: string, value: unknown) => this.updateRow(editRow, key, value),\n applyInputValues: (partialValues: Partial<T>) => this.applyInputValues({ creating, newRow, editing, editRow }, partialValues),\n };\n }\n\n private startCreate<T extends Record<string, unknown>>(\n creating: ReturnType<typeof signal<boolean>>,\n newRow: ReturnType<typeof signal<Partial<T> | null>>,\n columns: C80TableColDef[],\n data: T[]\n ): void {\n creating.set(true);\n newRow.set(this.initializeNewRow(columns, data));\n }\n\n private cancelCreate<T extends Record<string, unknown>>(\n creating: ReturnType<typeof signal<boolean>>,\n newRow: ReturnType<typeof signal<Partial<T> | null>>\n ): void {\n creating.set(false);\n newRow.set(null);\n }\n\n private updateRow<T extends Record<string, unknown>>(\n rowSignal: ReturnType<typeof signal<Partial<T> | null>>,\n key: string,\n value: unknown\n ): void {\n const current = rowSignal();\n if (!current) return;\n rowSignal.set({ ...current, [key]: value });\n }\n\n private startEdit<T extends Record<string, unknown>>(\n signals: {\n editing: ReturnType<typeof signal<string | null>>;\n editRow: ReturnType<typeof signal<Partial<T> | null>>;\n },\n row: T,\n columns: C80TableColDef[],\n data: T[]\n ): void {\n signals.editing.set(row['id'] as string);\n signals.editRow.set(this.initializeEditRow(row, columns, data));\n }\n\n private cancelEdit<T extends Record<string, unknown>>(\n editing: ReturnType<typeof signal<string | null>>,\n editRow: ReturnType<typeof signal<Partial<T> | null>>\n ): void {\n editing.set(null);\n editRow.set(null);\n }\n\n private applyInputValues<T extends Record<string, unknown>>(\n signals: {\n creating: ReturnType<typeof signal<boolean>>;\n newRow: ReturnType<typeof signal<Partial<T> | null>>;\n editing: ReturnType<typeof signal<string | null>>;\n editRow: ReturnType<typeof signal<Partial<T> | null>>;\n },\n partialValues: Partial<T>\n ): void {\n if (!signals.creating() && signals.editing() === null) return;\n\n if (signals.creating()) {\n const currentRow = signals.newRow();\n if (currentRow) {\n signals.newRow.set({ ...currentRow, ...partialValues });\n }\n } else {\n const currentEditRow = signals.editRow();\n if (currentEditRow) {\n signals.editRow.set({ ...currentEditRow, ...partialValues });\n }\n }\n }\n}\n"]}