@c80/ui 1.0.64 → 1.1.2

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 (57) hide show
  1. package/README.md +1 -1
  2. package/esm2022/index.js +3 -0
  3. package/esm2022/index.js.map +1 -1
  4. package/esm2022/lib/header/header.component.js +4 -3
  5. package/esm2022/lib/header/header.component.js.map +1 -1
  6. package/esm2022/lib/icon/icon.definitions.js +3 -0
  7. package/esm2022/lib/icon/icon.definitions.js.map +1 -1
  8. package/esm2022/lib/icon/theme.service.js +19 -4
  9. package/esm2022/lib/icon/theme.service.js.map +1 -1
  10. package/esm2022/lib/info-message/index.js +3 -0
  11. package/esm2022/lib/info-message/index.js.map +1 -0
  12. package/esm2022/lib/info-message/info-message.component.js +25 -0
  13. package/esm2022/lib/info-message/info-message.component.js.map +1 -0
  14. package/esm2022/lib/info-message/info-message.types.js +2 -0
  15. package/esm2022/lib/info-message/info-message.types.js.map +1 -0
  16. package/esm2022/lib/legal-disclaimer/index.js +2 -0
  17. package/esm2022/lib/legal-disclaimer/index.js.map +1 -0
  18. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js +21 -0
  19. package/esm2022/lib/legal-disclaimer/legal-disclaimer.component.js.map +1 -0
  20. package/esm2022/lib/modal/modal.component.js +9 -2
  21. package/esm2022/lib/modal/modal.component.js.map +1 -1
  22. package/esm2022/lib/modal/modal.service.js +17 -5
  23. package/esm2022/lib/modal/modal.service.js.map +1 -1
  24. package/esm2022/lib/modal/modal.types.js.map +1 -1
  25. package/esm2022/lib/navigation-card/index.js +3 -0
  26. package/esm2022/lib/navigation-card/index.js.map +1 -0
  27. package/esm2022/lib/navigation-card/navigation-card.component.js +18 -0
  28. package/esm2022/lib/navigation-card/navigation-card.component.js.map +1 -0
  29. package/esm2022/lib/navigation-card/navigation-card.types.js +2 -0
  30. package/esm2022/lib/navigation-card/navigation-card.types.js.map +1 -0
  31. package/esm2022/lib/table/table-dto-mapper.service.js +29 -32
  32. package/esm2022/lib/table/table-dto-mapper.service.js.map +1 -1
  33. package/esm2022/lib/table/table-selection.service.js +16 -16
  34. package/esm2022/lib/table/table-selection.service.js.map +1 -1
  35. package/esm2022/lib/table/table.component.js +22 -6
  36. package/esm2022/lib/table/table.component.js.map +1 -1
  37. package/esm2022/lib/table/table.utils.js +4 -3
  38. package/esm2022/lib/table/table.utils.js.map +1 -1
  39. package/index.d.ts +3 -0
  40. package/lib/header/header.component.d.ts +2 -1
  41. package/lib/icon/theme.service.d.ts +34 -0
  42. package/lib/info-message/index.d.ts +2 -0
  43. package/lib/info-message/info-message.component.d.ts +17 -0
  44. package/lib/info-message/info-message.types.d.ts +5 -0
  45. package/lib/legal-disclaimer/index.d.ts +1 -0
  46. package/lib/legal-disclaimer/legal-disclaimer.component.d.ts +15 -0
  47. package/lib/modal/modal.component.d.ts +5 -0
  48. package/lib/modal/modal.service.d.ts +11 -2
  49. package/lib/modal/modal.types.d.ts +1 -0
  50. package/lib/navigation-card/index.d.ts +2 -0
  51. package/lib/navigation-card/navigation-card.component.d.ts +10 -0
  52. package/lib/navigation-card/navigation-card.types.d.ts +7 -0
  53. package/lib/table/table-dto-mapper.service.d.ts +12 -5
  54. package/lib/table/table-selection.service.d.ts +1 -1
  55. package/lib/table/table.component.d.ts +2 -1
  56. package/lib/table/table.utils.d.ts +2 -1
  57. package/package.json +1 -1
