@c80/ui 0.0.1 → 1.0.1
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.
- package/esm2022/index.mjs +3 -2
- package/esm2022/lib/icon/icon.component.mjs +121 -0
- package/esm2022/lib/table/table.component.mjs +237 -0
- package/index.d.ts +2 -1
- package/lib/icon/icon.component.d.ts +31 -0
- package/lib/table/table.component.d.ts +60 -0
- package/package.json +5 -3
- package/esm2022/lib/ui/ui.component.mjs +0 -12
- package/lib/ui/ui.component.d.ts +0 -5
package/esm2022/index.mjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export * from './lib/
|
|
2
|
-
|
|
1
|
+
export * from './lib/table/table.component';
|
|
2
|
+
export * from './lib/icon/icon.component';
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9saWJzL3VpL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLDZCQUE2QixDQUFDO0FBQzVDLGNBQWMsMkJBQTJCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgKiBmcm9tICcuL2xpYi90YWJsZS90YWJsZS5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvaWNvbi9pY29uLmNvbXBvbmVudCc7XG4iXX0=
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/common";
|
|
5
|
+
export class C80IconComponent {
|
|
6
|
+
/** Tamaño base del icono (en px) */
|
|
7
|
+
get iconSize() {
|
|
8
|
+
return 24 * this.size;
|
|
9
|
+
}
|
|
10
|
+
icon = 'check';
|
|
11
|
+
color = 'primary';
|
|
12
|
+
disabled = false;
|
|
13
|
+
size = 1;
|
|
14
|
+
/** Si es true, renderiza como <button> nativo, si es false solo como icono */
|
|
15
|
+
_button = false;
|
|
16
|
+
set button(val) {
|
|
17
|
+
// Permite usar 'button' a secas, cualquier valor que no sea null/undefined/false es true
|
|
18
|
+
this._button = val !== null && val !== undefined && val !== false && val !== 'false';
|
|
19
|
+
}
|
|
20
|
+
get button() {
|
|
21
|
+
return this._button;
|
|
22
|
+
}
|
|
23
|
+
/** Tipo de botón nativo (solo si button=true) */
|
|
24
|
+
type = 'button';
|
|
25
|
+
/** Output para click (solo si button=true) */
|
|
26
|
+
iconClick = new EventEmitter();
|
|
27
|
+
checkIconTpl;
|
|
28
|
+
cancelIconTpl;
|
|
29
|
+
editIconTpl;
|
|
30
|
+
deleteIconTpl;
|
|
31
|
+
addIconTpl;
|
|
32
|
+
defaultIconTpl;
|
|
33
|
+
getIconTemplate() {
|
|
34
|
+
switch (this.icon) {
|
|
35
|
+
case 'check': return this.checkIconTpl;
|
|
36
|
+
case 'cancel': return this.cancelIconTpl;
|
|
37
|
+
case 'edit': return this.editIconTpl;
|
|
38
|
+
case 'delete': return this.deleteIconTpl;
|
|
39
|
+
case 'add': return this.addIconTpl;
|
|
40
|
+
default: return this.defaultIconTpl;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
get iconColor() {
|
|
44
|
+
if (this.disabled) {
|
|
45
|
+
return '#bdbdbd'; // gris deshabilitado
|
|
46
|
+
}
|
|
47
|
+
const palettes = {
|
|
48
|
+
check: {
|
|
49
|
+
primary: '#00234bad',
|
|
50
|
+
secondary: '#6c757d',
|
|
51
|
+
warn: '#e53935',
|
|
52
|
+
},
|
|
53
|
+
cancel: {
|
|
54
|
+
primary: '#00234bad',
|
|
55
|
+
secondary: '#6c757d',
|
|
56
|
+
warn: '#e53935',
|
|
57
|
+
},
|
|
58
|
+
edit: {
|
|
59
|
+
primary: '#00234bad',
|
|
60
|
+
secondary: '#6c757d',
|
|
61
|
+
warn: '#e53935',
|
|
62
|
+
},
|
|
63
|
+
delete: {
|
|
64
|
+
primary: '#00234bad',
|
|
65
|
+
secondary: '#6c757d',
|
|
66
|
+
warn: '#e53935',
|
|
67
|
+
},
|
|
68
|
+
add: {
|
|
69
|
+
primary: '#00234bad',
|
|
70
|
+
secondary: '#6c757d',
|
|
71
|
+
warn: '#e53935',
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return palettes[this.icon]?.[this.color] ?? '#222';
|
|
75
|
+
}
|
|
76
|
+
// Handler para click en modo button
|
|
77
|
+
onButtonClick(event) {
|
|
78
|
+
if (!this.disabled) {
|
|
79
|
+
this.iconClick.emit(event);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C80IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
83
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: C80IconComponent, isStandalone: true, selector: "c80-icon", inputs: { icon: "icon", color: "color", disabled: "disabled", size: "size", button: "button", type: "type" }, outputs: { iconClick: "iconClick" }, viewQueries: [{ propertyName: "checkIconTpl", first: true, predicate: ["checkIcon"], descendants: true, static: true }, { propertyName: "cancelIconTpl", first: true, predicate: ["cancelIcon"], descendants: true, static: true }, { propertyName: "editIconTpl", first: true, predicate: ["editIcon"], descendants: true, static: true }, { propertyName: "deleteIconTpl", first: true, predicate: ["deleteIcon"], descendants: true, static: true }, { propertyName: "addIconTpl", first: true, predicate: ["addIcon"], descendants: true, static: true }, { propertyName: "defaultIconTpl", first: true, predicate: ["defaultIcon"], descendants: true, static: true }], ngImport: i0, template: "@if (button) {\r\n<button type=\"{{type}}\" [disabled]=\"disabled\" class=\"icon-button\" [style.width.px]=\"iconSize + 8\"\r\n [style.height.px]=\"iconSize + 8\" (click)=\"onButtonClick($event)\">\r\n <ng-container *ngTemplateOutlet=\"getIconTemplate()\"></ng-container>\r\n</button>\r\n} @else {\r\n<span class=\"icon-span\" [style.width.px]=\"iconSize\" [style.height.px]=\"iconSize\">\r\n <ng-container *ngTemplateOutlet=\"getIconTemplate()\"></ng-container>\r\n</span>\r\n}\r\n\r\n<ng-template #checkIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M5 13l4 4L19 7\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #cancelIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M6 6l12 12M6 18L18 6\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #editIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <rect x=\"5\" y=\"19\" width=\"14\" height=\"2\" rx=\"1\" [attr.fill]=\"iconColor\" />\r\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #deleteIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" [attr.fill]=\"iconColor\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #addIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M12 5v14M5 12h14\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #defaultIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" />\r\n </svg>\r\n</ng-template>", styles: [":host .icon-button{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;background:transparent;border-radius:50%;min-width:0;min-height:0;padding:4px;cursor:pointer;transition:background .2s;box-sizing:border-box}:host .icon-button:focus-visible{outline:2px solid #1976d2;outline-offset:2px}:host .icon-button:hover:not(:disabled){background:#1976d214}:host .icon-button:active:not(:disabled){background:#1976d229}:host .icon-button:disabled{opacity:.5;cursor:default;background:transparent}:host .icon-span,:host .icon-button{margin-left:4px;margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
84
|
+
}
|
|
85
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C80IconComponent, decorators: [{
|
|
86
|
+
type: Component,
|
|
87
|
+
args: [{ selector: 'c80-icon', standalone: true, imports: [CommonModule], template: "@if (button) {\r\n<button type=\"{{type}}\" [disabled]=\"disabled\" class=\"icon-button\" [style.width.px]=\"iconSize + 8\"\r\n [style.height.px]=\"iconSize + 8\" (click)=\"onButtonClick($event)\">\r\n <ng-container *ngTemplateOutlet=\"getIconTemplate()\"></ng-container>\r\n</button>\r\n} @else {\r\n<span class=\"icon-span\" [style.width.px]=\"iconSize\" [style.height.px]=\"iconSize\">\r\n <ng-container *ngTemplateOutlet=\"getIconTemplate()\"></ng-container>\r\n</span>\r\n}\r\n\r\n<ng-template #checkIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M5 13l4 4L19 7\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #cancelIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M6 6l12 12M6 18L18 6\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #editIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <rect x=\"5\" y=\"19\" width=\"14\" height=\"2\" rx=\"1\" [attr.fill]=\"iconColor\" />\r\n <path d=\"M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #deleteIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M6 19a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\" [attr.fill]=\"iconColor\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #addIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <path d=\"M12 5v14M5 12h14\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" stroke-linecap=\"round\" />\r\n </svg>\r\n</ng-template>\r\n<ng-template #defaultIcon>\r\n <svg [attr.width]=\"iconSize\" [attr.height]=\"iconSize\" viewBox=\"0 0 24 24\" fill=\"none\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\" [attr.stroke]=\"iconColor\" stroke-width=\"2\" />\r\n </svg>\r\n</ng-template>", styles: [":host .icon-button{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;background:transparent;border-radius:50%;min-width:0;min-height:0;padding:4px;cursor:pointer;transition:background .2s;box-sizing:border-box}:host .icon-button:focus-visible{outline:2px solid #1976d2;outline-offset:2px}:host .icon-button:hover:not(:disabled){background:#1976d214}:host .icon-button:active:not(:disabled){background:#1976d229}:host .icon-button:disabled{opacity:.5;cursor:default;background:transparent}:host .icon-span,:host .icon-button{margin-left:4px;margin-right:4px}\n"] }]
|
|
88
|
+
}], propDecorators: { icon: [{
|
|
89
|
+
type: Input
|
|
90
|
+
}], color: [{
|
|
91
|
+
type: Input
|
|
92
|
+
}], disabled: [{
|
|
93
|
+
type: Input
|
|
94
|
+
}], size: [{
|
|
95
|
+
type: Input
|
|
96
|
+
}], button: [{
|
|
97
|
+
type: Input
|
|
98
|
+
}], type: [{
|
|
99
|
+
type: Input
|
|
100
|
+
}], iconClick: [{
|
|
101
|
+
type: Output
|
|
102
|
+
}], checkIconTpl: [{
|
|
103
|
+
type: ViewChild,
|
|
104
|
+
args: ['checkIcon', { static: true }]
|
|
105
|
+
}], cancelIconTpl: [{
|
|
106
|
+
type: ViewChild,
|
|
107
|
+
args: ['cancelIcon', { static: true }]
|
|
108
|
+
}], editIconTpl: [{
|
|
109
|
+
type: ViewChild,
|
|
110
|
+
args: ['editIcon', { static: true }]
|
|
111
|
+
}], deleteIconTpl: [{
|
|
112
|
+
type: ViewChild,
|
|
113
|
+
args: ['deleteIcon', { static: true }]
|
|
114
|
+
}], addIconTpl: [{
|
|
115
|
+
type: ViewChild,
|
|
116
|
+
args: ['addIcon', { static: true }]
|
|
117
|
+
}], defaultIconTpl: [{
|
|
118
|
+
type: ViewChild,
|
|
119
|
+
args: ['defaultIcon', { static: true }]
|
|
120
|
+
}] } });
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaWNvbi5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9saWJzL3VpL3NyYy9saWIvaWNvbi9pY29uLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL2xpYnMvdWkvc3JjL2xpYi9pY29uL2ljb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQWUsTUFBTSxlQUFlLENBQUM7QUFDL0YsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDOzs7QUFZL0MsTUFBTSxPQUFPLGdCQUFnQjtJQUMzQixvQ0FBb0M7SUFDcEMsSUFBSSxRQUFRO1FBQ1YsT0FBTyxFQUFFLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztJQUN4QixDQUFDO0lBQ1EsSUFBSSxHQUFTLE9BQU8sQ0FBQztJQUNyQixLQUFLLEdBQVUsU0FBUyxDQUFDO0lBQ3pCLFFBQVEsR0FBYSxLQUFLLENBQUM7SUFDM0IsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNsQiw4RUFBOEU7SUFDdEUsT0FBTyxHQUFHLEtBQUssQ0FBQztJQUN4QixJQUNJLE1BQU0sQ0FBQyxHQUF3QztRQUNqRCx5RkFBeUY7UUFDekYsSUFBSSxDQUFDLE9BQU8sR0FBRyxHQUFHLEtBQUssSUFBSSxJQUFJLEdBQUcsS0FBSyxTQUFTLElBQUksR0FBRyxLQUFLLEtBQUssSUFBSSxHQUFHLEtBQUssT0FBTyxDQUFDO0lBQ3ZGLENBQUM7SUFDRCxJQUFJLE1BQU07UUFDUixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUNELGlEQUFpRDtJQUN4QyxJQUFJLEdBQWtDLFFBQVEsQ0FBQztJQUN4RCw4Q0FBOEM7SUFDcEMsU0FBUyxHQUFHLElBQUksWUFBWSxFQUFTLENBQUM7SUFFTixZQUFZLENBQXdCO0lBQ25DLGFB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QVM7dUJBQUMsU0FBUyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFDTSxjQUFjO3NCQUF6RCxTQUFTO3VCQUFDLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPdXRwdXQsIEV2ZW50RW1pdHRlciwgVmlld0NoaWxkLCBUZW1wbGF0ZVJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5cclxuZXhwb3J0IHR5cGUgSWNvbiA9ICdjaGVjaycgfCAnY2FuY2VsJyB8ICdlZGl0JyB8ICdkZWxldGUnIHwgJ2FkZCc7XHJcbmV4cG9ydCB0eXBlIENvbG9yID0gJ3ByaW1hcnknIHwgJ3NlY29uZGFyeScgfCAnd2Fybic7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2M4MC1pY29uJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9pY29uLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9pY29uLmNvbXBvbmVudC5zY3NzJ11cclxufSlcclxuZXhwb3J0IGNsYXNzIEM4MEljb25Db21wb25lbnQge1xyXG4gIC8qKiBUYW1hw7FvIGJhc2UgZGVsIGljb25vIChlbiBweCkgKi9cclxuICBnZXQgaWNvblNpemUoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiAyNCAqIHRoaXMuc2l6ZTtcclxuICB9XHJcbiAgQElucHV0KCkgaWNvbjogSWNvbiA9ICdjaGVjayc7XHJcbiAgQElucHV0KCkgY29sb3I6IENvbG9yID0gJ3ByaW1hcnknO1xyXG4gIEBJbnB1dCgpIGRpc2FibGVkPzogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIHNpemUgPSAxO1xyXG4gIC8qKiBTaSBlcyB0cnVlLCByZW5kZXJpemEgY29tbyA8YnV0dG9uPiBuYXRpdm8sIHNpIGVzIGZhbHNlIHNvbG8gY29tbyBpY29ubyAqL1xyXG4gIHByaXZhdGUgX2J1dHRvbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpXHJcbiAgc2V0IGJ1dHRvbih2YWw6IGJvb2xlYW4gfCBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkKSB7XHJcbiAgICAvLyBQZXJtaXRlIHVzYXIgJ2J1dHRvbicgYSBzZWNhcywgY3VhbHF1aWVyIHZhbG9yIHF1ZSBubyBzZWEgbnVsbC91bmRlZmluZWQvZmFsc2UgZXMgdHJ1ZVxyXG4gICAgdGhpcy5fYnV0dG9uID0gdmFsICE9PSBudWxsICYmIHZhbCAhPT0gdW5kZWZpbmVkICYmIHZhbCAhPT0gZmFsc2UgJiYgdmFsICE9PSAnZmFsc2UnO1xyXG4gIH1cclxuICBnZXQgYnV0dG9uKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2J1dHRvbjtcclxuICB9XHJcbiAgLyoqIFRpcG8gZGUgYm90w7NuIG5hdGl2byAoc29sbyBzaSBidXR0b249dHJ1ZSkgKi9cclxuICBASW5wdXQoKSB0eXBlOiAnYnV0dG9uJyB8ICdzdWJtaXQnIHwgJ3Jlc2V0JyA9ICdidXR0b24nO1xyXG4gIC8qKiBPdXRwdXQgcGFyYSBjbGljayAoc29sbyBzaSBidXR0b249dHJ1ZSkgKi9cclxuICBAT3V0cHV0KCkgaWNvbkNsaWNrID0gbmV3IEV2ZW50RW1pdHRlcjxFdmVudD4oKTtcclxuXHJcbiAgQFZpZXdDaGlsZCgnY2hlY2tJY29uJywgeyBzdGF0aWM6IHRydWUgfSkgY2hlY2tJY29uVHBsITogVGVtcGxhdGVSZWY8dW5rbm93bj47XHJcbiAgQFZpZXdDaGlsZCgnY2FuY2VsSWNvbicsIHsgc3RhdGljOiB0cnVlIH0pIGNhbmNlbEljb25UcGwhOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcclxuICBAVmlld0NoaWxkKCdlZGl0SWNvbicsIHsgc3RhdGljOiB0cnVlIH0pIGVkaXRJY29uVHBsITogVGVtcGxhdGVSZWY8dW5rbm93bj47XHJcbiAgQFZpZXdDaGlsZCgnZGVsZXRlSWNvbicsIHsgc3RhdGljOiB0cnVlIH0pIGRlbGV0ZUljb25UcGwhOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcclxuICBAVmlld0NoaWxkKCdhZGRJY29uJywgeyBzdGF0aWM6IHRydWUgfSkgYWRkSWNvblRwbCE6IFRlbXBsYXRlUmVmPHVua25vd24+O1xyXG4gIEBWaWV3Q2hpbGQoJ2RlZmF1bHRJY29uJywgeyBzdGF0aWM6IHRydWUgfSkgZGVmYXVsdEljb25UcGwhOiBUZW1wbGF0ZVJlZjx1bmtub3duPjtcclxuXHJcbiAgZ2V0SWNvblRlbXBsYXRlKCk6IFRlbXBsYXRlUmVmPHVua25vd24+IHtcclxuICAgIHN3aXRjaCAodGhpcy5pY29uKSB7XHJcbiAgICAgIGNhc2UgJ2NoZWNrJzogcmV0dXJuIHRoaXMuY2hlY2tJY29uVHBsO1xyXG4gICAgICBjYXNlICdjYW5jZWwnOiByZXR1cm4gdGhpcy5jYW5jZWxJY29uVHBsO1xyXG4gICAgICBjYXNlICdlZGl0JzogcmV0dXJuIHRoaXMuZWRpdEljb25UcGw7XHJcbiAgICAgIGNhc2UgJ2RlbGV0ZSc6IHJldHVybiB0aGlzLmRlbGV0ZUljb25UcGw7XHJcbiAgICAgIGNhc2UgJ2FkZCc6IHJldHVybiB0aGlzLmFkZEljb25UcGw7XHJcbiAgICAgIGRlZmF1bHQ6IHJldHVybiB0aGlzLmRlZmF1bHRJY29uVHBsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZ2V0IGljb25Db2xvcigpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMuZGlzYWJsZWQpIHtcclxuICAgICAgcmV0dXJuICcjYmRiZGJkJzsgLy8gZ3JpcyBkZXNoYWJpbGl0YWRvXHJcbiAgICB9XHJcbiAgICBjb25zdCBwYWxldHRlczogUmVjb3JkPEljb24sIFJlY29yZDxDb2xvciwgc3RyaW5nPj4gPSB7XHJcbiAgICAgIGNoZWNrOiB7XHJcbiAgICAgICAgcHJpbWFyeTogJyMwMDIzNGJhZCcsXHJcbiAgICAgICAgc2Vjb25kYXJ5OiAnIzZjNzU3ZCcsXHJcbiAgICAgICAgd2FybjogJyNlNTM5MzUnLFxyXG4gICAgICB9LFxyXG4gICAgICBjYW5jZWw6IHtcclxuICAgICAgICBwcmltYXJ5OiAnIzAwMjM0YmFkJyxcclxuICAgICAgICBzZWNvbmRhcnk6ICcjNmM3NTdkJyxcclxuICAgICAgICB3YXJuOiAnI2U1MzkzNScsXHJcbiAgICAgIH0sXHJcbiAgICAgIGVkaXQ6IHtcclxuICAgICAgICBwcmltYXJ5OiAnIzAwMjM0YmFkJyxcclxuICAgICAgICBzZWNvbmRhcnk6ICcjNmM3NTdkJyxcclxuICAgICAgICB3YXJuOiAnI2U1MzkzNScsXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGV0ZToge1xyXG4gICAgICAgIHByaW1hcnk6ICcjMDAyMzRiYWQnLFxyXG4gICAgICAgIHNlY29uZGFyeTogJyM2Yzc1N2QnLFxyXG4gICAgICAgIHdhcm46ICcjZTUzOTM1JyxcclxuICAgICAgfSxcclxuICAgICAgYWRkOiB7XHJcbiAgICAgICAgcHJpbWFyeTogJyMwMDIzNGJhZCcsXHJcbiAgICAgICAgc2Vjb25kYXJ5OiAnIzZjNzU3ZCcsXHJcbiAgICAgICAgd2FybjogJyNlNTM5MzUnLFxyXG4gICAgICB9XHJcbiAgICB9O1xyXG4gICAgcmV0dXJuIHBhbGV0dGVzW3RoaXMuaWNvbl0/Llt0aGlzLmNvbG9yXSA/PyAnIzIyMic7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGVyIHBhcmEgY2xpY2sgZW4gbW9kbyBidXR0b25cclxuICBvbkJ1dHRvbkNsaWNrKGV2ZW50OiBFdmVudCkge1xyXG4gICAgaWYgKCF0aGlzLmRpc2FibGVkKSB7XHJcbiAgICAgIHRoaXMuaWNvbkNsaWNrLmVtaXQoZXZlbnQpO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG4iLCJAaWYgKGJ1dHRvbikge1xyXG48YnV0dG9uIHR5cGU9XCJ7e3R5cGV9fVwiIFtkaXNhYmxlZF09XCJkaXNhYmxlZFwiIGNsYXNzPVwiaWNvbi1idXR0b25cIiBbc3R5bGUud2lkdGgucHhdPVwiaWNvblNpemUgKyA4XCJcclxuICBbc3R5bGUuaGVpZ2h0LnB4XT1cImljb25TaXplICsgOFwiIChjbGljayk9XCJvbkJ1dHRvbkNsaWNrKCRldmVudClcIj5cclxuICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiZ2V0SWNvblRlbXBsYXRlKClcIj48L25nLWNvbnRhaW5lcj5cclxuPC9idXR0b24+XHJcbn0gQGVsc2Uge1xyXG48c3BhbiBjbGFzcz1cImljb24tc3BhblwiIFtzdHlsZS53aWR0aC5weF09XCJpY29uU2l6ZVwiIFtzdHlsZS5oZWlnaHQucHhdPVwiaWNvblNpemVcIj5cclxuICA8bmctY29udGFpbmVyICpuZ1RlbXBsYXRlT3V0bGV0PVwiZ2V0SWNvblRlbXBsYXRlKClcIj48L25nLWNvbnRhaW5lcj5cclxuPC9zcGFuPlxyXG59XHJcblxyXG48bmctdGVtcGxhdGUgI2NoZWNrSWNvbj5cclxuICA8c3ZnIFthdHRyLndpZHRoXT1cImljb25TaXplXCIgW2F0dHIuaGVpZ2h0XT1cImljb25TaXplXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICA8cGF0aCBkPVwiTTUgMTNsNCA0TDE5IDdcIiBbYXR0ci5zdHJva2VdPVwiaWNvbkNvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIlxyXG4gICAgICBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIC8+XHJcbiAgPC9zdmc+XHJcbjwvbmctdGVtcGxhdGU+XHJcbjxuZy10ZW1wbGF0ZSAjY2FuY2VsSWNvbj5cclxuICA8c3ZnIFthdHRyLndpZHRoXT1cImljb25TaXplXCIgW2F0dHIuaGVpZ2h0XT1cImljb25TaXplXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICA8cGF0aCBkPVwiTTYgNmwxMiAxMk02IDE4TDE4IDZcIiBbYXR0ci5zdHJva2VdPVwiaWNvbkNvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiAvPlxyXG4gIDwvc3ZnPlxyXG48L25nLXRlbXBsYXRlPlxyXG48bmctdGVtcGxhdGUgI2VkaXRJY29uPlxyXG4gIDxzdmcgW2F0dHIud2lkdGhdPVwiaWNvblNpemVcIiBbYXR0ci5oZWlnaHRdPVwiaWNvblNpemVcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIj5cclxuICAgIDxyZWN0IHg9XCI1XCIgeT1cIjE5XCIgd2lkdGg9XCIxNFwiIGhlaWdodD1cIjJcIiByeD1cIjFcIiBbYXR0ci5maWxsXT1cImljb25Db2xvclwiIC8+XHJcbiAgICA8cGF0aCBkPVwiTTE2LjUgMy41YTIuMTIxIDIuMTIxIDAgMCAxIDMgM0w3IDE5bC00IDEgMS00IDEyLjUtMTIuNXpcIiBbYXR0ci5zdHJva2VdPVwiaWNvbkNvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIC8+XHJcbiAgPC9zdmc+XHJcbjwvbmctdGVtcGxhdGU+XHJcbjxuZy10ZW1wbGF0ZSAjZGVsZXRlSWNvbj5cclxuICA8c3ZnIFthdHRyLndpZHRoXT1cImljb25TaXplXCIgW2F0dHIuaGVpZ2h0XT1cImljb25TaXplXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICA8cGF0aCBkPVwiTTYgMTlhMiAyIDAgMCAwIDIgMmg4YTIgMiAwIDAgMCAyLTJWN0g2djEyek0xOSA0aC0zLjVsLTEtMWgtNWwtMSAxSDV2MmgxNFY0elwiIFthdHRyLmZpbGxdPVwiaWNvbkNvbG9yXCIgLz5cclxuICA8L3N2Zz5cclxuPC9uZy10ZW1wbGF0ZT5cclxuPG5nLXRlbXBsYXRlICNhZGRJY29uPlxyXG4gIDxzdmcgW2F0dHIud2lkdGhdPVwiaWNvblNpemVcIiBbYXR0ci5oZWlnaHRdPVwiaWNvblNpemVcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCIgZmlsbD1cIm5vbmVcIj5cclxuICAgIDxwYXRoIGQ9XCJNMTIgNXYxNE01IDEyaDE0XCIgW2F0dHIuc3Ryb2tlXT1cImljb25Db2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgLz5cclxuICA8L3N2Zz5cclxuPC9uZy10ZW1wbGF0ZT5cclxuPG5nLXRlbXBsYXRlICNkZWZhdWx0SWNvbj5cclxuICA8c3ZnIFthdHRyLndpZHRoXT1cImljb25TaXplXCIgW2F0dHIuaGVpZ2h0XT1cImljb25TaXplXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICA8Y2lyY2xlIGN4PVwiMTJcIiBjeT1cIjEyXCIgcj1cIjEwXCIgW2F0dHIuc3Ryb2tlXT1cImljb25Db2xvclwiIHN0cm9rZS13aWR0aD1cIjJcIiAvPlxyXG4gIDwvc3ZnPlxyXG48L25nLXRlbXBsYXRlPiJdfQ==
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { Component, Input, Output, signal, EventEmitter } from '@angular/core';
|
|
2
|
+
import { take } from 'rxjs';
|
|
3
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
4
|
+
import { C80IconComponent } from '../icon/icon.component';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/material/checkbox";
|
|
7
|
+
export class C80TableComponent {
|
|
8
|
+
service;
|
|
9
|
+
columns = [];
|
|
10
|
+
errorEvent = new EventEmitter();
|
|
11
|
+
data = signal([]);
|
|
12
|
+
keys = signal([]);
|
|
13
|
+
creating = signal(false);
|
|
14
|
+
newRow = signal(null);
|
|
15
|
+
editing = signal(null); // id of row being edited
|
|
16
|
+
editRow = signal(null);
|
|
17
|
+
ngOnInit() {
|
|
18
|
+
if (!this.service)
|
|
19
|
+
return;
|
|
20
|
+
this.refresh();
|
|
21
|
+
}
|
|
22
|
+
onInput(event, key, col) {
|
|
23
|
+
if (col?.type === 'boolean') {
|
|
24
|
+
// MatCheckboxChange
|
|
25
|
+
const checked = event.checked;
|
|
26
|
+
this.updateNewRow(key, checked);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const target = event.target;
|
|
30
|
+
if (target && typeof target.value === 'string') {
|
|
31
|
+
this.updateNewRow(key, target.value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
onDelete(row) {
|
|
36
|
+
if (!this.service.delete)
|
|
37
|
+
return;
|
|
38
|
+
const id = row['id'];
|
|
39
|
+
if (typeof id !== 'number') {
|
|
40
|
+
this.errorEvent.emit('No se puede borrar: id inválido');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (confirm('¿Está seguro de que desea borrar este elemento?')) {
|
|
44
|
+
this.service.delete(id).pipe(take(1)).subscribe({
|
|
45
|
+
next: () => this.refresh(),
|
|
46
|
+
error: (err) => this.errorEvent.emit(err?.message || 'Error al borrar')
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
refresh() {
|
|
51
|
+
this.service.get().pipe(take(1)).subscribe((items) => {
|
|
52
|
+
this.data.update(() => items);
|
|
53
|
+
// Solo mostrar las columnas visibles
|
|
54
|
+
const visibleColumns = this.columns.filter(col => col?.visible !== false);
|
|
55
|
+
this.keys.update(() => visibleColumns.map(col => col.accessor));
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
startCreate() {
|
|
59
|
+
this.creating.set(true);
|
|
60
|
+
// Inicializa newRow solo con los accessors de columnas visibles
|
|
61
|
+
const row = {};
|
|
62
|
+
this.columns.filter(col => col.visible !== false).forEach(col => {
|
|
63
|
+
row[col.accessor] = '';
|
|
64
|
+
});
|
|
65
|
+
this.newRow.set(row);
|
|
66
|
+
}
|
|
67
|
+
cancelCreate() {
|
|
68
|
+
this.creating.set(false);
|
|
69
|
+
this.newRow.set(null);
|
|
70
|
+
}
|
|
71
|
+
updateNewRow(key, value) {
|
|
72
|
+
const current = this.newRow();
|
|
73
|
+
if (!current)
|
|
74
|
+
return;
|
|
75
|
+
this.newRow.set({ ...current, [key]: value });
|
|
76
|
+
}
|
|
77
|
+
saveCreate() {
|
|
78
|
+
const row = this.newRow();
|
|
79
|
+
if (!row)
|
|
80
|
+
return;
|
|
81
|
+
const visibleColumns = this.columns.filter(col => col.visible !== false);
|
|
82
|
+
const converted = visibleColumns.reduce((acc, col) => {
|
|
83
|
+
acc[col.accessor] = this.convertCellValue(row[col.accessor], col);
|
|
84
|
+
return acc;
|
|
85
|
+
}, {});
|
|
86
|
+
if (this.service.create) {
|
|
87
|
+
this.service.create(converted).pipe(take(1)).subscribe({
|
|
88
|
+
next: () => {
|
|
89
|
+
this.cancelCreate();
|
|
90
|
+
this.refresh();
|
|
91
|
+
},
|
|
92
|
+
error: (err) => {
|
|
93
|
+
this.errorEvent.emit(err?.message || 'Error al crear');
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Converts a cell value based on column type or sample data.
|
|
100
|
+
* Handles stringification of objects for string columns.
|
|
101
|
+
*/
|
|
102
|
+
/**
|
|
103
|
+
* Converts a cell value based on column type or sample data.
|
|
104
|
+
* Delegates to type-specific helpers for clarity and maintainability.
|
|
105
|
+
*/
|
|
106
|
+
convertCellValue(value, col) {
|
|
107
|
+
if (col.type === 'boolean')
|
|
108
|
+
return this.toBoolean(value);
|
|
109
|
+
if (col.type === 'number')
|
|
110
|
+
return this.toNumber(value);
|
|
111
|
+
if (col.type === 'string')
|
|
112
|
+
return this.toStringValue(value);
|
|
113
|
+
// Fallback: use sample data if available
|
|
114
|
+
const sample = this.data()[0];
|
|
115
|
+
if (sample && col.accessor in sample) {
|
|
116
|
+
const sampleValue = sample[col.accessor];
|
|
117
|
+
if (typeof sampleValue === 'boolean')
|
|
118
|
+
return this.toBoolean(value);
|
|
119
|
+
if (typeof sampleValue === 'number')
|
|
120
|
+
return this.toNumber(value);
|
|
121
|
+
if (typeof sampleValue === 'string')
|
|
122
|
+
return this.toStringValue(value);
|
|
123
|
+
}
|
|
124
|
+
return value;
|
|
125
|
+
}
|
|
126
|
+
/** Converts value to boolean using best practices. */
|
|
127
|
+
toBoolean(value) {
|
|
128
|
+
if (typeof value === 'boolean')
|
|
129
|
+
return value;
|
|
130
|
+
if (typeof value === 'string')
|
|
131
|
+
return value.trim().toLowerCase() === 'true' || value.trim() === '1';
|
|
132
|
+
if (typeof value === 'number')
|
|
133
|
+
return value === 1;
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
/** Converts value to number using best practices. */
|
|
137
|
+
toNumber(value) {
|
|
138
|
+
if (typeof value === 'number')
|
|
139
|
+
return value;
|
|
140
|
+
if (typeof value === 'string')
|
|
141
|
+
return value.trim() === '' ? undefined : Number(value);
|
|
142
|
+
if (typeof value === 'boolean')
|
|
143
|
+
return value ? 1 : 0;
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
/** Converts value to string using best practices, always stringifies objects. */
|
|
147
|
+
toStringValue(value) {
|
|
148
|
+
if (value == null)
|
|
149
|
+
return '';
|
|
150
|
+
if (typeof value === 'string')
|
|
151
|
+
return value;
|
|
152
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
153
|
+
return String(value);
|
|
154
|
+
if (typeof value === 'object') {
|
|
155
|
+
try {
|
|
156
|
+
return JSON.stringify(value);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return '[object Object]';
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// For functions, symbols, undefined, etc., return empty string
|
|
163
|
+
return '';
|
|
164
|
+
}
|
|
165
|
+
onEdit(row) {
|
|
166
|
+
this.editing.set(row['id']);
|
|
167
|
+
const edit = {};
|
|
168
|
+
this.columns.filter(col => col.visible !== false).forEach(col => {
|
|
169
|
+
edit[col.accessor] = row[col.accessor];
|
|
170
|
+
});
|
|
171
|
+
this.editRow.set(edit);
|
|
172
|
+
}
|
|
173
|
+
cancelEdit() {
|
|
174
|
+
this.editing.set(null);
|
|
175
|
+
this.editRow.set(null);
|
|
176
|
+
}
|
|
177
|
+
onEditInput(event, key, col) {
|
|
178
|
+
const current = this.editRow();
|
|
179
|
+
if (!current)
|
|
180
|
+
return;
|
|
181
|
+
if (col?.type === 'boolean') {
|
|
182
|
+
// MatCheckboxChange
|
|
183
|
+
const checked = event.checked;
|
|
184
|
+
this.editRow.set({ ...current, [key]: checked });
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const target = event.target;
|
|
188
|
+
if (target && typeof target.value === 'string') {
|
|
189
|
+
this.editRow.set({ ...current, [key]: target.value });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
saveEdit(row) {
|
|
194
|
+
const id = row['id'];
|
|
195
|
+
if (typeof id !== 'number' || !this.editRow())
|
|
196
|
+
return;
|
|
197
|
+
const visibleColumns = this.columns.filter(col => col.visible !== false);
|
|
198
|
+
const converted = visibleColumns.reduce((acc, col) => {
|
|
199
|
+
acc[col.accessor] = this.convertCellValue(this.editRow()[col.accessor], col);
|
|
200
|
+
return acc;
|
|
201
|
+
}, {});
|
|
202
|
+
// Type-safe update method detection
|
|
203
|
+
const updateFn = this.service.update;
|
|
204
|
+
if (updateFn) {
|
|
205
|
+
updateFn(id, converted).pipe(take(1)).subscribe({
|
|
206
|
+
next: () => {
|
|
207
|
+
this.cancelEdit();
|
|
208
|
+
this.refresh();
|
|
209
|
+
},
|
|
210
|
+
error: (err) => {
|
|
211
|
+
const message = (typeof err === 'object' && err && 'message' in err) ? err.message : undefined;
|
|
212
|
+
this.errorEvent.emit(message || 'Error al editar');
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).
|
|
219
|
+
*/
|
|
220
|
+
trackById(index, row) {
|
|
221
|
+
const id = row && typeof row === 'object' && 'id' in row ? row['id'] : undefined;
|
|
222
|
+
return (typeof id === 'string' || typeof id === 'number') ? id : index;
|
|
223
|
+
}
|
|
224
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C80TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
225
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: C80TableComponent, isStandalone: true, selector: "c80-table", inputs: { service: "service", columns: "columns" }, outputs: { errorEvent: "errorEvent" }, ngImport: i0, template: "<div class=\"table-responsive\">\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light\">\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <th class=\"text-center\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n <th class=\"table-actions-header\">\n <span>Actions</span>\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" class=\"add-action-btn\"\n (iconClick)=\"startCreate()\"></c80-icon>\n </th>\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (editing() === row['id']) {\n <mat-checkbox [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\"\n [aria-label]=\"col.label\"></mat-checkbox>\n }\n @else {\n @if (row[col.accessor] === true) {\n <c80-icon icon=\"check\" [size]=\"1\"></c80-icon>\n <br />\n }\n @else if (row[col.accessor] === false) {\n <c80-icon icon=\"cancel\"></c80-icon>\n <br />\n }\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id']) {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'number' ? 'number' : 'text'\"\n [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n {{ row[col.accessor] }}\n }\n </td>\n }\n }\n }\n <td class=\"text-center\">\n @if (editing() === row['id']) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\"></c80-icon>\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\"></c80-icon>\n }\n @else {\n <c80-icon button icon=\"edit\" title=\"Editar\" (iconClick)=\"onEdit(row)\"></c80-icon>\n <c80-icon button icon=\"delete\" color=\"warn\" title=\"Borrar\" (iconClick)=\"onDelete(row)\"></c80-icon>\n }\n </td>\n </tr>\n }\n @if (creating()) {\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n <mat-checkbox [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\"\n [aria-label]=\"col.label\"></mat-checkbox>\n </td>\n } @else {\n <td>\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'number' ? 'number' : 'text'\"\n [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\"\n (input)=\"onInput($event, col.accessor, col)\" />\n </td>\n }\n }\n }\n <td class=\"text-center\">\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\"></c80-icon>\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\"></c80-icon>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0) {\n <div class=\"text-center text-muted py-3\">\n No hay datos para mostrar.\n </div>\n }\n</div>", styles: ["@charset \"UTF-8\";.table-responsive{width:100%;overflow-x:auto}.table-responsive .table{min-width:0px}.table-responsive .table .thead .table-actions-header{text-align:center;vertical-align:middle;display:flex;justify-content:center;align-items:center;gap:.5rem}.table-responsive .table .thead .table-actions-header .add-action-btn{margin-bottom:2px}.table-responsive .table .thead th{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .6rem!important}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:35px!important}\n"], dependencies: [{ kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: C80IconComponent, selector: "c80-icon", inputs: ["icon", "color", "disabled", "size", "button", "type"], outputs: ["iconClick"] }] });
|
|
226
|
+
}
|
|
227
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: C80TableComponent, decorators: [{
|
|
228
|
+
type: Component,
|
|
229
|
+
args: [{ selector: 'c80-table', standalone: true, imports: [MatCheckboxModule, C80IconComponent], template: "<div class=\"table-responsive\">\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light\">\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <th class=\"text-center\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n <th class=\"table-actions-header\">\n <span>Actions</span>\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" class=\"add-action-btn\"\n (iconClick)=\"startCreate()\"></c80-icon>\n </th>\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (editing() === row['id']) {\n <mat-checkbox [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\"\n [aria-label]=\"col.label\"></mat-checkbox>\n }\n @else {\n @if (row[col.accessor] === true) {\n <c80-icon icon=\"check\" [size]=\"1\"></c80-icon>\n <br />\n }\n @else if (row[col.accessor] === false) {\n <c80-icon icon=\"cancel\"></c80-icon>\n <br />\n }\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id']) {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'number' ? 'number' : 'text'\"\n [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n {{ row[col.accessor] }}\n }\n </td>\n }\n }\n }\n <td class=\"text-center\">\n @if (editing() === row['id']) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\"></c80-icon>\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\"></c80-icon>\n }\n @else {\n <c80-icon button icon=\"edit\" title=\"Editar\" (iconClick)=\"onEdit(row)\"></c80-icon>\n <c80-icon button icon=\"delete\" color=\"warn\" title=\"Borrar\" (iconClick)=\"onDelete(row)\"></c80-icon>\n }\n </td>\n </tr>\n }\n @if (creating()) {\n <tr>\n @for (col of columns; track col) {\n @if (col.visible !== false) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n <mat-checkbox [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\"\n [aria-label]=\"col.label\"></mat-checkbox>\n </td>\n } @else {\n <td>\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'number' ? 'number' : 'text'\"\n [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\"\n (input)=\"onInput($event, col.accessor, col)\" />\n </td>\n }\n }\n }\n <td class=\"text-center\">\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\"></c80-icon>\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\"></c80-icon>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0) {\n <div class=\"text-center text-muted py-3\">\n No hay datos para mostrar.\n </div>\n }\n</div>", styles: ["@charset \"UTF-8\";.table-responsive{width:100%;overflow-x:auto}.table-responsive .table{min-width:0px}.table-responsive .table .thead .table-actions-header{text-align:center;vertical-align:middle;display:flex;justify-content:center;align-items:center;gap:.5rem}.table-responsive .table .thead .table-actions-header .add-action-btn{margin-bottom:2px}.table-responsive .table .thead th{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .6rem!important}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer}.table-responsive .table tbody tr:hover{background-color:#f5f5f5}.table-responsive .table tbody input{border:1px solid rgba(34,0,255,.37);height:35px!important}\n"] }]
|
|
230
|
+
}], propDecorators: { service: [{
|
|
231
|
+
type: Input
|
|
232
|
+
}], columns: [{
|
|
233
|
+
type: Input
|
|
234
|
+
}], errorEvent: [{
|
|
235
|
+
type: Output
|
|
236
|
+
}] } });
|
|
237
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy91aS9zcmMvbGliL3RhYmxlL3RhYmxlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL2xpYnMvdWkvc3JjL2xpYi90YWJsZS90YWJsZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN2RixPQUFPLEVBQWMsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRS9ELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDOzs7QUF3QjFELE1BQU0sT0FBTyxpQkFBaUI7SUFDbkIsT0FBTyxDQUFzQjtJQUM3QixPQUFPLEdBQXFCLEVBQUUsQ0FBQztJQUM5QixVQUFVLEdBQUcsSUFBSSxZQUFZLEVBQVUsQ0FBQztJQUV6QyxJQUFJLEdBQUcsTUFBTSxDQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZCLElBQUksR0FBRyxNQUFNLENBQVcsRUFBRSxDQUFDLENBQUM7SUFDckMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN6QixNQUFNLEdBQUcsTUFBTSxDQUFvQixJQUFJLENBQUMsQ0FBQztJQUNoQyxPQUFPLEdBQUcsTUFBTSxDQUFnQixJQUFJLENBQUMsQ0FBQyxDQUFDLHlCQUF5QjtJQUNoRSxPQUFPLEdBQUcsTUFBTSxDQUFvQixJQUFJLENBQUMsQ0FBQztJQUVuRCxRQUFRO1FBQ04sSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTztRQUMxQixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDakIsQ0FBQztJQUVELE9BQU8sQ0FBQyxLQUFn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S0FBSyxDQUFDO0lBQ3pFLENBQUM7d0dBck5VLGlCQUFpQjs0RkFBakIsaUJBQWlCLGdLQzVCOUIscXJIQXFHTSx5Z0NEN0VNLGlCQUFpQixxWUFBRSxnQkFBZ0I7OzRGQUlsQyxpQkFBaUI7a0JBUDdCLFNBQVM7K0JBQ0UsV0FBVyxjQUNULElBQUksV0FDUCxDQUFDLGlCQUFpQixFQUFFLGdCQUFnQixDQUFDOzhCQUtyQyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNJLFVBQVU7c0JBQW5CLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPbkluaXQsIE91dHB1dCwgc2lnbmFsLCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgdGFrZSB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBNYXRDaGVja2JveE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcclxuaW1wb3J0IHR5cGUgeyBNYXRDaGVja2JveENoYW5nZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NoZWNrYm94JztcclxuaW1wb3J0IHsgQzgwSWNvbkNvbXBvbmVudCB9IGZyb20gJy4uL2ljb24vaWNvbi5jb21wb25lbnQnO1xyXG5cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQzgwVGFibGVTZXJ2aWNlPFQ+IHtcclxuICBnZXQ6ICgpID0+IE9ic2VydmFibGU8VFtdPjtcclxuICBjcmVhdGU6IChyb3c6IFQpID0+IE9ic2VydmFibGU8VD47XHJcbiAgZGVsZXRlOiAoaWQ6IG51bWJlcikgPT4gT2JzZXJ2YWJsZTx2b2lkPjtcclxuICB1cGRhdGU6IChpZDogbnVtYmVyLCByb3c6IFQpID0+IE9ic2VydmFibGU8VD47XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQzgwVGFibGVDb2xEZWYge1xyXG4gIGFjY2Vzc29yOiBzdHJpbmc7XHJcbiAgbGFiZWw6IHN0cmluZztcclxuICB2aXNpYmxlPzogYm9vbGVhbjsgLy8gU2kgbm8gc2UgZXNwZWNpZmljYSwgc2UgYXN1bWUgdHJ1ZVxyXG4gIHR5cGU/OiAnc3RyaW5nJyB8ICdudW1iZXInIHwgJ2Jvb2xlYW4nOyAvLyBUaXBvIGRlIGRhdG8gcGFyYSBsYSBjb2x1bW5hXHJcbn1cclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnYzgwLXRhYmxlJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtNYXRDaGVja2JveE1vZHVsZSwgQzgwSWNvbkNvbXBvbmVudF0sXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3RhYmxlLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybDogJy4vdGFibGUuY29tcG9uZW50LnNjc3MnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQzgwVGFibGVDb21wb25lbnQ8VCBleHRlbmRzIFJlY29yZDxzdHJpbmcsIHVua25vd24+PiBpbXBsZW1lbnRzIE9uSW5pdCB7XHJcbiAgQElucHV0KCkgc2VydmljZSE6IEM4MFRhYmxlU2VydmljZTxUPjtcclxuICBASW5wdXQoKSBjb2x1bW5zOiBDODBUYWJsZUNvbERlZltdID0gW107XHJcbiAgQE91dHB1dCgpIGVycm9yRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyPHN0cmluZz4oKTtcclxuXHJcbiAgcmVhZG9ubHkgZGF0YSA9IHNpZ25hbDxUW10+KFtdKTtcclxuICByZWFkb25seSBrZXlzID0gc2lnbmFsPHN0cmluZ1tdPihbXSk7XHJcbiAgY3JlYXRpbmcgPSBzaWduYWwoZmFsc2UpO1xyXG4gIG5ld1JvdyA9IHNpZ25hbDxQYXJ0aWFsPFQ+IHwgbnVsbD4obnVsbCk7XHJcbiAgcmVhZG9ubHkgZWRpdGluZyA9IHNpZ25hbDxudW1iZXIgfCBudWxsPihudWxsKTsgLy8gaWQgb2Ygcm93IGJlaW5nIGVkaXRlZFxyXG4gIHJlYWRvbmx5IGVkaXRSb3cgPSBzaWduYWw8UGFydGlhbDxUPiB8IG51bGw+KG51bGwpO1xyXG5cclxuICBuZ09uSW5pdCgpIHtcclxuICAgIGlmICghdGhpcy5zZXJ2aWNlKSByZXR1cm47XHJcbiAgICB0aGlzLnJlZnJlc2goKTtcclxuICB9XHJcblxyXG4gIG9uSW5wdXQoZXZlbnQ6IEV2ZW50IHwgTWF0Q2hlY2tib3hDaGFuZ2UsIGtleTogc3RyaW5nLCBjb2w/OiBDODBUYWJsZUNvbERlZikge1xyXG4gICAgaWYgKGNvbD8udHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgIC8vIE1hdENoZWNrYm94Q2hhbmdlXHJcbiAgICAgIGNvbnN0IGNoZWNrZWQgPSAoZXZlbnQgYXMgTWF0Q2hlY2tib3hDaGFuZ2UpLmNoZWNrZWQ7XHJcbiAgICAgIHRoaXMudXBkYXRlTmV3Um93KGtleSwgY2hlY2tlZCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjb25zdCB0YXJnZXQgPSAoZXZlbnQgYXMgRXZlbnQpLnRhcmdldDtcclxuICAgICAgaWYgKHRhcmdldCAmJiB0eXBlb2YgKHRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS52YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgICB0aGlzLnVwZGF0ZU5ld1JvdyhrZXksICh0YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBvbkRlbGV0ZShyb3c6IFQpIHtcclxuICAgIGlmICghdGhpcy5zZXJ2aWNlLmRlbGV0ZSkgcmV0dXJuO1xyXG4gICAgY29uc3QgaWQgPSByb3dbJ2lkJ107XHJcbiAgICBpZiAodHlwZW9mIGlkICE9PSAnbnVtYmVyJykge1xyXG4gICAgICB0aGlzLmVycm9yRXZlbnQuZW1pdCgnTm8gc2UgcHVlZGUgYm9ycmFyOiBpZCBpbnbDoWxpZG8nKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKGNvbmZpcm0oJ8K/RXN0w6Egc2VndXJvIGRlIHF1ZSBkZXNlYSBib3JyYXIgZXN0ZSBlbGVtZW50bz8nKSkge1xyXG4gICAgICB0aGlzLnNlcnZpY2UuZGVsZXRlKGlkKS5waXBlKHRha2UoMSkpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgbmV4dDogKCkgPT4gdGhpcy5yZWZyZXNoKCksXHJcbiAgICAgICAgZXJyb3I6IChlcnIpID0+IHRoaXMuZXJyb3JFdmVudC5lbWl0KGVycj8ubWVzc2FnZSB8fCAnRXJyb3IgYWwgYm9ycmFyJylcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZWZyZXNoKCkge1xyXG4gICAgdGhpcy5zZXJ2aWNlLmdldCgpLnBpcGUodGFrZSgxKSkuc3Vic2NyaWJlKChpdGVtcykgPT4ge1xyXG4gICAgICB0aGlzLmRhdGEudXBkYXRlKCgpID0+IGl0ZW1zKTtcclxuICAgICAgLy8gU29sbyBtb3N0cmFyIGxhcyBjb2x1bW5hcyB2aXNpYmxlc1xyXG4gICAgICBjb25zdCB2aXNpYmxlQ29sdW1ucyA9IHRoaXMuY29sdW1ucy5maWx0ZXIoY29sID0+IGNvbD8udmlzaWJsZSAhPT0gZmFsc2UpO1xyXG4gICAgICB0aGlzLmtleXMudXBkYXRlKCgpID0+IHZpc2libGVDb2x1bW5zLm1hcChjb2wgPT4gY29sLmFjY2Vzc29yKSk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHN0YXJ0Q3JlYXRlKCkge1xyXG4gICAgdGhpcy5jcmVhdGluZy5zZXQodHJ1ZSk7XHJcbiAgICAvLyBJbmljaWFsaXphIG5ld1JvdyBzb2xvIGNvbiBsb3MgYWNjZXNzb3JzIGRlIGNvbHVtbmFzIHZpc2libGVzXHJcbiAgICBjb25zdCByb3c6IFBhcnRpYWw8VD4gPSB7fTtcclxuICAgIHRoaXMuY29sdW1ucy5maWx0ZXIoY29sID0+IGNvbC52aXNpYmxlICE9PSBmYWxzZSkuZm9yRWFjaChjb2wgPT4ge1xyXG4gICAgICAocm93IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVtjb2wuYWNjZXNzb3JdID0gJyc7XHJcbiAgICB9KTtcclxuICAgIHRoaXMubmV3Um93LnNldChyb3cpO1xyXG4gIH1cclxuXHJcbiAgY2FuY2VsQ3JlYXRlKCkge1xyXG4gICAgdGhpcy5jcmVhdGluZy5zZXQoZmFsc2UpO1xyXG4gICAgdGhpcy5uZXdSb3cuc2V0KG51bGwpO1xyXG4gIH1cclxuXHJcbiAgdXBkYXRlTmV3Um93KGtleTogc3RyaW5nLCB2YWx1ZTogdW5rbm93bikge1xyXG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMubmV3Um93KCk7XHJcbiAgICBpZiAoIWN1cnJlbnQpIHJldHVybjtcclxuICAgIHRoaXMubmV3Um93LnNldCh7IC4uLmN1cnJlbnQsIFtrZXldOiB2YWx1ZSB9KTtcclxuICB9XHJcblxyXG4gIHNhdmVDcmVhdGUoKSB7XHJcbiAgICBjb25zdCByb3cgPSB0aGlzLm5ld1JvdygpO1xyXG4gICAgaWYgKCFyb3cpIHJldHVybjtcclxuXHJcbiAgICBjb25zdCB2aXNpYmxlQ29sdW1ucyA9IHRoaXMuY29sdW1ucy5maWx0ZXIoY29sID0+IGNvbC52aXNpYmxlICE9PSBmYWxzZSk7XHJcbiAgICBjb25zdCBjb252ZXJ0ZWQgPSB2aXNpYmxlQ29sdW1ucy5yZWR1Y2UoKGFjYywgY29sKSA9PiB7XHJcbiAgICAgIGFjY1tjb2wuYWNjZXNzb3JdID0gdGhpcy5jb252ZXJ0Q2VsbFZhbHVlKHJvd1tjb2wuYWNjZXNzb3JdLCBjb2wpO1xyXG4gICAgICByZXR1cm4gYWNjO1xyXG4gICAgfSwge30gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pIGFzIFBhcnRpYWw8VD47XHJcblxyXG4gICAgaWYgKHRoaXMuc2VydmljZS5jcmVhdGUpIHtcclxuICAgICAgKHRoaXMuc2VydmljZS5jcmVhdGUgYXMgKHJvdzogUGFydGlhbDxUPikgPT4gT2JzZXJ2YWJsZTxUPikoY29udmVydGVkKS5waXBlKHRha2UoMSkpLnN1YnNjcmliZSh7XHJcbiAgICAgICAgbmV4dDogKCkgPT4ge1xyXG4gICAgICAgICAgdGhpcy5jYW5jZWxDcmVhdGUoKTtcclxuICAgICAgICAgIHRoaXMucmVmcmVzaCgpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXJyb3I6IChlcnIpID0+IHtcclxuICAgICAgICAgIHRoaXMuZXJyb3JFdmVudC5lbWl0KGVycj8ubWVzc2FnZSB8fCAnRXJyb3IgYWwgY3JlYXInKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQ29udmVydHMgYSBjZWxsIHZhbHVlIGJhc2VkIG9uIGNvbHVtbiB0eXBlIG9yIHNhbXBsZSBkYXRhLlxyXG4gICAqIEhhbmRsZXMgc3RyaW5naWZpY2F0aW9uIG9mIG9iamVjdHMgZm9yIHN0cmluZyBjb2x1bW5zLlxyXG4gICAqL1xyXG4gIC8qKlxyXG4gICAqIENvbnZlcnRzIGEgY2VsbCB2YWx1ZSBiYXNlZCBvbiBjb2x1bW4gdHlwZSBvciBzYW1wbGUgZGF0YS5cclxuICAgKiBEZWxlZ2F0ZXMgdG8gdHlwZS1zcGVjaWZpYyBoZWxwZXJzIGZvciBjbGFyaXR5IGFuZCBtYWludGFpbmFiaWxpdHkuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBjb252ZXJ0Q2VsbFZhbHVlKHZhbHVlOiB1bmtub3duLCBjb2w6IEM4MFRhYmxlQ29sRGVmKTogdW5rbm93biB7XHJcbiAgICBpZiAoY29sLnR5cGUgPT09ICdib29sZWFuJykgcmV0dXJuIHRoaXMudG9Cb29sZWFuKHZhbHVlKTtcclxuICAgIGlmIChjb2wudHlwZSA9PT0gJ251bWJlcicpIHJldHVybiB0aGlzLnRvTnVtYmVyKHZhbHVlKTtcclxuICAgIGlmIChjb2wudHlwZSA9PT0gJ3N0cmluZycpIHJldHVybiB0aGlzLnRvU3RyaW5nVmFsdWUodmFsdWUpO1xyXG5cclxuICAgIC8vIEZhbGxiYWNrOiB1c2Ugc2FtcGxlIGRhdGEgaWYgYXZhaWxhYmxlXHJcbiAgICBjb25zdCBzYW1wbGUgPSB0aGlzLmRhdGEoKVswXTtcclxuICAgIGlmIChzYW1wbGUgJiYgY29sLmFjY2Vzc29yIGluIHNhbXBsZSkge1xyXG4gICAgICBjb25zdCBzYW1wbGVWYWx1ZSA9IHNhbXBsZVtjb2wuYWNjZXNzb3JdO1xyXG4gICAgICBpZiAodHlwZW9mIHNhbXBsZVZhbHVlID09PSAnYm9vbGVhbicpIHJldHVybiB0aGlzLnRvQm9vbGVhbih2YWx1ZSk7XHJcbiAgICAgIGlmICh0eXBlb2Ygc2FtcGxlVmFsdWUgPT09ICdudW1iZXInKSByZXR1cm4gdGhpcy50b051bWJlcih2YWx1ZSk7XHJcbiAgICAgIGlmICh0eXBlb2Ygc2FtcGxlVmFsdWUgPT09ICdzdHJpbmcnKSByZXR1cm4gdGhpcy50b1N0cmluZ1ZhbHVlKHZhbHVlKTtcclxuICAgIH1cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qKiBDb252ZXJ0cyB2YWx1ZSB0byBib29sZWFuIHVzaW5nIGJlc3QgcHJhY3RpY2VzLiAqL1xyXG4gIHByaXZhdGUgdG9Cb29sZWFuKHZhbHVlOiB1bmtub3duKTogYm9vbGVhbiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicpIHJldHVybiB2YWx1ZTtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSByZXR1cm4gdmFsdWUudHJpbSgpLnRvTG93ZXJDYXNlKCkgPT09ICd0cnVlJyB8fCB2YWx1ZS50cmltKCkgPT09ICcxJztcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInKSByZXR1cm4gdmFsdWUgPT09IDE7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvKiogQ29udmVydHMgdmFsdWUgdG8gbnVtYmVyIHVzaW5nIGJlc3QgcHJhY3RpY2VzLiAqL1xyXG4gIHByaXZhdGUgdG9OdW1iZXIodmFsdWU6IHVua25vd24pOiBudW1iZXIgfCB1bmRlZmluZWQge1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHJldHVybiB2YWx1ZTtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSByZXR1cm4gdmFsdWUudHJpbSgpID09PSAnJyA/IHVuZGVmaW5lZCA6IE51bWJlcih2YWx1ZSk7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicpIHJldHVybiB2YWx1ZSA/IDEgOiAwO1xyXG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICB9XHJcblxyXG4gIC8qKiBDb252ZXJ0cyB2YWx1ZSB0byBzdHJpbmcgdXNpbmcgYmVzdCBwcmFjdGljZXMsIGFsd2F5cyBzdHJpbmdpZmllcyBvYmplY3RzLiAqL1xyXG4gIHByaXZhdGUgdG9TdHJpbmdWYWx1ZSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB7XHJcbiAgICBpZiAodmFsdWUgPT0gbnVsbCkgcmV0dXJuICcnO1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHJldHVybiB2YWx1ZTtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nKSByZXR1cm4gU3RyaW5nKHZhbHVlKTtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHZhbHVlKTtcclxuICAgICAgfSBjYXRjaCB7XHJcbiAgICAgICAgcmV0dXJuICdbb2JqZWN0IE9iamVjdF0nO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICAvLyBGb3IgZnVuY3Rpb25zLCBzeW1ib2xzLCB1bmRlZmluZWQsIGV0Yy4sIHJldHVybiBlbXB0eSBzdHJpbmdcclxuICAgIHJldHVybiAnJztcclxuICB9XHJcblxyXG4gIG9uRWRpdChyb3c6IFQpIHtcclxuICAgIHRoaXMuZWRpdGluZy5zZXQocm93WydpZCddIGFzIG51bWJlcik7XHJcbiAgICBjb25zdCBlZGl0OiBQYXJ0aWFsPFQ+ID0ge307XHJcbiAgICB0aGlzLmNvbHVtbnMuZmlsdGVyKGNvbCA9PiBjb2wudmlzaWJsZSAhPT0gZmFsc2UpLmZvckVhY2goY29sID0+IHtcclxuICAgICAgKGVkaXQgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2NvbC5hY2Nlc3Nvcl0gPSByb3dbY29sLmFjY2Vzc29yXTtcclxuICAgIH0pO1xyXG4gICAgdGhpcy5lZGl0Um93LnNldChlZGl0KTtcclxuICB9XHJcblxyXG4gIGNhbmNlbEVkaXQoKSB7XHJcbiAgICB0aGlzLmVkaXRpbmcuc2V0KG51bGwpO1xyXG4gICAgdGhpcy5lZGl0Um93LnNldChudWxsKTtcclxuICB9XHJcblxyXG4gIG9uRWRpdElucHV0KGV2ZW50OiBFdmVudCB8IE1hdENoZWNrYm94Q2hhbmdlLCBrZXk6IHN0cmluZywgY29sPzogQzgwVGFibGVDb2xEZWYpIHtcclxuICAgIGNvbnN0IGN1cnJlbnQgPSB0aGlzLmVkaXRSb3coKTtcclxuICAgIGlmICghY3VycmVudCkgcmV0dXJuO1xyXG4gICAgaWYgKGNvbD8udHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgIC8vIE1hdENoZWNrYm94Q2hhbmdlXHJcbiAgICAgIGNvbnN0IGNoZWNrZWQgPSAoZXZlbnQgYXMgTWF0Q2hlY2tib3hDaGFuZ2UpLmNoZWNrZWQ7XHJcbiAgICAgIHRoaXMuZWRpdFJvdy5zZXQoeyAuLi5jdXJyZW50LCBba2V5XTogY2hlY2tlZCB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGNvbnN0IHRhcmdldCA9IChldmVudCBhcyBFdmVudCkudGFyZ2V0O1xyXG4gICAgICBpZiAodGFyZ2V0ICYmIHR5cGVvZiAodGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQpLnZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICAgIHRoaXMuZWRpdFJvdy5zZXQoeyAuLi5jdXJyZW50LCBba2V5XTogKHRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS52YWx1ZSB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgc2F2ZUVkaXQocm93OiBUKSB7XHJcbiAgICBjb25zdCBpZCA9IHJvd1snaWQnXTtcclxuICAgIGlmICh0eXBlb2YgaWQgIT09ICdudW1iZXInIHx8ICF0aGlzLmVkaXRSb3coKSkgcmV0dXJuO1xyXG4gICAgY29uc3QgdmlzaWJsZUNvbHVtbnMgPSB0aGlzLmNvbHVtbnMuZmlsdGVyKGNvbCA9PiBjb2wudmlzaWJsZSAhPT0gZmFsc2UpO1xyXG4gICAgY29uc3QgY29udmVydGVkID0gdmlzaWJsZUNvbHVtbnMucmVkdWNlKChhY2MsIGNvbCkgPT4ge1xyXG4gICAgICBhY2NbY29sLmFjY2Vzc29yXSA9IHRoaXMuY29udmVydENlbGxWYWx1ZSh0aGlzLmVkaXRSb3coKSFbY29sLmFjY2Vzc29yXSwgY29sKTtcclxuICAgICAgcmV0dXJuIGFjYztcclxuICAgIH0sIHt9IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KSBhcyBQYXJ0aWFsPFQ+O1xyXG4gICAgLy8gVHlwZS1zYWZlIHVwZGF0ZSBtZXRob2QgZGV0ZWN0aW9uXHJcbiAgICBjb25zdCB1cGRhdGVGbiA9ICh0aGlzLnNlcnZpY2UgYXMgeyB1cGRhdGU/OiAoaWQ6IG51bWJlciwgcm93OiBUKSA9PiBPYnNlcnZhYmxlPFQ+IH0pLnVwZGF0ZTtcclxuICAgIGlmICh1cGRhdGVGbikge1xyXG4gICAgICB1cGRhdGVGbihpZCwgY29udmVydGVkIGFzIFQpLnBpcGUodGFrZSgxKSkuc3Vic2NyaWJlKHtcclxuICAgICAgICBuZXh0OiAoKSA9PiB7XHJcbiAgICAgICAgICB0aGlzLmNhbmNlbEVkaXQoKTtcclxuICAgICAgICAgIHRoaXMucmVmcmVzaCgpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXJyb3I6IChlcnI6IHVua25vd24pID0+IHtcclxuICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSAodHlwZW9mIGVyciA9PT0gJ29iamVjdCcgJiYgZXJyICYmICdtZXNzYWdlJyBpbiBlcnIpID8gKGVyciBhcyB7IG1lc3NhZ2U/OiBzdHJpbmcgfSkubWVzc2FnZSA6IHVuZGVmaW5lZDtcclxuICAgICAgICAgIHRoaXMuZXJyb3JFdmVudC5lbWl0KG1lc3NhZ2UgfHwgJ0Vycm9yIGFsIGVkaXRhcicpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBUcmFja0J5IGZ1bmN0aW9uIGZvciBuZ0ZvciB0byBhdm9pZCBET00gcmUtY3JlYXRpb24gKE5HMDk1NiB3YXJuaW5nKS5cclxuICAgKi9cclxuICB0cmFja0J5SWQoaW5kZXg6IG51bWJlciwgcm93OiBUKTogbnVtYmVyIHwgc3RyaW5nIHtcclxuICAgIGNvbnN0IGlkID0gcm93ICYmIHR5cGVvZiByb3cgPT09ICdvYmplY3QnICYmICdpZCcgaW4gcm93ID8gKHJvdyBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPilbJ2lkJ10gOiB1bmRlZmluZWQ7XHJcbiAgICByZXR1cm4gKHR5cGVvZiBpZCA9PT0gJ3N0cmluZycgfHwgdHlwZW9mIGlkID09PSAnbnVtYmVyJykgPyBpZCA6IGluZGV4O1xyXG4gIH1cclxufVxyXG4iLCI8ZGl2IGNsYXNzPVwidGFibGUtcmVzcG9uc2l2ZVwiPlxuICA8dGFibGUgY2xhc3M9XCJ0YWJsZSB0YWJsZS1ib3JkZXJlZCB0YWJsZS1ob3ZlciBhbGlnbi1taWRkbGVcIj5cbiAgICA8dGhlYWQgY2xhc3M9XCJ0aGVhZCB0YWJsZS1saWdodFwiPlxuICAgICAgPHRyPlxuICAgICAgICBAZm9yIChjb2wgb2YgY29sdW1uczsgdHJhY2sgY29sKSB7XG4gICAgICAgIEBpZiAoY29sLnZpc2libGUgIT09IGZhbHNlKSB7XG4gICAgICAgIEBpZiAoY29sLnR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICA8dGggY2xhc3M9XCJ0ZXh0LWNlbnRlclwiPnt7IGNvbC5sYWJlbCB9fTwvdGg+XG4gICAgICAgIH1cbiAgICAgICAgQGVsc2Uge1xuICAgICAgICA8dGg+e3sgY29sLmxhYmVsIH19PC90aD5cbiAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgPHRoIGNsYXNzPVwidGFibGUtYWN0aW9ucy1oZWFkZXJcIj5cbiAgICAgICAgICA8c3Bhbj5BY3Rpb25zPC9zcGFuPlxuICAgICAgICAgIDxjODAtaWNvbiBidXR0b24gaWNvbj1cImFkZFwiIFtkaXNhYmxlZF09XCJjcmVhdGluZygpXCIgdGl0bGU9XCJBZ3JlZ2FyXCIgY2xhc3M9XCJhZGQtYWN0aW9uLWJ0blwiXG4gICAgICAgICAgICAoaWNvbkNsaWNrKT1cInN0YXJ0Q3JlYXRlKClcIj48L2M4MC1pY29uPlxuICAgICAgICA8L3RoPlxuICAgICAgPC90cj5cbiAgICA8L3RoZWFkPlxuICAgIDx0Ym9keT5cbiAgICAgIEBmb3IgKHJvdyBvZiBkYXRhKCk7IHRyYWNrIHRyYWNrQnlJZChpLCByb3cpOyBsZXQgaSA9ICRpbmRleCkge1xuICAgICAgPHRyPlxuICAgICAgICBAZm9yIChjb2wgb2YgY29sdW1uczsgdHJhY2sgY29sKSB7XG4gICAgICAgIEBpZiAoY29sLnZpc2libGUgIT09IGZhbHNlKSB7XG4gICAgICAgIEBpZiAoY29sLnR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICA8dGQgY2xhc3M9XCJ0ZXh0LWNlbnRlclwiPlxuICAgICAgICAgIEBpZiAoZWRpdGluZygpID09PSByb3dbJ2lkJ10pIHtcbiAgICAgICAgICA8bWF0LWNoZWNrYm94IFtjaGVja2VkXT1cIiEhZWRpdFJvdygpPy5bY29sLmFjY2Vzc29yXVwiIChjaGFuZ2UpPVwib25FZGl0SW5wdXQoJGV2ZW50LCBjb2wuYWNjZXNzb3IsIGNvbClcIlxuICAgICAgICAgICAgW2FyaWEtbGFiZWxdPVwiY29sLmxhYmVsXCI+PC9tYXQtY2hlY2tib3g+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBlbHNlIHtcbiAgICAgICAgICBAaWYgKHJvd1tjb2wuYWNjZXNzb3JdID09PSB0cnVlKSB7XG4gICAgICAgICAgPGM4MC1pY29uIGljb249XCJjaGVja1wiIFtzaXplXT1cIjFcIj48L2M4MC1pY29uPlxuICAgICAgICAgIDxiciAvPlxuICAgICAgICAgIH1cbiAgICAgICAgICBAZWxzZSBpZiAocm93W2NvbC5hY2Nlc3Nvcl0gPT09IGZhbHNlKSB7XG4gICAgICAgICAgPGM4MC1pY29uIGljb249XCJjYW5jZWxcIj48L2M4MC1pY29uPlxuICAgICAgICAgIDxiciAvPlxuICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIDwvdGQ+XG4gICAgICAgIH1cbiAgICAgICAgQGVsc2Uge1xuICAgICAgICA8dGQ+XG4gICAgICAgICAgQGlmIChlZGl0aW5nKCkgPT09IHJvd1snaWQnXSkge1xuICAgICAgICAgIDxpbnB1dCBjbGFzcz1cImZvcm0tY29udHJvbCBmb3JtLWNvbnRyb2wtc21cIiBbdHlwZV09XCJjb2wudHlwZSA9PT0gJ251bWJlcicgPyAnbnVtYmVyJyA6ICd0ZXh0J1wiXG4gICAgICAgICAgICBbdmFsdWVdPVwiZWRpdFJvdygpPy5bY29sLmFjY2Vzc29yXSA/PyAnJ1wiIFtwbGFjZWhvbGRlcl09XCJjb2wubGFiZWxcIlxuICAgICAgICAgICAgKGlucHV0KT1cIm9uRWRpdElucHV0KCRldmVudCwgY29sLmFjY2Vzc29yLCBjb2wpXCIgLz5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGVsc2Uge1xuICAgICAgICAgIHt7IHJvd1tjb2wuYWNjZXNzb3JdIH19XG4gICAgICAgICAgfVxuICAgICAgICA8L3RkPlxuICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICA8dGQgY2xhc3M9XCJ0ZXh0LWNlbnRlclwiPlxuICAgICAgICAgIEBpZiAoZWRpdGluZygpID09PSByb3dbJ2lkJ10pIHtcbiAgICAgICAgICA8YzgwLWljb24gYnV0dG9uIGljb249XCJjaGVja1wiIHRpdGxlPVwiR3VhcmRhclwiIChpY29uQ2xpY2spPVwic2F2ZUVkaXQocm93KVwiPjwvYzgwLWljb24+XG4gICAgICAgICAgPGM4MC1pY29uIGJ1dHRvbiBpY29uPVwiY2FuY2VsXCIgY29sb3I9XCJ3YXJuXCIgdGl0bGU9XCJDYW5jZWxhclwiIChpY29uQ2xpY2spPVwiY2FuY2VsRWRpdCgpXCI+PC9jODAtaWNvbj5cbiAgICAgICAgICB9XG4gICAgICAgICAgQGVsc2Uge1xuICAgICAgICAgIDxjODAtaWNvbiBidXR0b24gaWNvbj1cImVkaXRcIiB0aXRsZT1cIkVkaXRhclwiIChpY29uQ2xpY2spPVwib25FZGl0KHJvdylcIj48L2M4MC1pY29uPlxuICAgICAgICAgIDxjODAtaWNvbiBidXR0b24gaWNvbj1cImRlbGV0ZVwiIGNvbG9yPVwid2FyblwiIHRpdGxlPVwiQm9ycmFyXCIgKGljb25DbGljayk9XCJvbkRlbGV0ZShyb3cpXCI+PC9jODAtaWNvbj5cbiAgICAgICAgICB9XG4gICAgICAgIDwvdGQ+XG4gICAgICA8L3RyPlxuICAgICAgfVxuICAgICAgQGlmIChjcmVhdGluZygpKSB7XG4gICAgICA8dHI+XG4gICAgICAgIEBmb3IgKGNvbCBvZiBjb2x1bW5zOyB0cmFjayBjb2wpIHtcbiAgICAgICAgQGlmIChjb2wudmlzaWJsZSAhPT0gZmFsc2UpIHtcbiAgICAgICAgQGlmIChjb2wudHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgIDx0ZCBjbGFzcz1cInRleHQtY2VudGVyXCI+XG4gICAgICAgICAgPG1hdC1jaGVja2JveCBbY2hlY2tlZF09XCIhIW5ld1JvdygpPy5bY29sLmFjY2Vzc29yXVwiIChjaGFuZ2UpPVwib25JbnB1dCgkZXZlbnQsIGNvbC5hY2Nlc3NvciwgY29sKVwiXG4gICAgICAgICAgICBbYXJpYS1sYWJlbF09XCJjb2wubGFiZWxcIj48L21hdC1jaGVja2JveD5cbiAgICAgICAgPC90ZD5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDx0ZD5cbiAgICAgICAgICA8aW5wdXQgY2xhc3M9XCJmb3JtLWNvbnRyb2wgZm9ybS1jb250cm9sLXNtXCIgW3R5cGVdPVwiY29sLnR5cGUgPT09ICdudW1iZXInID8gJ251bWJlcicgOiAndGV4dCdcIlxuICAgICAgICAgICAgW3ZhbHVlXT1cIm5ld1JvdygpPy5bY29sLmFjY2Vzc29yXSA/PyAnJ1wiIFtwbGFjZWhvbGRlcl09XCJjb2wubGFiZWxcIlxuICAgICAgICAgICAgKGlucHV0KT1cIm9uSW5wdXQoJGV2ZW50LCBjb2wuYWNjZXNzb3IsIGNvbClcIiAvPlxuICAgICAgICA8L3RkPlxuICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICA8dGQgY2xhc3M9XCJ0ZXh0LWNlbnRlclwiPlxuICAgICAgICAgIDxjODAtaWNvbiBidXR0b24gaWNvbj1cImNoZWNrXCIgdGl0bGU9XCJHdWFyZGFyXCIgKGljb25DbGljayk9XCJzYXZlQ3JlYXRlKClcIj48L2M4MC1pY29uPlxuICAgICAgICAgIDxjODAtaWNvbiBidXR0b24gaWNvbj1cImNhbmNlbFwiIGNvbG9yPVwid2FyblwiIHRpdGxlPVwiQ2FuY2VsYXJcIiAoaWNvbkNsaWNrKT1cImNhbmNlbENyZWF0ZSgpXCI+PC9jODAtaWNvbj5cbiAgICAgICAgPC90ZD5cbiAgICAgIDwvdHI+XG4gICAgICB9XG4gICAgPC90Ym9keT5cbiAgPC90YWJsZT5cbiAgQGlmIChkYXRhKCkubGVuZ3RoID09PSAwKSB7XG4gIDxkaXYgY2xhc3M9XCJ0ZXh0LWNlbnRlciB0ZXh0LW11dGVkIHB5LTNcIj5cbiAgICBObyBoYXkgZGF0b3MgcGFyYSBtb3N0cmFyLlxuICA8L2Rpdj5cbiAgfVxuPC9kaXY+Il19
|
package/index.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export * from './lib/
|
|
1
|
+
export * from './lib/table/table.component';
|
|
2
|
+
export * from './lib/icon/icon.component';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter, TemplateRef } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export type Icon = 'check' | 'cancel' | 'edit' | 'delete' | 'add';
|
|
4
|
+
export type Color = 'primary' | 'secondary' | 'warn';
|
|
5
|
+
export declare class C80IconComponent {
|
|
6
|
+
/** Tamaño base del icono (en px) */
|
|
7
|
+
get iconSize(): number;
|
|
8
|
+
icon: Icon;
|
|
9
|
+
color: Color;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
size: number;
|
|
12
|
+
/** Si es true, renderiza como <button> nativo, si es false solo como icono */
|
|
13
|
+
private _button;
|
|
14
|
+
set button(val: boolean | string | null | undefined);
|
|
15
|
+
get button(): boolean;
|
|
16
|
+
/** Tipo de botón nativo (solo si button=true) */
|
|
17
|
+
type: 'button' | 'submit' | 'reset';
|
|
18
|
+
/** Output para click (solo si button=true) */
|
|
19
|
+
iconClick: EventEmitter<Event>;
|
|
20
|
+
checkIconTpl: TemplateRef<unknown>;
|
|
21
|
+
cancelIconTpl: TemplateRef<unknown>;
|
|
22
|
+
editIconTpl: TemplateRef<unknown>;
|
|
23
|
+
deleteIconTpl: TemplateRef<unknown>;
|
|
24
|
+
addIconTpl: TemplateRef<unknown>;
|
|
25
|
+
defaultIconTpl: TemplateRef<unknown>;
|
|
26
|
+
getIconTemplate(): TemplateRef<unknown>;
|
|
27
|
+
get iconColor(): string;
|
|
28
|
+
onButtonClick(event: Event): void;
|
|
29
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<C80IconComponent, never>;
|
|
30
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<C80IconComponent, "c80-icon", never, { "icon": { "alias": "icon"; "required": false; }; "color": { "alias": "color"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "size": { "alias": "size"; "required": false; }; "button": { "alias": "button"; "required": false; }; "type": { "alias": "type"; "required": false; }; }, { "iconClick": "iconClick"; }, never, never, true, never>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { OnInit, EventEmitter } from '@angular/core';
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
|
+
import type { MatCheckboxChange } from '@angular/material/checkbox';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export interface C80TableService<T> {
|
|
6
|
+
get: () => Observable<T[]>;
|
|
7
|
+
create: (row: T) => Observable<T>;
|
|
8
|
+
delete: (id: number) => Observable<void>;
|
|
9
|
+
update: (id: number, row: T) => Observable<T>;
|
|
10
|
+
}
|
|
11
|
+
export interface C80TableColDef {
|
|
12
|
+
accessor: string;
|
|
13
|
+
label: string;
|
|
14
|
+
visible?: boolean;
|
|
15
|
+
type?: 'string' | 'number' | 'boolean';
|
|
16
|
+
}
|
|
17
|
+
export declare class C80TableComponent<T extends Record<string, unknown>> implements OnInit {
|
|
18
|
+
service: C80TableService<T>;
|
|
19
|
+
columns: C80TableColDef[];
|
|
20
|
+
errorEvent: EventEmitter<string>;
|
|
21
|
+
readonly data: import("@angular/core").WritableSignal<T[]>;
|
|
22
|
+
readonly keys: import("@angular/core").WritableSignal<string[]>;
|
|
23
|
+
creating: import("@angular/core").WritableSignal<boolean>;
|
|
24
|
+
newRow: import("@angular/core").WritableSignal<Partial<T> | null>;
|
|
25
|
+
readonly editing: import("@angular/core").WritableSignal<number | null>;
|
|
26
|
+
readonly editRow: import("@angular/core").WritableSignal<Partial<T> | null>;
|
|
27
|
+
ngOnInit(): void;
|
|
28
|
+
onInput(event: Event | MatCheckboxChange, key: string, col?: C80TableColDef): void;
|
|
29
|
+
onDelete(row: T): void;
|
|
30
|
+
refresh(): void;
|
|
31
|
+
startCreate(): void;
|
|
32
|
+
cancelCreate(): void;
|
|
33
|
+
updateNewRow(key: string, value: unknown): void;
|
|
34
|
+
saveCreate(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Converts a cell value based on column type or sample data.
|
|
37
|
+
* Handles stringification of objects for string columns.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Converts a cell value based on column type or sample data.
|
|
41
|
+
* Delegates to type-specific helpers for clarity and maintainability.
|
|
42
|
+
*/
|
|
43
|
+
private convertCellValue;
|
|
44
|
+
/** Converts value to boolean using best practices. */
|
|
45
|
+
private toBoolean;
|
|
46
|
+
/** Converts value to number using best practices. */
|
|
47
|
+
private toNumber;
|
|
48
|
+
/** Converts value to string using best practices, always stringifies objects. */
|
|
49
|
+
private toStringValue;
|
|
50
|
+
onEdit(row: T): void;
|
|
51
|
+
cancelEdit(): void;
|
|
52
|
+
onEditInput(event: Event | MatCheckboxChange, key: string, col?: C80TableColDef): void;
|
|
53
|
+
saveEdit(row: T): void;
|
|
54
|
+
/**
|
|
55
|
+
* TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).
|
|
56
|
+
*/
|
|
57
|
+
trackById(index: number, row: T): number | string;
|
|
58
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<C80TableComponent<any>, never>;
|
|
59
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<C80TableComponent<any>, "c80-table", never, { "service": { "alias": "service"; "required": false; }; "columns": { "alias": "columns"; "required": false; }; }, { "errorEvent": "errorEvent"; }, never, never, true, never>;
|
|
60
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c80/ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@angular/
|
|
6
|
-
"
|
|
5
|
+
"@angular/core": "^18.2.0",
|
|
6
|
+
"rxjs": "~7.8.0",
|
|
7
|
+
"@angular/material": "^18.2.14",
|
|
8
|
+
"@angular/common": "~18.2.0"
|
|
7
9
|
},
|
|
8
10
|
"sideEffects": false,
|
|
9
11
|
"module": "esm2022/c80-ui.mjs",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export class UiComponent {
|
|
5
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UiComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: UiComponent, isStandalone: true, selector: "lib-ui", ngImport: i0, template: "<p>Ui works!</p>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7
|
-
}
|
|
8
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: UiComponent, decorators: [{
|
|
9
|
-
type: Component,
|
|
10
|
-
args: [{ selector: 'lib-ui', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p>Ui works!</p>\n" }]
|
|
11
|
-
}] });
|
|
12
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidWkuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy91aS9zcmMvbGliL3VpL3VpLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL2xpYnMvdWkvc3JjL2xpYi91aS91aS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7QUFVL0MsTUFBTSxPQUFPLFdBQVc7d0dBQVgsV0FBVzs0RkFBWCxXQUFXLGtFQ1h4QixvQkFDQSx5RERLWSxZQUFZOzs0RkFLWCxXQUFXO2tCQVJ2QixTQUFTOytCQUNFLFFBQVEsY0FDTixJQUFJLFdBQ1AsQ0FBQyxZQUFZLENBQUMsbUJBR04sdUJBQXVCLENBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi11aScsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxuICB0ZW1wbGF0ZVVybDogJy4vdWkuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybDogJy4vdWkuY29tcG9uZW50LmNzcycsXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBVaUNvbXBvbmVudCB7fVxuIiwiPHA+VWkgd29ya3MhPC9wPlxuIl19
|
package/lib/ui/ui.component.d.ts
DELETED