@@ -33,16 +33,18 @@ export class ModalService {
33
33
  * @param options.message
34
34
  * @param options.confirmText
35
35
  * @param options.cancelText
36
+ * @param options.allowHtml
36
37
  * @returns Promise que resuelve true si se confirmó
37
38
  */
38
39
  async confirm(options) {
39
- const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar' } = options;
40
+ const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar', allowHtml } = options;
40
41
  return this.showModal({
41
42
  title,
42
43
  message,
43
44
  type: 'confirm',
44
45
  confirmText,
45
46
  cancelText,
47
+ allowHtml,
46
48
  }).then((result) => result.confirmed);
47
49
  }
48
50
  /**
@@ -52,29 +54,35 @@ export class ModalService {
52
54
  * @param options.message
53
55
  * @param options.yesText
54
56
  * @param options.noText
57
+ * @param options.allowHtml
55
58
  * @returns Promise que resuelve true si se eligió Sí
56
59
  */
57
60
  async yesNo(options) {
58
- const { title, message, yesText = 'Sí', noText = 'No' } = options;
61
+ const { title, message, yesText = 'Sí', noText = 'No', allowHtml } = options;
59
62
  return this.showModal({
60
63
  title,
61
64
  message,
62
65
  type: 'yesNo',
63
66
  yesText,
64
67
  noText,
68
+ allowHtml,
65
69
  }).then((result) => result.action === 'yes');
66
70
  }
67
71
  /**
68
72
  *
69
73
  * @param title
70
74
  * @param message
75
+ * @param allowHtml
76
+ * @param confirmText
71
77
  * @returns Promise que resuelve cuando se cierra el modal
72
78
  */
73
- async info(title, message) {
79
+ async info(title, message, allowHtml, confirmText) {
74
80
  return this.showModal({
75
81
  title,
76
82
  message,
77
83
  type: 'info',
84
+ allowHtml,
85
+ confirmText,
78
86
  }).then(() => void 0);
79
87
  }
80
88
  /**
@@ -84,16 +92,18 @@ export class ModalService {
84
92
  * @param options.message
85
93
  * @param options.confirmText
86
94
  * @param options.cancelText
95
+ * @param options.allowHtml
87
96
  * @returns Promise que resuelve true si se confirmó
88
97
  */
89
98
  async warning(options) {
90
- const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar' } = options;
99
+ const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar', allowHtml } = options;
91
100
  return this.showModal({
92
101
  title,
93
102
  message,
94
103
  type: 'warning',
95
104
  confirmText,
96
105
  cancelText,
106
+ allowHtml,
97
107
  }).then((result) => result.confirmed);
98
108
  }
99
109
  /**
@@ -101,14 +111,16 @@ export class ModalService {
101
111
  * @param title
102
112
  * @param message
103
113
  * @param confirmText
114
+ * @param allowHtml
104
115
  * @returns Promise que resuelve true si se confirmó
105
116
  */
106
- async error(title, message, confirmText = 'Entendido') {
117
+ async error(title, message, confirmText = 'Entendido', allowHtml) {
107
118
  return this.showModal({
108
119
  title,
109
120
  message,
110
121
  type: 'error',
111
122
  confirmText,
123
+ allowHtml,
112
124
  }).then(() => void 0);
113
125
  }
114
126
  /**
@@ -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';\nimport type { ModalConfig, ModalResult } from './modal.types';\n\n/**\n *\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ModalService {\n private readonly isOpen = signal(false);\n private readonly config = signal<ModalConfig>({\n title: '',\n message: '',\n type: 'info',\n });\n\n private resolvePromise?: (result: ModalResult) => void;\n\n readonly modalState = {\n isOpen: this.isOpen.asReadonly(),\n config: this.config.asReadonly(),\n };\n\n /**\n *\n * @param config\n */\n async showModal(config: ModalConfig): Promise<ModalResult> {\n this.config.set(config);\n this.isOpen.set(true);\n\n return new Promise<ModalResult>((resolve) => {\n this.resolvePromise = resolve;\n });\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @returns Promise que resuelve true si se confirmó\n */\n async confirm(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar' } = options;\n return this.showModal({\n title,\n message,\n type: 'confirm',\n confirmText,\n cancelText,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.yesText\n * @param options.noText\n * @returns Promise que resuelve true si se eligió Sí\n */\n async yesNo(options: {\n title: string;\n message: string;\n yesText?: string;\n noText?: string;\n }): Promise<boolean> {\n const { title, message, yesText = 'Sí', noText = 'No' } = options;\n return this.showModal({\n title,\n message,\n type: 'yesNo',\n yesText,\n noText,\n }).then((result) => result.action === 'yes');\n }\n\n /**\n *\n * @param title\n * @param message\n * @returns Promise que resuelve cuando se cierra el modal\n */\n async info(title: string, message: string): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'info',\n }).then(() => void 0);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @returns Promise que resuelve true si se confirmó\n */\n async warning(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar' } = options;\n return this.showModal({\n title,\n message,\n type: 'warning',\n confirmText,\n cancelText,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param title\n * @param message\n * @param confirmText\n * @returns Promise que resuelve true si se confirmó\n */\n async error(\n title: string,\n message: string,\n confirmText = 'Entendido'\n ): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'error',\n confirmText,\n }).then(() => void 0);\n }\n\n /**\n * Maneja el resultado del modal y resuelve la promesa\n * @param result - Resultado de la acción del modal\n */\n handleResult(result: ModalResult): void {\n if (this.resolvePromise) {\n this.resolvePromise(result);\n this.resolvePromise = undefined;\n }\n this.closeModal();\n }\n\n /**\n * Cierra el modal actual\n */\n closeModal(): void {\n this.isOpen.set(false);\n }\n}\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';\nimport type { ModalConfig, ModalResult } from './modal.types';\n\n/**\n *\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ModalService {\n private readonly isOpen = signal(false);\n private readonly config = signal<ModalConfig>({\n title: '',\n message: '',\n type: 'info',\n });\n\n private resolvePromise?: (result: ModalResult) => void;\n\n readonly modalState = {\n isOpen: this.isOpen.asReadonly(),\n config: this.config.asReadonly(),\n };\n\n /**\n *\n * @param config\n */\n async showModal(config: ModalConfig): Promise<ModalResult> {\n this.config.set(config);\n this.isOpen.set(true);\n\n return new Promise<ModalResult>((resolve) => {\n this.resolvePromise = resolve;\n });\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async confirm(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Confirmar', cancelText = 'Cancelar', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'confirm',\n confirmText,\n cancelText,\n allowHtml,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.yesText\n * @param options.noText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se eligió Sí\n */\n async yesNo(options: {\n title: string;\n message: string;\n yesText?: string;\n noText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, yesText = 'Sí', noText = 'No', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'yesNo',\n yesText,\n noText,\n allowHtml,\n }).then((result) => result.action === 'yes');\n }\n\n /**\n *\n * @param title\n * @param message\n * @param allowHtml\n * @param confirmText\n * @returns Promise que resuelve cuando se cierra el modal\n */\n async info(title: string, message: string, allowHtml?: boolean, confirmText?: string): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'info',\n allowHtml,\n confirmText,\n }).then(() => void 0);\n }\n\n /**\n *\n * @param options\n * @param options.title\n * @param options.message\n * @param options.confirmText\n * @param options.cancelText\n * @param options.allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async warning(options: {\n title: string;\n message: string;\n confirmText?: string;\n cancelText?: string;\n allowHtml?: boolean;\n }): Promise<boolean> {\n const { title, message, confirmText = 'Entendido', cancelText = 'Cancelar', allowHtml } = options;\n return this.showModal({\n title,\n message,\n type: 'warning',\n confirmText,\n cancelText,\n allowHtml,\n }).then((result) => result.confirmed);\n }\n\n /**\n *\n * @param title\n * @param message\n * @param confirmText\n * @param allowHtml\n * @returns Promise que resuelve true si se confirmó\n */\n async error(\n title: string,\n message: string,\n confirmText = 'Entendido',\n allowHtml?: boolean\n ): Promise<void> {\n return this.showModal({\n title,\n message,\n type: 'error',\n confirmText,\n allowHtml,\n }).then(() => void 0);\n }\n\n /**\n * Maneja el resultado del modal y resuelve la promesa\n * @param result - Resultado de la acción del modal\n */\n handleResult(result: ModalResult): void {\n if (this.resolvePromise) {\n this.resolvePromise(result);\n this.resolvePromise = undefined;\n }\n this.closeModal();\n }\n\n /**\n * Cierra el modal actual\n */\n closeModal(): void {\n this.isOpen.set(false);\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"modal.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.types.ts"],"names":[],"mappings":"","sourcesContent":["export 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"]}
1
+ {"version":3,"file":"modal.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.types.ts"],"names":[],"mappings":"","sourcesContent":["export 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 allowHtml?: boolean;\n}\n\nexport interface ModalResult {\n action: 'confirm' | 'cancel' | 'yes' | 'no';\n confirmed: boolean;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export * from './navigation-card.component';
2
+ export * from './navigation-card.types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC","sourcesContent":["export * from './navigation-card.component';\nexport * from './navigation-card.types';\n"]}
@@ -0,0 +1,18 @@
1
+ import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';
2
+ import { IconComponent } from '../icon';
3
+ import * as i0 from "@angular/core";
4
+ export class NavigationCardComponent {
5
+ card = input.required(...(ngDevMode ? [{ debugName: "card" }] : []));
6
+ active = input(false, ...(ngDevMode ? [{ debugName: "active" }] : []));
7
+ cardClick = output();
8
+ onCardClick() {
9
+ this.cardClick.emit(this.card());
10
+ }
11
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: NavigationCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.10", type: NavigationCardComponent, isStandalone: true, selector: "c80-navigation-card", inputs: { card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cardClick: "cardClick" }, ngImport: i0, template: "<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>", styles: [".nav-card{background:var(--color-bg-primary);border:1px solid var(--color-border-default);border-radius:12px;padding:24px;cursor:pointer;transition:all .1s ease;display:flex;flex-direction:column;align-items:center;text-align:center;min-height:140px;justify-content:center;width:100%;font-family:inherit;font-size:inherit}.nav-card:hover{background:var(--color-bg-hover);box-shadow:var(--shadow-md);transform:translateY(-1px);border-color:var(--color-border-medium)}.nav-card.active{background:var(--color-bg-tertiary);border-color:var(--color-text-primary)}.nav-card:focus-visible{outline:none}.nav-card .card-icon{margin-bottom:12px;display:flex;justify-content:center;align-items:center}.nav-card .card-title{font-size:16px;font-weight:600;margin:0;color:var(--color-text-primary);transition:color .2s}@media(max-width:768px){.nav-card{min-height:120px;padding:20px}.nav-card .card-icon{font-size:40px;width:40px;height:40px}.nav-card .card-title{font-size:14px}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13
+ }
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: NavigationCardComponent, decorators: [{
15
+ type: Component,
16
+ args: [{ selector: 'c80-navigation-card', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>", styles: [".nav-card{background:var(--color-bg-primary);border:1px solid var(--color-border-default);border-radius:12px;padding:24px;cursor:pointer;transition:all .1s ease;display:flex;flex-direction:column;align-items:center;text-align:center;min-height:140px;justify-content:center;width:100%;font-family:inherit;font-size:inherit}.nav-card:hover{background:var(--color-bg-hover);box-shadow:var(--shadow-md);transform:translateY(-1px);border-color:var(--color-border-medium)}.nav-card.active{background:var(--color-bg-tertiary);border-color:var(--color-text-primary)}.nav-card:focus-visible{outline:none}.nav-card .card-icon{margin-bottom:12px;display:flex;justify-content:center;align-items:center}.nav-card .card-title{font-size:16px;font-weight:600;margin:0;color:var(--color-text-primary);transition:color .2s}@media(max-width:768px){.nav-card{min-height:120px;padding:20px}.nav-card .card-icon{font-size:40px;width:40px;height:40px}.nav-card .card-title{font-size:14px}}\n"] }]
17
+ }], propDecorators: { card: [{ type: i0.Input, args: [{ isSignal: true, alias: "card", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], cardClick: [{ type: i0.Output, args: ["cardClick"] }] } });
18
+ //# sourceMappingURL=navigation-card.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-card.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/navigation-card.component.ts","../../../../../libs/ui/src/lib/navigation-card/navigation-card.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;AAaxC,MAAM,OAAO,uBAAuB;IACvB,IAAI,GAAG,KAAK,CAAC,QAAQ,+CAAkB,CAAC;IACxC,MAAM,GAAG,KAAK,CAAU,KAAK,kDAAC,CAAC;IAC/B,SAAS,GAAG,MAAM,EAAkB,CAAC;IAE9C,WAAW;QACP,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;wGAPQ,uBAAuB;4FAAvB,uBAAuB,+WCdpC,gPAGS,kgCDMK,aAAa;;4FAKd,uBAAuB;kBATnC,SAAS;+BAEI,qBAAqB,cACnB,IAAI,WACP,CAAC,aAAa,CAAC,mBAGP,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';\nimport { IconComponent } from '../icon';\nimport type { NavigationCard } from './navigation-card.types';\n\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-navigation-card',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './navigation-card.component.html',\n styleUrl: './navigation-card.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class NavigationCardComponent {\n readonly card = input.required<NavigationCard>();\n readonly active = input<boolean>(false);\n readonly cardClick = output<NavigationCard>();\n\n onCardClick(): void {\n this.cardClick.emit(this.card());\n }\n}\n","<button type=\"button\" class=\"nav-card\" [class.active]=\"active()\" (click)=\"onCardClick()\">\n <c80-icon [icon]=\"card().icon\" [size]=\"1.7\" class=\"card-icon\" />\n <h3 class=\"card-title\">{{ card().title }}</h3>\n</button>"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=navigation-card.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-card.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/navigation-card/navigation-card.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { IconType } from '../icon';\n\nexport interface NavigationCard {\n readonly title: string;\n readonly icon: IconType;\n readonly route: string;\n readonly permission?: string;\n}\n"]}
@@ -1,4 +1,5 @@
1
- import { Injectable } from '@angular/core';
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { TableDataConverterService } from './table-data-converter.service';
2
3
  import * as i0 from "@angular/core";
3
4
  /**
4
5
  * Servicio para mapear automáticamente datos de tabla a DTOs
@@ -7,9 +8,15 @@ import * as i0 from "@angular/core";
7
8
  * Reglas de exclusión:
8
9
  * - readOnly: true → campo NO se incluye
9
10
  * - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)
11
+ * - undefined / null → campo NO se incluye (no hubo cambio)
12
+ * - '' (cadena vacía) → se envía null para LIMPIAR el campo
10
13
  * - readOnly: false o undefined → campo se incluye
14
+ *
15
+ * La conversión de tipos delega en TableDataConverterService (que acepta
16
+ * strings, tal como llegan desde los inputs HTML).
11
17
  */
12
18
  export class TableDtoMapperService {
19
+ converter = inject(TableDataConverterService);
13
20
  /**
14
21
  * Mapea un objeto de fila a DTO, excluyendo campos readOnly e id
15
22
  * @param row - Datos de la fila
@@ -23,10 +30,16 @@ export class TableDtoMapperService {
23
30
  const editableColumns = columns.filter(col => !col.readOnly && col.accessor !== 'id');
24
31
  for (const col of editableColumns) {
25
32
  const value = row[col.accessor];
26
- // Solo incluir si el valor existe
27
- if (value !== undefined && value !== null && value !== '') {
28
- dto[col.accessor] = this.convertValue(value, col);
33
+ // undefined / null: el campo no cambió, no se incluye
34
+ if (value === undefined || value === null) {
35
+ continue;
36
+ }
37
+ // Cadena vacía: se interpreta como "limpiar el campo" → null explícito
38
+ if (value === '') {
39
+ dto[col.accessor] = null;
40
+ continue;
29
41
  }
42
+ dto[col.accessor] = this.convertValue(value, col);
30
43
  }
31
44
  // Agregar campos adicionales (ej: boxId, profileId)
32
45
  if (additionalFields) {
@@ -35,7 +48,8 @@ export class TableDtoMapperService {
35
48
  return dto;
36
49
  }
37
50
  /**
38
- * Convierte un valor según el tipo de columna
51
+ * Convierte un valor según el tipo de columna, reutilizando
52
+ * TableDataConverterService (acepta strings provenientes de inputs HTML).
39
53
  * @param value - Valor a convertir
40
54
  * @param col - Definición de columna
41
55
  * @returns Valor convertido
@@ -43,49 +57,32 @@ export class TableDtoMapperService {
43
57
  convertValue(value, col) {
44
58
  switch (col.type) {
45
59
  case 'integer':
46
- return this.toInteger(value, col);
60
+ return this.applyBounds(this.converter.toInteger(value), col);
47
61
  case 'number':
48
- return this.toNumber(value);
62
+ return this.converter.toNumber(value);
49
63
  case 'boolean':
50
- return this.toBoolean(value);
64
+ return this.converter.toBoolean(value);
51
65
  case 'string':
52
66
  case 'password':
53
67
  case 'enum':
54
- return this.toString(value);
68
+ return this.converter.toStringValue(value);
55
69
  default:
56
70
  return value;
57
71
  }
58
72
  }
59
- toInteger(value, col) {
60
- if (typeof value !== 'number')
73
+ /**
74
+ * Aplica los límites min/max declarados en la columna a un valor numérico.
75
+ */
76
+ applyBounds(value, col) {
77
+ if (value === undefined)
61
78
  return undefined;
62
- let result = Math.floor(value);
63
- // Aplicar min/max si existen
79
+ let result = value;
64
80
  if (col.min !== undefined)
65
81
  result = Math.max(result, col.min);
66
82
  if (col.max !== undefined)
67
83
  result = Math.min(result, col.max);
68
84
  return result;
69
85
  }
70
- toNumber(value) {
71
- if (typeof value === 'number')
72
- return value;
73
- if (typeof value === 'string') {
74
- const num = Number(value);
75
- return Number.isNaN(num) ? undefined : num;
76
- }
77
- return undefined;
78
- }
79
- toBoolean(value) {
80
- if (typeof value === 'boolean')
81
- return value;
82
- if (typeof value === 'string')
83
- return value.toLowerCase() === 'true';
84
- return Boolean(value);
85
- }
86
- toString(value) {
87
- return String(value);
88
- }
89
86
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableDtoMapperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
90
87
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableDtoMapperService, providedIn: 'root' });
91
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"table-dto-mapper.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-dto-mapper.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable } from '@angular/core';\nimport type { TableColDef } from './table.types';\n\n/**\n * Servicio para mapear automáticamente datos de tabla a DTOs\n * basándose en la configuración de TableColDef.\n * \n * Reglas de exclusión:\n * - readOnly: true → campo NO se incluye\n * - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)\n * - readOnly: false o undefined → campo se incluye\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDtoMapperService {\n\n /**\n * Mapea un objeto de fila a DTO, excluyendo campos readOnly e id\n * @param row - Datos de la fila\n * @param columns - Definiciones de columnas\n * @param additionalFields - Campos adicionales a agregar al DTO (ej: boxId)\n * @returns DTO con solo campos editables (sin id)\n */\n mapToDto(\n row: Record<string, unknown>,\n columns: TableColDef[],\n additionalFields?: Record<string, unknown>\n ): Record<string, unknown> {\n const dto: Record<string, unknown> = {};\n\n // Mapear solo columnas NO readOnly y NO id\n const editableColumns = columns.filter(col =>\n !col.readOnly && col.accessor !== 'id'\n );\n\n for (const col of editableColumns) {\n const value = row[col.accessor];\n\n // Solo incluir si el valor existe\n if (value !== undefined && value !== null && value !== '') {\n dto[col.accessor] = this.convertValue(value, col);\n }\n }\n\n // Agregar campos adicionales (ej: boxId, profileId)\n if (additionalFields) {\n Object.assign(dto, additionalFields);\n }\n\n return dto;\n }\n\n /**\n * Convierte un valor según el tipo de columna\n * @param value - Valor a convertir\n * @param col - Definición de columna\n * @returns Valor convertido\n */\n private convertValue(value: unknown, col: TableColDef): unknown {\n switch (col.type) {\n case 'integer':\n return this.toInteger(value, col);\n case 'number':\n return this.toNumber(value);\n case 'boolean':\n return this.toBoolean(value);\n case 'string':\n case 'password':\n case 'enum':\n return this.toString(value);\n default:\n return value;\n }\n }\n\n private toInteger(value: unknown, col: TableColDef): number | undefined {\n if (typeof value !== 'number') return undefined;\n\n let result = Math.floor(value);\n\n // Aplicar min/max si existen\n if (col.min !== undefined) result = Math.max(result, col.min);\n if (col.max !== undefined) result = Math.min(result, col.max);\n\n return result;\n }\n\n private toNumber(value: unknown): number | undefined {\n if (typeof value === 'number') return value;\n if (typeof value === 'string') {\n const num = Number(value);\n return Number.isNaN(num) ? undefined : num;\n }\n return undefined;\n }\n\n private toBoolean(value: unknown): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') return value.toLowerCase() === 'true';\n return Boolean(value);\n }\n\n private toString(value: unknown): string {\n return String(value);\n }\n}\n"]}
1
+ {"version":3,"file":"table-dto-mapper.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-dto-mapper.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;;AAE3E;;;;;;;;;;;;;GAaG;AAIH,MAAM,OAAO,qBAAqB;IAEb,SAAS,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAE/D;;;;;;OAMG;IACH,QAAQ,CACJ,GAA4B,EAC5B,OAAsB,EACtB,gBAA0C;QAE1C,MAAM,GAAG,GAA4B,EAAE,CAAC;QAExC,2CAA2C;QAC3C,MAAM,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACzC,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,CACzC,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAEhC,sDAAsD;YACtD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACxC,SAAS;YACb,CAAC;YAED,uEAAuE;YACvE,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;gBACf,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;gBACzB,SAAS;YACb,CAAC;YAED,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACtD,CAAC;QAED,oDAAoD;QACpD,IAAI,gBAAgB,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,GAAG,CAAC;IACf,CAAC;IAED;;;;;;OAMG;IACK,YAAY,CAAC,KAAc,EAAE,GAAgB;QACjD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,SAAS;gBACV,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;YAClE,KAAK,QAAQ;gBACT,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC1C,KAAK,SAAS;gBACV,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAC3C,KAAK,QAAQ,CAAC;YACd,KAAK,UAAU,CAAC;YAChB,KAAK,MAAM;gBACP,OAAO,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC/C;gBACI,OAAO,KAAK,CAAC;QACrB,CAAC;IACL,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,KAAyB,EAAE,GAAgB;QAC3D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAE1C,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;YAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9D,IAAI,GAAG,CAAC,GAAG,KAAK,SAAS;YAAE,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QAE9D,OAAO,MAAM,CAAC;IAClB,CAAC;wGAnFQ,qBAAqB;4GAArB,qBAAqB,cAFlB,MAAM;;4FAET,qBAAqB;kBAHjC,UAAU;mBAAC;oBACR,UAAU,EAAE,MAAM;iBACrB","sourcesContent":["import { Injectable, inject } from '@angular/core';\nimport type { TableColDef } from './table.types';\nimport { TableDataConverterService } from './table-data-converter.service';\n\n/**\n * Servicio para mapear automáticamente datos de tabla a DTOs\n * basándose en la configuración de TableColDef.\n *\n * Reglas de exclusión:\n * - readOnly: true → campo NO se incluye\n * - accessor: 'id' → campo NO se incluye (IDs van en URL, no en body)\n * - undefined / null → campo NO se incluye (no hubo cambio)\n * - '' (cadena vacía) → se envía null para LIMPIAR el campo\n * - readOnly: false o undefined → campo se incluye\n *\n * La conversión de tipos delega en TableDataConverterService (que acepta\n * strings, tal como llegan desde los inputs HTML).\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableDtoMapperService {\n\n private readonly converter = inject(TableDataConverterService);\n\n /**\n * Mapea un objeto de fila a DTO, excluyendo campos readOnly e id\n * @param row - Datos de la fila\n * @param columns - Definiciones de columnas\n * @param additionalFields - Campos adicionales a agregar al DTO (ej: boxId)\n * @returns DTO con solo campos editables (sin id)\n */\n mapToDto(\n row: Record<string, unknown>,\n columns: TableColDef[],\n additionalFields?: Record<string, unknown>\n ): Record<string, unknown> {\n const dto: Record<string, unknown> = {};\n\n // Mapear solo columnas NO readOnly y NO id\n const editableColumns = columns.filter(col =>\n !col.readOnly && col.accessor !== 'id'\n );\n\n for (const col of editableColumns) {\n const value = row[col.accessor];\n\n // undefined / null: el campo no cambió, no se incluye\n if (value === undefined || value === null) {\n continue;\n }\n\n // Cadena vacía: se interpreta como \"limpiar el campo\" → null explícito\n if (value === '') {\n dto[col.accessor] = null;\n continue;\n }\n\n dto[col.accessor] = this.convertValue(value, col);\n }\n\n // Agregar campos adicionales (ej: boxId, profileId)\n if (additionalFields) {\n Object.assign(dto, additionalFields);\n }\n\n return dto;\n }\n\n /**\n * Convierte un valor según el tipo de columna, reutilizando\n * TableDataConverterService (acepta strings provenientes de inputs HTML).\n * @param value - Valor a convertir\n * @param col - Definición de columna\n * @returns Valor convertido\n */\n private convertValue(value: unknown, col: TableColDef): unknown {\n switch (col.type) {\n case 'integer':\n return this.applyBounds(this.converter.toInteger(value), col);\n case 'number':\n return this.converter.toNumber(value);\n case 'boolean':\n return this.converter.toBoolean(value);\n case 'string':\n case 'password':\n case 'enum':\n return this.converter.toStringValue(value);\n default:\n return value;\n }\n }\n\n /**\n * Aplica los límites min/max declarados en la columna a un valor numérico.\n */\n private applyBounds(value: number | undefined, col: TableColDef): number | undefined {\n if (value === undefined) return undefined;\n\n let result = value;\n if (col.min !== undefined) result = Math.max(result, col.min);\n if (col.max !== undefined) result = Math.min(result, col.max);\n\n return result;\n }\n}\n"]}
@@ -14,7 +14,7 @@ export class TableSelectionService {
14
14
  * Inicializa el estado de selección para una nueva tabla
15
15
  * @returns Objeto con signals y métodos de selección
16
16
  */
17
- createSelectionState() {
17
+ createSelectionState(getRowId = (item) => item['id']) {
18
18
  const selectedItems = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
19
19
  const selectAllChecked = signal(false, ...(ngDevMode ? [{ debugName: "selectAllChecked" }] : []));
20
20
  const selectAllIndeterminate = signal(false, ...(ngDevMode ? [{ debugName: "selectAllIndeterminate" }] : []));
@@ -24,11 +24,11 @@ export class TableSelectionService {
24
24
  selectAllChecked: selectAllChecked.asReadonly(),
25
25
  selectAllIndeterminate: selectAllIndeterminate.asReadonly(),
26
26
  clearSelection: () => this.clearSelection(signals),
27
- toggleSelectAll: (allItems) => this.toggleSelectAll(signals, allItems),
28
- toggleItemSelection: (item, multiple) => this.toggleItemSelection(selectedItems, item, multiple),
29
- isItemSelected: (item) => this.isItemSelected(selectedItems, item),
30
- preserveSelection: (newData) => this.preserveSelection(signals, newData),
31
- getSelectedItems: (allData) => this.getSelectedItems(selectedItems, allData),
27
+ toggleSelectAll: (allItems) => this.toggleSelectAll(signals, allItems, getRowId),
28
+ toggleItemSelection: (item, multiple) => this.toggleItemSelection(selectedItems, item, multiple, getRowId),
29
+ isItemSelected: (item) => this.isItemSelected(selectedItems, item, getRowId),
30
+ preserveSelection: (newData) => this.preserveSelection(signals, newData, getRowId),
31
+ getSelectedItems: (allData) => this.getSelectedItems(selectedItems, allData, getRowId),
32
32
  };
33
33
  }
34
34
  clearSelection(signals) {
@@ -36,7 +36,7 @@ export class TableSelectionService {
36
36
  signals.selectAllChecked.set(false);
37
37
  signals.selectAllIndeterminate.set(false);
38
38
  }
39
- toggleSelectAll(signals, allItems) {
39
+ toggleSelectAll(signals, allItems, getRowId) {
40
40
  const currentSelection = signals.selectedItems();
41
41
  if (currentSelection.size === allItems.length) {
42
42
  signals.selectedItems.set(new Set());
@@ -44,7 +44,7 @@ export class TableSelectionService {
44
44
  signals.selectAllIndeterminate.set(false);
45
45
  }
46
46
  else {
47
- const allIds = new Set(allItems.map(item => item['id']));
47
+ const allIds = new Set(allItems.map(getRowId));
48
48
  signals.selectedItems.set(allIds);
49
49
  this.updateSelectAllState({
50
50
  allItems,
@@ -54,8 +54,8 @@ export class TableSelectionService {
54
54
  });
55
55
  }
56
56
  }
57
- toggleItemSelection(selectedItems, item, multiple) {
58
- const id = item['id'];
57
+ toggleItemSelection(selectedItems, item, multiple, getRowId) {
58
+ const id = getRowId(item);
59
59
  const currentSelection = new Set(selectedItems());
60
60
  if (!multiple) {
61
61
  currentSelection.clear();
@@ -71,16 +71,16 @@ export class TableSelectionService {
71
71
  }
72
72
  selectedItems.set(currentSelection);
73
73
  }
74
- isItemSelected(selectedItems, item) {
75
- return selectedItems().has(item['id']);
74
+ isItemSelected(selectedItems, item, getRowId) {
75
+ return selectedItems().has(getRowId(item));
76
76
  }
77
- preserveSelection(signals, newData) {
77
+ preserveSelection(signals, newData, getRowId) {
78
78
  const currentSelection = signals.selectedItems();
79
79
  if (currentSelection.size === 0 || newData.length === 0) {
80
80
  this.clearSelection(signals);
81
81
  return;
82
82
  }
83
- const availableIds = new Set(newData.map(item => item['id']));
83
+ const availableIds = new Set(newData.map(getRowId));
84
84
  const preservedSelection = new Set(Array.from(currentSelection).filter(id => availableIds.has(id)));
85
85
  signals.selectedItems.set(preservedSelection);
86
86
  this.updateSelectAllState({
@@ -90,9 +90,9 @@ export class TableSelectionService {
90
90
  selectAllIndeterminate: signals.selectAllIndeterminate
91
91
  });
92
92
  }
93
- getSelectedItems(selectedItems, allData) {
93
+ getSelectedItems(selectedItems, allData, getRowId) {
94
94
  const selectedIds = selectedItems();
95
- return allData.filter(item => selectedIds.has(item['id']));
95
+ return allData.filter(item => selectedIds.has(getRowId(item)));
96
96
  }
97
97
  updateSelectAllState(context) {
98
98
  const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;
@@ -1 +1 @@
1
- {"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type OutputEmitterRef, Injectable, signal, type Signal } from '@angular/core';\n\ninterface SelectionState<T extends Record<string, unknown>> {\n selectedItems: Signal<Set<string>>;\n selectAllChecked: Signal<boolean>;\n selectAllIndeterminate: Signal<boolean>;\n clearSelection: () => void;\n toggleSelectAll: (allItems: T[]) => void;\n toggleItemSelection: (item: T, multiple: boolean) => void;\n isItemSelected: (item: T) => boolean;\n preserveSelection: (newData: T[]) => void;\n getSelectedItems: (allData: T[]) => T[];\n}\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>(): SelectionState<T> {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(item => item['id'] as string));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState({\n allItems,\n selectedCount: allIds.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean\n ): void {\n const id = item['id'] as string;\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T\n ): boolean {\n return selectedItems().has(item['id'] as string);\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[]\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(item => item['id'] as string));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState({\n allItems: newData,\n selectedCount: preservedSelection.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[]\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(item['id'] as string));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(context: {\n allItems: T[];\n selectedCount: number;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}
1
+ {"version":3,"file":"table-selection.service.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table-selection.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { type OutputEmitterRef, Injectable, signal, type Signal } from '@angular/core';\n\ninterface SelectionState<T extends Record<string, unknown>> {\n selectedItems: Signal<Set<string>>;\n selectAllChecked: Signal<boolean>;\n selectAllIndeterminate: Signal<boolean>;\n clearSelection: () => void;\n toggleSelectAll: (allItems: T[]) => void;\n toggleItemSelection: (item: T, multiple: boolean) => void;\n isItemSelected: (item: T) => boolean;\n preserveSelection: (newData: T[]) => void;\n getSelectedItems: (allData: T[]) => T[];\n}\n\n/**\n * Servicio para gestionar la selección de elementos en tablas C80\n *\n * Maneja:\n * - Selección simple y múltiple\n * - Estado de selección completa\n * - Preservación de selección tras actualizaciones de datos\n * - Emisión de eventos de selección\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class TableSelectionService {\n\n /**\n * Inicializa el estado de selección para una nueva tabla\n * @returns Objeto con signals y métodos de selección\n */\n createSelectionState<T extends Record<string, unknown>>(\n getRowId: (item: T) => string = (item) => item['id'] as string\n ): SelectionState<T> {\n const selectedItems = signal<Set<string>>(new Set());\n const selectAllChecked = signal(false);\n const selectAllIndeterminate = signal(false);\n\n const signals = { selectedItems, selectAllChecked, selectAllIndeterminate };\n\n return {\n selectedItems: selectedItems.asReadonly(),\n selectAllChecked: selectAllChecked.asReadonly(),\n selectAllIndeterminate: selectAllIndeterminate.asReadonly(),\n clearSelection: () => this.clearSelection(signals),\n toggleSelectAll: (allItems: T[]) => this.toggleSelectAll(signals, allItems, getRowId),\n toggleItemSelection: (item: T, multiple: boolean) => this.toggleItemSelection(selectedItems, item, multiple, getRowId),\n isItemSelected: (item: T) => this.isItemSelected(selectedItems, item, getRowId),\n preserveSelection: (newData: T[]) => this.preserveSelection(signals, newData, getRowId),\n getSelectedItems: (allData: T[]) => this.getSelectedItems(selectedItems, allData, getRowId),\n };\n }\n\n private clearSelection(signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n }\n\n private toggleSelectAll<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n allItems: T[],\n getRowId: (item: T) => string\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === allItems.length) {\n signals.selectedItems.set(new Set());\n signals.selectAllChecked.set(false);\n signals.selectAllIndeterminate.set(false);\n } else {\n const allIds = new Set(allItems.map(getRowId));\n signals.selectedItems.set(allIds);\n this.updateSelectAllState({\n allItems,\n selectedCount: allIds.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n }\n\n private toggleItemSelection<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n multiple: boolean,\n getRowId: (item: T) => string\n ): void {\n const id = getRowId(item);\n const currentSelection = new Set(selectedItems());\n\n if (!multiple) {\n currentSelection.clear();\n if (!selectedItems().has(id)) {\n currentSelection.add(id);\n }\n } else if (currentSelection.has(id)) {\n currentSelection.delete(id);\n } else {\n currentSelection.add(id);\n }\n\n selectedItems.set(currentSelection);\n }\n\n private isItemSelected<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n item: T,\n getRowId: (item: T) => string\n ): boolean {\n return selectedItems().has(getRowId(item));\n }\n\n private preserveSelection<T extends Record<string, unknown>>(\n signals: {\n selectedItems: ReturnType<typeof signal<Set<string>>>;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n },\n newData: T[],\n getRowId: (item: T) => string\n ): void {\n const currentSelection = signals.selectedItems();\n\n if (currentSelection.size === 0 || newData.length === 0) {\n this.clearSelection(signals);\n return;\n }\n\n const availableIds = new Set(newData.map(getRowId));\n const preservedSelection = new Set(\n Array.from(currentSelection).filter(id => availableIds.has(id))\n );\n\n signals.selectedItems.set(preservedSelection);\n this.updateSelectAllState({\n allItems: newData,\n selectedCount: preservedSelection.size,\n selectAllChecked: signals.selectAllChecked,\n selectAllIndeterminate: signals.selectAllIndeterminate\n });\n }\n\n private getSelectedItems<T extends Record<string, unknown>>(\n selectedItems: ReturnType<typeof signal<Set<string>>>,\n allData: T[],\n getRowId: (item: T) => string\n ): T[] {\n const selectedIds = selectedItems();\n return allData.filter(item => selectedIds.has(getRowId(item)));\n }\n\n private updateSelectAllState<T extends Record<string, unknown>>(context: {\n allItems: T[];\n selectedCount: number;\n selectAllChecked: ReturnType<typeof signal<boolean>>;\n selectAllIndeterminate: ReturnType<typeof signal<boolean>>;\n }): void {\n const { allItems, selectedCount, selectAllChecked, selectAllIndeterminate } = context;\n const totalCount = allItems.length;\n\n if (selectedCount === 0) {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(false);\n } else if (selectedCount === totalCount) {\n selectAllChecked.set(true);\n selectAllIndeterminate.set(false);\n } else {\n selectAllChecked.set(false);\n selectAllIndeterminate.set(true);\n }\n }\n\n /**\n * Emite los elementos seleccionados a través del output proporcionado\n * @param selectionState - Estado de selección\n * @param allData - Todos los datos de la tabla\n * @param selectableEmitter - Output para emitir la selección\n */\n emitSelection<T extends Record<string, unknown>>(\n selectionState: { getSelectedItems: (allData: T[]) => T[] },\n allData: T[],\n selectableEmitter: OutputEmitterRef<T[]>\n ): void {\n const selectedItems = selectionState.getSelectedItems(allData);\n selectableEmitter.emit(selectedItems);\n }\n}\n"]}