@c80/ui 1.0.56 → 1.0.57
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/lib/action-list/action-list.component.js.map +1 -1
- package/esm2022/lib/header/header.component.js.map +1 -1
- package/esm2022/lib/info-list/info-list.component.js.map +1 -1
- package/esm2022/lib/input-field/input-field.component.js.map +1 -1
- package/esm2022/lib/modal/modal.component.js +2 -2
- package/esm2022/lib/modal/modal.component.js.map +1 -1
- package/esm2022/lib/profile-stats/profile-stats.component.js.map +1 -1
- package/esm2022/lib/snackbar/snackbar.component.js +2 -2
- package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
- package/esm2022/lib/tab/c80-tab.component.js +2 -2
- package/esm2022/lib/table/table.component.js +2 -2
- package/esm2022/lib/table/table.component.js.map +1 -1
- package/lib/card-level/card-level.component.d.ts +1 -1
- package/lib/snackbar/snackbar.component.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-list.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/action-list/action-list.component.ts","../../../../../libs/ui/src/lib/action-list/action-list.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;
|
|
1
|
+
{"version":3,"file":"action-list.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/action-list/action-list.component.ts","../../../../../libs/ui/src/lib/action-list/action-list.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;AAWxC,MAAM,OAAO,mBAAmB;IAC5B,KAAK,GAAG,KAAK,CAAS,EAAE,iDAAC,CAAC;IAC1B,OAAO,GAAG,KAAK,CAAe,EAAE,mDAAC,CAAC;IAElC,WAAW,GAAG,MAAM,EAAU,CAAC;IAErB,aAAa,CAAC,MAAkB;QACtC,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC7C,MAAM,CAAC,MAAM,EAAE,CAAC;QACpB,CAAC;IACL,CAAC;wGAZQ,mBAAmB;4FAAnB,mBAAmB,sXCbhC,w5BAoBM,8+BDZQ,aAAa;;4FAKd,mBAAmB;kBAT/B,SAAS;+BAEI,iBAAiB,cACf,IAAI,WACP,CAAC,aAAa,CAAC,mBAGP,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';\nimport type { ActionItem } from './action-list.types';\nimport { IconComponent } from '../icon';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-action-list',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './action-list.component.html',\n styleUrl: './action-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ActionListComponent {\n title = input<string>('');\n actions = input<ActionItem[]>([]);\n\n actionClick = output<string>();\n\n protected onActionClick(action: ActionItem): void {\n if (typeof action.action === 'string') {\n this.actionClick.emit(action.action);\n } else if (typeof action.action === 'function') {\n action.action();\n }\n }\n}","<div class=\"action-list\">\n @if (title()) {\n <h2 class=\"action-list__title\">{{ title() }}</h2>\n }\n\n @for (action of actions(); track $index) {\n <button class=\"action-list__item\" [class.action-list__item--danger]=\"action.isDanger\" [class.action-list__item--navigable]=\"action.isNavigable\" (click)=\"onActionClick(action)\">\n\n <div class=\"action-list__info\">\n <span class=\"action-list__label\">{{ action.label }}</span>\n @if (action.description) {\n <span class=\"action-list__description\">{{ action.description }}</span>\n }\n </div>\n\n @if (action.icon || action.isNavigable) {\n <c80-icon [button]=\"!action.isNavigable\" [icon]=\"action.icon || (action.isNavigable ? 'arrowRight' : '')\" [color]=\"action.isDanger ? 'warn' : undefined\" [title]=\"action.label\" />\n }\n </button>\n }\n</div>"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"header.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/header/header.component.ts","../../../../../libs/ui/src/lib/header/header.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;
|
|
1
|
+
{"version":3,"file":"header.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/header/header.component.ts","../../../../../libs/ui/src/lib/header/header.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;;AAYxC,MAAM,OAAO,eAAe;IACP,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAE7C,MAAM,GAAG,KAAK,CAAC,QAAQ,iDAAgB,CAAC;IAE9B,WAAW;QACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;wGAPQ,eAAe;4FAAf,eAAe,4MCd5B,kRAIS,0bDKK,aAAa;;4FAKd,eAAe;kBAT3B,SAAS;+BAEI,YAAY,cACV,IAAI,WACP,CAAC,aAAa,CAAC,mBAGP,uBAAuB,CAAC,MAAM","sourcesContent":["import { Location } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, inject, input } from '@angular/core';\nimport { IconComponent } from '../icon';\nimport type { HeaderConfig } from './header.types';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-header',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './header.component.html',\n styleUrl: './header.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class HeaderComponent {\n private readonly location = inject(Location);\n\n config = input.required<HeaderConfig>();\n\n protected onBackClick(): void {\n this.location.back();\n }\n}","<header class=\"header\">\n <c80-icon button icon=\"arrowLeft\" [size]=\"1.2\" (iconClick)=\"onBackClick()\" title=\"Volver\" class=\"header__back-btn\" />\n <h1 class=\"header__title\">{{ config().title }}</h1>\n <span class=\"header__spacer\"></span>\n</header>"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"info-list.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/info-list/info-list.component.ts","../../../../../libs/ui/src/lib/info-list/info-list.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"info-list.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/info-list/info-list.component.ts","../../../../../libs/ui/src/lib/info-list/info-list.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;;AAY1E,MAAM,OAAO,iBAAiB;IACjB,KAAK,GAAG,KAAK,CAAC,QAAQ,gDAAc,CAAC;wGADrC,iBAAiB;4FAAjB,iBAAiB,4MCZ9B,0SASM;;4FDGO,iBAAiB;kBAT7B,SAAS;+BAEI,eAAe,cACb,IAAI,WACP,EAAE,mBAGM,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, ChangeDetectionStrategy } from '@angular/core';\nimport type { InfoItem } from './info-list.types';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-info-list',\n standalone: true,\n imports: [],\n templateUrl: './info-list.component.html',\n styleUrl: './info-list.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class InfoListComponent {\n readonly items = input.required<InfoItem[]>();\n}","<div class=\"info-list\">\n @for (item of items(); track $index) {\n @if (item.value) {\n <div class=\"info-list__item\">\n <span class=\"info-list__label\">{{ item.label }}</span>\n <span class=\"info-list__value\">{{ item.value }}</span>\n </div>\n }\n }\n</div>"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input-field.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/input-field/input-field.component.ts","../../../../../libs/ui/src/lib/input-field/input-field.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"input-field.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/input-field/input-field.component.ts","../../../../../libs/ui/src/lib/input-field/input-field.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;;AAWnF,MAAM,OAAO,mBAAmB;IACnB,KAAK,GAAG,MAAM,CAAS,EAAE,iDAAC,CAAC;IAC3B,KAAK,GAAG,MAAM,CAAS,EAAE,iDAAC,CAAC;IAC3B,WAAW,GAAG,MAAM,CAAS,EAAE,uDAAC,CAAC;IACjC,IAAI,GAAG,MAAM,CAAgC,MAAM,gDAAC,CAAC;IACrD,SAAS,GAAG,MAAM,CAAqB,SAAS,qDAAC,CAAC;IAClD,QAAQ,GAAG,MAAM,CAAU,KAAK,oDAAC,CAAC;IAClC,QAAQ,GAAG,MAAM,CAAU,KAAK,oDAAC,CAAC;IAE3C,WAAW,GAAG,MAAM,EAAU,CAAC;IAC/B,YAAY,GAAG,MAAM,EAAQ,CAAC;IAEX,SAAS,GAAG,MAAM,CAAC,KAAK,qDAAC,CAAC;IAEnC,aAAa,CAAC,KAAY;QAChC,MAAM,QAAQ,GAAI,KAAK,CAAC,MAA2B,CAAC,KAAK,CAAC;QAC1D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAES,OAAO;QACb,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAES,MAAM;QACZ,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAES,SAAS,CAAC,KAAoB;QACpC,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACxB,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QAC7B,CAAC;IACL,CAAC;wGAhCQ,mBAAmB;4FAAnB,mBAAmB,kJCXhC,ihBAMM;;4FDKO,mBAAmB;kBAT/B,SAAS;+BAEI,iBAAiB,cACf,IAAI,WACP,EAAE,mBAGM,uBAAuB,CAAC,MAAM","sourcesContent":["import { ChangeDetectionStrategy, Component, output, signal } from '@angular/core';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-input-field',\n standalone: true,\n imports: [],\n templateUrl: './input-field.component.html',\n styleUrl: './input-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class InputFieldComponent {\n readonly label = signal<string>('');\n readonly value = signal<string>('');\n readonly placeholder = signal<string>('');\n readonly type = signal<'text' | 'email' | 'password'>('text');\n readonly maxLength = signal<number | undefined>(undefined);\n readonly readonly = signal<boolean>(false);\n readonly required = signal<boolean>(false);\n\n valueChange = output<string>();\n enterPressed = output<void>();\n\n protected readonly isFocused = signal(false);\n\n protected onValueChange(event: Event): void {\n const newValue = (event.target as HTMLInputElement).value;\n this.value.set(newValue);\n this.valueChange.emit(newValue);\n }\n\n protected onFocus(): void {\n this.isFocused.set(true);\n }\n\n protected onBlur(): void {\n this.isFocused.set(false);\n }\n\n protected onKeyDown(event: KeyboardEvent): void {\n if (event.key === 'Enter') {\n this.enterPressed.emit();\n }\n }\n}","<div class=\"input-field\">\n <div class=\"input-field__item\">\n <span class=\"input-field__label\">{{ label() }}</span>\n <input class=\"input-field__input\" [class.input-field__input--focused]=\"isFocused()\" [type]=\"type()\" [value]=\"value()\" [placeholder]=\"placeholder()\" [attr.maxlength]=\"maxLength()\" [readonly]=\"readonly()\" [required]=\"required()\"\n (input)=\"onValueChange($event)\" (focus)=\"onFocus()\" (blur)=\"onBlur()\" (keydown)=\"onKeyDown($event)\" />\n </div>\n</div>"]}
|
|
@@ -78,10 +78,10 @@ export class ModalComponent {
|
|
|
78
78
|
return this.config().noText ?? 'No';
|
|
79
79
|
}
|
|
80
80
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
81
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ModalComponent, isStandalone: true, selector: "c80-modal", ngImport: i0, template: "<!-- Modal Backdrop -->\n@if (isOpen()) {\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\n\n <!-- Modal Container -->\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\n\n <!-- Modal Header -->\n <div class=\"modal-header\">\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" color=\"warn\" />\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <p class=\"modal-message\">{{ config().message }}</p>\n </div>\n\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n\n <!-- Info Modal - Solo OK -->\n @if (showOkButton()) {\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\"
|
|
81
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ModalComponent, isStandalone: true, selector: "c80-modal", ngImport: i0, template: "<!-- Modal Backdrop -->\n@if (isOpen()) {\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\n\n <!-- Modal Container -->\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\n\n <!-- Modal Header -->\n <div class=\"modal-header\">\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" color=\"warn\" />\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <p class=\"modal-message\">{{ config().message }}</p>\n </div>\n\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n\n <!-- Info Modal - Solo OK -->\n @if (showOkButton()) {\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n }\n\n <!-- Yes/No Modal -->\n @if (showYesNoButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" (iconClick)=\"onYes()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"warn\" (iconClick)=\"onNo()\" [border]=\"true\" />\n }\n\n <!-- Confirm Modal -->\n @if (showConfirmButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"warn\" (iconClick)=\"onCancel()\" [border]=\"true\" />\n }\n\n </div>\n </dialog>\n</div>\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1100;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:var(--color-bg-primary);border-radius:8px;box-shadow:0 4px 20px #00000026;border:1px solid var(--color-border-default);max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid var(--color-border-default);background:var(--color-bg-secondary)}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:var(--color-text-primary);line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:var(--color-text-primary);white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:var(--color-bg-secondary);border-top:1px solid var(--color-border-default)}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}\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 });
|
|
82
82
|
}
|
|
83
83
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ModalComponent, decorators: [{
|
|
84
84
|
type: Component,
|
|
85
|
-
args: [{ selector: 'c80-modal', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Modal Backdrop -->\n@if (isOpen()) {\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\n\n <!-- Modal Container -->\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\n\n <!-- Modal Header -->\n <div class=\"modal-header\">\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" color=\"warn\" />\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <p class=\"modal-message\">{{ config().message }}</p>\n </div>\n\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n\n <!-- Info Modal - Solo OK -->\n @if (showOkButton()) {\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\"
|
|
85
|
+
args: [{ selector: 'c80-modal', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Modal Backdrop -->\n@if (isOpen()) {\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\n\n <!-- Modal Container -->\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\n\n <!-- Modal Header -->\n <div class=\"modal-header\">\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" color=\"warn\" />\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <p class=\"modal-message\">{{ config().message }}</p>\n </div>\n\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n\n <!-- Info Modal - Solo OK -->\n @if (showOkButton()) {\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n }\n\n <!-- Yes/No Modal -->\n @if (showYesNoButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" (iconClick)=\"onYes()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"warn\" (iconClick)=\"onNo()\" [border]=\"true\" />\n }\n\n <!-- Confirm Modal -->\n @if (showConfirmButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"warn\" (iconClick)=\"onCancel()\" [border]=\"true\" />\n }\n\n </div>\n </dialog>\n</div>\n}", styles: [".modal-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);z-index:1100;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s ease-in-out;outline:none}.modal-backdrop.show{opacity:1}.modal-container{background:var(--color-bg-primary);border-radius:8px;box-shadow:0 4px 20px #00000026;border:1px solid var(--color-border-default);max-width:400px;width:90%;max-height:90vh;overflow:hidden;transform:scale(.9) translateY(-10px);transition:all .15s ease-out;position:relative;padding:0}.modal-container.show{transform:scale(1) translateY(0)}.modal-container::backdrop{background:transparent}.modal-header{display:flex;align-items:center;gap:8px;padding:16px 20px 12px;border-bottom:1px solid var(--color-border-default);background:var(--color-bg-secondary)}.modal-header .modal-title{flex:1;margin:0;font-size:16px;font-weight:600;color:var(--color-text-primary);line-height:1.3}.modal-body{padding:16px 20px}.modal-body .modal-message{margin:0;font-size:14px;line-height:1.5;color:var(--color-text-primary);white-space:pre-line}.modal-footer{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 16px;background:var(--color-bg-secondary);border-top:1px solid var(--color-border-default)}@media(max-width:768px){.modal-container{width:95%;margin:10px}.modal-header{padding:12px 16px 8px}.modal-header .modal-title{font-size:15px}.modal-body{padding:12px 16px}.modal-body .modal-message{font-size:13px}.modal-footer{padding:8px 16px 12px;flex-direction:column}}\n"] }]
|
|
86
86
|
}], ctorParameters: () => [] });
|
|
87
87
|
//# sourceMappingURL=modal.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"modal.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.component.ts","../../../../../libs/ui/src/lib/modal/modal.component.html"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"modal.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/modal/modal.component.ts","../../../../../libs/ui/src/lib/modal/modal.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, effect, inject, ChangeDetectionStrategy } from '@angular/core';\nimport { ModalService } from './modal.service';\nimport { IconComponent } from './../icon';\n\nexport type ModalType = 'info' | 'confirm' | 'yesNo' | 'warning' | 'error';\n\nexport interface ModalConfig {\n title: string;\n message: string;\n type?: ModalType;\n confirmText?: string;\n cancelText?: string;\n yesText?: string;\n noText?: string;\n showCancel?: boolean;\n}\n\nexport interface ModalResult {\n action: 'confirm' | 'cancel' | 'yes' | 'no';\n confirmed: boolean;\n}\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-modal',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ModalComponent {\n private readonly modalService = inject(ModalService);\n\n readonly isOpen = this.modalService.modalState.isOpen;\n readonly config = this.modalService.modalState.config;\n readonly isVisible = computed(() => this.isOpen());\n\n constructor() {\n effect(() => {\n if (this.isOpen()) {\n // Auto-focus modal when opened for accessibility\n /* v8 ignore next 8 */\n setTimeout(() => {\n const backdrop = document.querySelector(\n '.modal-backdrop'\n ) as HTMLElement;\n if (backdrop) {\n backdrop.focus();\n }\n }, 100);\n }\n });\n }\n\n onConfirm() {\n this.modalService.handleResult({ action: 'confirm', confirmed: true });\n }\n\n onCancel() {\n this.modalService.handleResult({ action: 'cancel', confirmed: false });\n }\n\n onYes() {\n this.modalService.handleResult({ action: 'yes', confirmed: true });\n }\n\n onNo() {\n this.modalService.handleResult({ action: 'no', confirmed: false });\n }\n\n closeModal() {\n this.modalService.closeModal();\n }\n\n onBackdropClick(event: Event) {\n if (event.target === event.currentTarget) {\n this.closeModal();\n }\n }\n\n getPrimaryButtonClass(): string {\n const configValue = this.config();\n switch (configValue.type) {\n case 'warning':\n return 'btn-warning';\n case 'error':\n return 'btn-danger';\n case 'confirm':\n case 'yesNo':\n return 'btn-primary';\n default:\n return 'btn-info';\n }\n }\n\n showYesNoButtons(): boolean {\n return this.config().type === 'yesNo';\n }\n\n showConfirmButtons(): boolean {\n const type = this.config().type;\n return type === 'confirm' || type === 'warning' || type === 'error';\n }\n\n showOkButton(): boolean {\n return this.config().type === 'info';\n }\n\n getConfirmText(): string {\n return this.config().confirmText ?? 'Confirmar';\n }\n\n getCancelText(): string {\n return this.config().cancelText ?? 'Cancelar';\n }\n\n getYesText(): string {\n return this.config().yesText ?? 'Sí';\n }\n\n getNoText(): string {\n return this.config().noText ?? 'No';\n }\n}\n","<!-- Modal Backdrop -->\n@if (isOpen()) {\n<div class=\"modal-backdrop\" [class.show]=\"isVisible()\" tabindex=\"-1\" (click)=\"onBackdropClick($event)\" (keydown.escape)=\"closeModal()\">\n\n <!-- Modal Container -->\n <dialog class=\"modal-container\" [class.show]=\"isVisible()\" [attr.aria-labelledby]=\"'modal-title'\" [open]=\"isVisible()\">\n\n <!-- Modal Header -->\n <div class=\"modal-header\">\n <h4 class=\"modal-title\" id=\"modal-title\">{{ config().title }}</h4>\n <c80-icon [button]=\"true\" icon=\"close\" (iconClick)=\"closeModal()\" title=\"Cerrar\" color=\"warn\" />\n </div>\n\n <!-- Modal Body -->\n <div class=\"modal-body\">\n <p class=\"modal-message\">{{ config().message }}</p>\n </div>\n\n <!-- Modal Footer -->\n <div class=\"modal-footer\">\n\n <!-- Info Modal - Solo OK -->\n @if (showOkButton()) {\n <c80-icon [button]=\"true\" icon=\"check\" textRight=\"OK\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n }\n\n <!-- Yes/No Modal -->\n @if (showYesNoButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getYesText()\" (iconClick)=\"onYes()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getNoText()\" color=\"warn\" (iconClick)=\"onNo()\" [border]=\"true\" />\n }\n\n <!-- Confirm Modal -->\n @if (showConfirmButtons()) {\n <c80-icon [button]=\"true\" icon=\"check\" [textRight]=\"getConfirmText()\" (iconClick)=\"onConfirm()\" [border]=\"true\" />\n <c80-icon [button]=\"true\" icon=\"cancel\" [textRight]=\"getCancelText()\" color=\"warn\" (iconClick)=\"onCancel()\" [border]=\"true\" />\n }\n\n </div>\n </dialog>\n</div>\n}"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-stats.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/profile-stats/profile-stats.component.ts","../../../../../libs/ui/src/lib/profile-stats/profile-stats.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"profile-stats.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/profile-stats/profile-stats.component.ts","../../../../../libs/ui/src/lib/profile-stats/profile-stats.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;;AAW1E,MAAM,OAAO,qBAAqB;IAC9B,KAAK,GAAG,KAAK,CAAC,QAAQ,gDAAc,CAAC;wGAD5B,qBAAqB;4FAArB,qBAAqB,gNCXlC,2PAOM;;4FDIO,qBAAqB;kBARjC,SAAS;+BAEI,mBAAmB,cACjB,IAAI,mBAGC,uBAAuB,CAAC,MAAM","sourcesContent":["import { ChangeDetectionStrategy, Component, input } from '@angular/core';\nimport type { StatItem } from './profile-stats.types';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-profile-stats',\n standalone: true,\n templateUrl: './profile-stats.component.html',\n styleUrl: './profile-stats.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ProfileStatsComponent {\n stats = input.required<StatItem[]>();\n}","<div class=\"stats\">\n @for (stat of stats(); track $index) {\n <div class=\"stats__item\">\n <span class=\"stats__value\">{{ stat.value }}</span>\n <span class=\"stats__label\">{{ stat.label }}</span>\n </div>\n }\n</div>"]}
|
|
@@ -50,10 +50,10 @@ export class SnackbarComponent {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: SnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
53
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: SnackbarComponent, isStandalone: true, selector: "
|
|
53
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: SnackbarComponent, isStandalone: true, selector: "c80-snackbar", ngImport: i0, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--color-bg-snackbar);color:var(--color-text-primary);border-radius:.25rem;box-shadow:var(--shadow-lg);pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:var(--color-text-link-light);cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:var(--color-bg-hover-overlay)}.notification-success{background:var(--color-icon-success)}.notification-success .snackbar-action{color:var(--color-text-inverse)}.notification-error{background:var(--color-icon-danger)}.notification-error .snackbar-action{color:var(--color-text-primary)}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
54
54
|
}
|
|
55
55
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: SnackbarComponent, decorators: [{
|
|
56
56
|
type: Component,
|
|
57
|
-
args: [{ selector: '
|
|
57
|
+
args: [{ selector: 'c80-snackbar', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}", styles: [":host{position:fixed;z-index:9999;pointer-events:none}.snackbar{display:flex;align-items:center;gap:.75rem;padding:.875rem 1rem;background:var(--color-bg-snackbar);color:var(--color-text-primary);border-radius:.25rem;box-shadow:var(--shadow-lg);pointer-events:auto;animation:slideIn .3s ease-out;min-width:18rem;max-width:35rem}.snackbar-message{flex:1;font-size:.875rem}.snackbar-action{background:transparent;border:none;color:var(--color-text-link-light);cursor:pointer;font-size:.875rem;font-weight:500;text-transform:uppercase;padding:.25rem .5rem;border-radius:.25rem;transition:background-color .2s}.snackbar-action:hover{background-color:var(--color-bg-hover-overlay)}.notification-success{background:var(--color-icon-success)}.notification-success .snackbar-action{color:var(--color-text-inverse)}.notification-error{background:var(--color-icon-danger)}.notification-error .snackbar-action{color:var(--color-text-primary)}@keyframes slideIn{0%{opacity:0;transform:translateY(-1rem)}to{opacity:1;transform:translateY(0)}}\n"] }]
|
|
58
58
|
}] });
|
|
59
59
|
//# sourceMappingURL=snackbar.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snackbar.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.component.ts","../../../../../libs/ui/src/lib/snackbar/snackbar.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;;
|
|
1
|
+
{"version":3,"file":"snackbar.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/snackbar/snackbar.component.ts","../../../../../libs/ui/src/lib/snackbar/snackbar.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, computed, signal, ElementRef, inject, Renderer2, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';\nimport type { SnackbarData } from './snackbar.model';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-snackbar',\n standalone: true,\n templateUrl: './snackbar.component.html',\n styleUrl: './snackbar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SnackbarComponent {\n private readonly elementRef = inject(ElementRef);\n private readonly renderer = inject(Renderer2);\n private readonly cdr = inject(ChangeDetectorRef);\n\n /* v8 ignore next */\n readonly data = signal<SnackbarData | null>(null);\n /* v8 ignore next */\n readonly visible = signal(false);\n\n private timerId?: ReturnType<typeof setTimeout>;\n\n readonly panelClasses = computed(() => this.data()?.config.panelClass.join(' ') ?? '');\n\n show(data: SnackbarData): void {\n this.clearTimer();\n this.data.set(data);\n this.applyPosition(data.config);\n this.visible.set(true);\n\n // Marcar para revisión de cambios con OnPush\n this.cdr.markForCheck();\n\n if (data.config.duration > 0) {\n this.timerId = setTimeout(() => this.dismiss(), data.config.duration);\n }\n }\n\n dismiss(): void {\n this.visible.set(false);\n this.clearTimer();\n\n // Marcar para revisión de cambios con OnPush\n this.cdr.markForCheck();\n }\n\n private clearTimer(): void {\n if (this.timerId !== undefined) {\n clearTimeout(this.timerId);\n this.timerId = undefined;\n }\n }\n\n private applyPosition(config: SnackbarData['config']): void {\n const host = this.elementRef.nativeElement;\n const { verticalPosition, horizontalPosition } = config;\n\n const positions = ['top', 'bottom', 'left', 'right', 'transform'];\n for (const pos of positions) {\n this.renderer.removeStyle(host, pos);\n }\n\n this.renderer.setStyle(host, verticalPosition, '1rem');\n\n if (horizontalPosition === 'center') {\n this.renderer.setStyle(host, 'left', '50%');\n this.renderer.setStyle(host, 'transform', 'translateX(-50%)');\n } else {\n this.renderer.setStyle(host, horizontalPosition, '1rem');\n }\n }\n}\n","@if (visible() && data(); as snackData) {\n<div class=\"snackbar\" [class]=\"panelClasses()\">\n <span class=\"snackbar-message\">{{ snackData.message }}</span>\n @if (snackData.action) {\n <button class=\"snackbar-action\" type=\"button\" (click)=\"dismiss()\">\n {{ snackData.action }}\n </button>\n }\n</div>\n}"]}
|
|
@@ -24,10 +24,10 @@ export class TabComponent {
|
|
|
24
24
|
return label?.template ?? null;
|
|
25
25
|
}
|
|
26
26
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
27
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: TabComponent, isStandalone: true, selector: "c80-tab", inputs: { selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectedIndexChange: "selectedIndexChange" }, queries: [{ propertyName: "tabs", predicate: C80TabItemDirective, isSignal: true }, { propertyName: "labels", predicate: C80TabLabelDirective, isSignal: true }], ngImport: i0, template: "<div class=\"c80-tab-container\">\n <div class=\"c80-tab-header\">\n <div class=\"c80-tab-labels\">\n @for (tab of tabs(); track $index) {\n <button type=\"button\" class=\"c80-tab-label\" [class.active]=\"selectedIndex() === $index\" (click)=\"onTabClick($index)\">\n @if (getTabLabel($index); as labelTemplate) {\n <ng-container *ngTemplateOutlet=\"labelTemplate\" />\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"c80-tab-body\">\n @for (tab of tabs(); track $index) {\n @if (selectedIndex() === $index) {\n <div class=\"c80-tab-content\">\n <ng-container *ngTemplateOutlet=\"getTabContent($index)\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".c80-tab-container{display:flex;flex-direction:column;height:100%}.c80-tab-header{border-bottom:1px solid #dee2e6;background:#f8f9fa}.c80-tab-labels{display:flex;gap:0;width:100%;max-height:40px}.c80-tab-labels button{padding:10px}.c80-tab-label{flex:1;min-width:120px;padding:16px;background:transparent;border:none;border-bottom:2px solid transparent;cursor:pointer;opacity:.7;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px;font-family:inherit;font-size:14px;font-weight:500;color:inherit}.c80-tab-label:hover{opacity:.9;background:#0000000a}.c80-tab-label.active{opacity:1;border-bottom-color:#000;color:#000}.c80-tab-label:focus-visible{outline:none;outline-offset:-2px}.c80-tab-body{flex:1;overflow-y:auto;position:relative}.c80-tab-content{height:100%;animation:fadeIn .2s ease-in}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:768px){.c80-tab-label{min-width:
|
|
27
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: TabComponent, isStandalone: true, selector: "c80-tab", inputs: { selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectedIndexChange: "selectedIndexChange" }, queries: [{ propertyName: "tabs", predicate: C80TabItemDirective, isSignal: true }, { propertyName: "labels", predicate: C80TabLabelDirective, isSignal: true }], ngImport: i0, template: "<div class=\"c80-tab-container\">\n <div class=\"c80-tab-header\">\n <div class=\"c80-tab-labels\">\n @for (tab of tabs(); track $index) {\n <button type=\"button\" class=\"c80-tab-label\" [class.active]=\"selectedIndex() === $index\" (click)=\"onTabClick($index)\">\n @if (getTabLabel($index); as labelTemplate) {\n <ng-container *ngTemplateOutlet=\"labelTemplate\" />\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"c80-tab-body\">\n @for (tab of tabs(); track $index) {\n @if (selectedIndex() === $index) {\n <div class=\"c80-tab-content\">\n <ng-container *ngTemplateOutlet=\"getTabContent($index)\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".c80-tab-container{display:flex;flex-direction:column;height:100%}.c80-tab-header{border-bottom:1px solid #dee2e6;background:#f8f9fa}.c80-tab-labels{display:flex;gap:0;width:100%;max-height:40px}.c80-tab-labels button{padding:10px}.c80-tab-label{flex:1;min-width:120px;padding:16px;background:transparent;border:none;border-bottom:2px solid transparent;cursor:pointer;opacity:.7;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px;font-family:inherit;font-size:14px;font-weight:500;color:inherit}.c80-tab-label:hover{opacity:.9;background:#0000000a}.c80-tab-label.active{opacity:1;border-bottom-color:#000;color:#000}.c80-tab-label:focus-visible{outline:none;outline-offset:-2px}.c80-tab-body{flex:1;overflow-y:auto;position:relative}.c80-tab-content{height:100%;animation:fadeIn .2s ease-in}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:768px){.c80-tab-label{min-width:70px;padding:12px 8px}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
28
28
|
}
|
|
29
29
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TabComponent, decorators: [{
|
|
30
30
|
type: Component,
|
|
31
|
-
args: [{ selector: 'c80-tab', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c80-tab-container\">\n <div class=\"c80-tab-header\">\n <div class=\"c80-tab-labels\">\n @for (tab of tabs(); track $index) {\n <button type=\"button\" class=\"c80-tab-label\" [class.active]=\"selectedIndex() === $index\" (click)=\"onTabClick($index)\">\n @if (getTabLabel($index); as labelTemplate) {\n <ng-container *ngTemplateOutlet=\"labelTemplate\" />\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"c80-tab-body\">\n @for (tab of tabs(); track $index) {\n @if (selectedIndex() === $index) {\n <div class=\"c80-tab-content\">\n <ng-container *ngTemplateOutlet=\"getTabContent($index)\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".c80-tab-container{display:flex;flex-direction:column;height:100%}.c80-tab-header{border-bottom:1px solid #dee2e6;background:#f8f9fa}.c80-tab-labels{display:flex;gap:0;width:100%;max-height:40px}.c80-tab-labels button{padding:10px}.c80-tab-label{flex:1;min-width:120px;padding:16px;background:transparent;border:none;border-bottom:2px solid transparent;cursor:pointer;opacity:.7;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px;font-family:inherit;font-size:14px;font-weight:500;color:inherit}.c80-tab-label:hover{opacity:.9;background:#0000000a}.c80-tab-label.active{opacity:1;border-bottom-color:#000;color:#000}.c80-tab-label:focus-visible{outline:none;outline-offset:-2px}.c80-tab-body{flex:1;overflow-y:auto;position:relative}.c80-tab-content{height:100%;animation:fadeIn .2s ease-in}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:768px){.c80-tab-label{min-width:
|
|
31
|
+
args: [{ selector: 'c80-tab', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c80-tab-container\">\n <div class=\"c80-tab-header\">\n <div class=\"c80-tab-labels\">\n @for (tab of tabs(); track $index) {\n <button type=\"button\" class=\"c80-tab-label\" [class.active]=\"selectedIndex() === $index\" (click)=\"onTabClick($index)\">\n @if (getTabLabel($index); as labelTemplate) {\n <ng-container *ngTemplateOutlet=\"labelTemplate\" />\n }\n </button>\n }\n </div>\n </div>\n\n <div class=\"c80-tab-body\">\n @for (tab of tabs(); track $index) {\n @if (selectedIndex() === $index) {\n <div class=\"c80-tab-content\">\n <ng-container *ngTemplateOutlet=\"getTabContent($index)\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".c80-tab-container{display:flex;flex-direction:column;height:100%}.c80-tab-header{border-bottom:1px solid #dee2e6;background:#f8f9fa}.c80-tab-labels{display:flex;gap:0;width:100%;max-height:40px}.c80-tab-labels button{padding:10px}.c80-tab-label{flex:1;min-width:120px;padding:16px;background:transparent;border:none;border-bottom:2px solid transparent;cursor:pointer;opacity:.7;transition:all .2s;display:flex;align-items:center;justify-content:center;gap:8px;font-family:inherit;font-size:14px;font-weight:500;color:inherit}.c80-tab-label:hover{opacity:.9;background:#0000000a}.c80-tab-label.active{opacity:1;border-bottom-color:#000;color:#000}.c80-tab-label:focus-visible{outline:none;outline-offset:-2px}.c80-tab-body{flex:1;overflow-y:auto;position:relative}.c80-tab-content{height:100%;animation:fadeIn .2s ease-in}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:768px){.c80-tab-label{min-width:70px;padding:12px 8px}}\n"] }]
|
|
32
32
|
}], propDecorators: { tabs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => C80TabItemDirective), { isSignal: true }] }], labels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => C80TabLabelDirective), { isSignal: true }] }], selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }, { type: i0.Output, args: ["selectedIndexChange"] }], selectedIndexChange: [{ type: i0.Output, args: ["selectedIndexChange"] }] } });
|
|
33
33
|
//# sourceMappingURL=c80-tab.component.js.map
|
|
@@ -439,10 +439,10 @@ import * as i0 from "@angular/core";
|
|
|
439
439
|
return '#e9ecef';
|
|
440
440
|
}
|
|
441
441
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
442
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: TableComponent, isStandalone: true, selector: "c80-table", inputs: { data$: { classPropertyName: "data$", publicName: "data$", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, inputValues$: { classPropertyName: "inputValues$", publicName: "inputValues$", isSignal: true, isRequired: false, transformFunction: null }, customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allowSelection: { classPropertyName: "allowSelection", publicName: "allowSelection", isSignal: true, isRequired: false, transformFunction: null }, noConfirm: { classPropertyName: "noConfirm", publicName: "noConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", searchTerm: "searchTerm", errorEvent: "errorEvent", selectable: "selectable" }, ngImport: i0, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" color=\"dark\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" color=\"dark\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" color=\"dark\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }, { kind: "component", type: ModalComponent, selector: "c80-modal" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
442
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: TableComponent, isStandalone: true, selector: "c80-table", inputs: { data$: { classPropertyName: "data$", publicName: "data$", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, inputValues$: { classPropertyName: "inputValues$", publicName: "inputValues$", isSignal: true, isRequired: false, transformFunction: null }, customActions: { classPropertyName: "customActions", publicName: "customActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, allowSelection: { classPropertyName: "allowSelection", publicName: "allowSelection", isSignal: true, isRequired: false, transformFunction: null }, noConfirm: { classPropertyName: "noConfirm", publicName: "noConfirm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick", searchTerm: "searchTerm", errorEvent: "errorEvent", selectable: "selectable" }, ngImport: i0, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\"\n [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }, { kind: "component", type: ModalComponent, selector: "c80-modal" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
443
443
|
}
|
|
444
444
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: TableComponent, decorators: [{
|
|
445
445
|
type: Component,
|
|
446
|
-
args: [{ selector: 'c80-table', standalone: true, imports: [IconComponent, ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" color=\"dark\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" color=\"dark\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" color=\"dark\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}\n"] }]
|
|
446
|
+
args: [{ selector: 'c80-table', standalone: true, imports: [IconComponent, ModalComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar b\u00FAsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edici\u00F3n: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\"\n [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />", styles: ["@charset \"UTF-8\";input[type=checkbox]{width:1.3rem!important;height:1.3rem!important;accent-color:var(--color-icon-danger);background:var(--color-bg-primary);margin:0 .25rem;vertical-align:middle;cursor:pointer}.table-responsive{width:100%;overflow-x:auto}.table-responsive .search-container{margin-bottom:-.06rem}.table-responsive .search-container .search-input-wrapper .input-group .btn-borrar{border-bottom-right-radius:0;border-color:var(--color-border-default);height:32px}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text{background-color:var(--color-bg-secondary);border-color:var(--color-border-default);border-bottom-left-radius:0;color:var(--color-text-secondary);width:56.1px;height:32px;padding:.25rem .5rem}.table-responsive .search-container .search-input-wrapper .input-group .input-group-text c80-icon{display:flex;align-items:center;justify-content:center}.table-responsive .search-container .search-input-wrapper .input-group .search-input{border-color:var(--color-border-default);border-bottom-right-radius:0;font-size:.75rem;height:32px;padding:.25rem .5rem;outline:none!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .search-container .search-input-wrapper .input-group .search-input:focus{outline:none!important}.table-responsive .search-container .search-input-wrapper .input-group .search-input::placeholder{color:var(--color-text-muted);font-style:italic}.table-responsive .table{min-width:0px;margin-bottom:.5rem;background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .table.table-bordered,.table-responsive .table.table-bordered th,.table-responsive .table.table-bordered td{border-color:var(--color-border-default)}.table-responsive .table.table-hover tbody tr:hover{background-color:var(--color-bg-hover)!important;color:var(--color-text-primary)}.table-responsive .table.table-hover tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table .sticky-header{position:sticky;top:0;z-index:10;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .table-actions-header{display:table-cell;vertical-align:middle;padding:.2rem .6rem!important;background-color:var(--color-bg-secondary)!important}.table-responsive .table .sticky-header .actions-wrapper{display:flex;align-items:center;justify-content:center;gap:.5rem;height:100%}.table-responsive .table .sticky-header th{max-height:31px!important;vertical-align:middle!important;padding:.2rem .6rem!important;font-size:small!important;background-color:var(--color-bg-secondary)!important;border-bottom:2px solid var(--color-border-default);color:var(--color-text-primary)}.table-responsive .table tbody{background-color:var(--color-bg-primary)}.table-responsive .table tbody td{height:35px!important;min-height:35px!important;max-height:35px!important;vertical-align:middle!important;padding:.2rem .8rem!important;font-size:small;color:var(--color-text-primary);background-color:var(--color-bg-primary);border-color:var(--color-border-default)}.table-responsive .table tbody tr{height:35px!important;min-height:35px!important;max-height:35px!important;cursor:pointer;background-color:var(--color-bg-primary)}.table-responsive .table tbody tr:hover{background-color:var(--color-bg-hover)!important}.table-responsive .table tbody tr:hover td{background-color:var(--color-bg-hover)}.table-responsive .table tbody .text-muted{color:var(--color-text-muted)!important}.table-responsive .table tbody input,.table-responsive .table tbody select{border:1px solid var(--color-border-default);height:100%!important;font-size:smaller!important;background-color:var(--color-bg-primary);color:var(--color-text-primary)}.table-responsive .table tbody input:focus,.table-responsive .table tbody select:focus{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus)}.table-responsive .table tbody input::placeholder,.table-responsive .table tbody select::placeholder{color:var(--color-text-muted)}.table-responsive .table tbody input[type=text],.table-responsive .table tbody input:not([type]){width:100%!important}.table-responsive .table tbody input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table tbody select{width:100%!important;padding:.25rem .5rem}.table-responsive .table thead th.boolean-column,.table-responsive .table tbody td.boolean-column,.table-responsive .table thead th.selection-column,.table-responsive .table tbody td.selection-column,.table-responsive .table thead th.table-actions-header,.table-responsive .table tbody td.table-actions-header{width:1%;white-space:nowrap}.table-responsive .table thead th.number-column,.table-responsive .table tbody td.number-column{width:1%;white-space:nowrap;text-align:center}.table-responsive .table thead th.number-column input[type=number],.table-responsive .table tbody td.number-column input[type=number]{min-width:80px!important;width:80px!important;text-align:center}.table-responsive .table .actions-cell{white-space:nowrap;padding:0!important}.table-responsive .table .actions-container{display:flex;flex-direction:row;justify-content:center;align-items:center;width:100%;height:100%}.table-responsive .text-center.text-muted{color:var(--color-text-muted)!important}.table-responsive .btn-outline-secondary{background-color:var(--color-bg-primary);color:var(--color-text-primary);border-color:var(--color-border-default)}.table-responsive .btn-outline-secondary:hover{background-color:var(--color-bg-hover);border-color:var(--color-border-medium)}.table-responsive .btn-outline-secondary:focus{box-shadow:var(--shadow-focus)}\n"] }]
|
|
447
447
|
}], propDecorators: { data$: [{ type: i0.Input, args: [{ isSignal: true, alias: "data$", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], inputValues$: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputValues$", required: false }] }], customActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "customActions", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], allowSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowSelection", required: false }] }], noConfirm: [{ type: i0.Input, args: [{ isSignal: true, alias: "noConfirm", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }], searchTerm: [{ type: i0.Output, args: ["searchTerm"] }], errorEvent: [{ type: i0.Output, args: ["errorEvent"] }], selectable: [{ type: i0.Output, args: ["selectable"] }] } });
|
|
448
448
|
//# sourceMappingURL=table.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.component.ts","../../../../../libs/ui/src/lib/table/table.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n type OnInit,\n type OnDestroy,\n Component,\n ChangeDetectionStrategy,\n input,\n signal,\n computed,\n output,\n inject,\n} from '@angular/core';\nimport type { Observable, Subscription } from 'rxjs';\nimport { IconComponent } from '../icon';\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\nimport { TableDataConverterService } from './table-data-converter.service';\nimport { TableSelectionService } from './table-selection.service';\nimport { TableCrudStateService } from './table-crud-state.service';\nimport type { TableColDef, CustomTableAction } from './table.types';\nimport { ModalComponent, ModalService } from '../modal';\nimport {\n booleanAttribute,\n getErrorMessage,\n getInputValue,\n trackById,\n shouldShowAction,\n getActionTooltip,\n} from './table.utils';\n\n/**\n * C80TableComponent - Componente de tabla avanzado con funcionalidades CRUD\n *\n * COMPORTAMIENTO DE VISIBILIDAD DE COLUMNAS:\n * ========================================\n *\n * 1. PRIORIDAD MÁXIMA - visible: false\n * - La columna se oculta SIEMPRE, sin excepciones\n * - Ni en modo creación ni en modo edición se muestra\n *\n * 2. OCULTACIÓN AUTOMÁTICA - hideIfAllValuesAreNull: true\n * - La columna se oculta solo si TODOS los valores actuales están vacíos\n * - Valores considerados vacíos: null, undefined, '', [], {}\n * - Valores NO vacíos: 0, false (son valores válidos)\n * - EXCEPCIONES IMPORTANTES:\n * * En modo creación (creating=true) estas columnas SÍ se muestran\n * * En modo edición de una fila específica se muestran SOLO si esa fila tiene valor\n *\n * 3. POR DEFECTO - Columnas normales\n * - Se muestran siempre (visualización, creación y edición)\n *\n * VALORES POR DEFECTO EN CREACIÓN:\n * ===============================\n *\n * - Propiedad `default?: unknown` permite definir valores por defecto para modo creación\n * - Solo se aplica cuando se inicia el modo creación (startCreate)\n * - Puede ser cualquier tipo: string, number, boolean, etc.\n * - Si no se especifica `default`, se usa cadena vacía ('')\n *\n * VALORES DINÁMICOS EN CREACIÓN Y EDICIÓN:\n * =======================================\n *\n * - Input `inputValues$?: Observable<Partial<T>>` permite actualizar valores dinámicamente\n * - Solo se aplica durante modo creación (creating=true) o edición (editing!=null)\n * - Los valores se aplican automáticamente cuando el Observable emite\n * - Permite cambios múltiples durante el mismo modo de creación/edición\n * - Los nuevos valores sobrescriben los existentes (spread operator)\n *\n * TIPOS DE DATOS SOPORTADOS:\n * =========================\n *\n * - 'string': Texto normal (default)\n * - 'number': Números decimales (preserva decimales: 5.3 → 5.3)\n * - 'integer': Números enteros (convierte a entero: 5.3 → 5)\n * - 'boolean': Verdadero/Falso (checkbox)\n * - 'password': Texto oculto (input type=\"password\")\n * - 'enum': Lista de opciones predefinidas (select)\n *\n * SISTEMA DE ACCIONES UNIFICADO (customActions):\n * =============================================\n *\n * Input: `customActions: CustomTableAction[]` - Array de acciones dinámicas\n * Output: `(actionClick)` - Evento unificado que emite { action: string, row: T }\n *\n * ACCIONES CRUD PREDEFINIDAS (TABLE_CRUD_ACTIONS):\n * ------------------------------------------------\n * - CREATE: Solo aparece como botón \"+\" en header (no en filas)\n * - UPDATE: Activa modo edición (muestra inputs), botón \"✓\" guarda cambios\n * - DELETE: Muestra confirmación y emite evento delete\n * - CANCEL: Muestra confirmación y emite evento cancel (opcional)\n *\n * ACCIONES PERSONALIZADAS (Custom Actions):\n * -----------------------------------------\n * Interfaz: { name: string, icon: IconType, condition?: (row) => boolean, tooltip?: string }\n * - name: ID único de la acción\n * - icon: Icono del botón (ej: 'settings', 'upload', 'refresh')\n * - condition: Función opcional para mostrar/ocultar según estado de fila\n * - tooltip: Texto al hacer hover (default: name)\n *\n * MANEJO EN COMPONENTE:\n * --------------------\n * ```typescript\n * // 1. Definir acciones en constants:\n * export const ENTITY_TABLE_ACTIONS: CustomTableAction[] = [\n * TABLE_CRUD_ACTIONS.CREATE,\n * TABLE_CRUD_ACTIONS.UPDATE,\n * { name: 'custom-action', icon: 'settings', tooltip: 'Configurar' },\n * TABLE_CRUD_ACTIONS.DELETE\n * ];\n *\n * // 2. En el componente:\n * readonly tableActions = ENTITY_TABLE_ACTIONS;\n *\n * handleAction({ action, row }) {\n * const entity = row as unknown as EntityType;\n * switch (action) {\n * case 'create': this.onCreate(row); break;\n * case 'update': this.onUpdate(entity); break;\n * case 'delete': this.onDelete(entity.id); break;\n * case 'custom-action': this.onCustom(entity); break;\n * }\n * }\n * ```\n *\n * ACCIONES CON CONDICIÓN:\n * ----------------------\n * ```typescript\n * {\n * name: 'enable',\n * icon: 'toggleOn',\n * tooltip: 'Habilitar',\n * condition: (row) => row['enabled'] === false\n * }\n * ```\n *\n * CONSTANTES REUTILIZABLES:\n * ------------------------\n * - TABLE_CRUD_ACTIONS: Objeto con CREATE, UPDATE, DELETE, CANCEL\n * - BASIC_CRUD_ACTIONS: Array con [CREATE, UPDATE, DELETE]\n * Importar desde: `@shared` o `@shared/constants`\n *\n * EJEMPLOS COMPLETOS:\n * ------------------\n * - { accessor: 'id', visible: false } → NUNCA se muestra\n * - { accessor: 'motorPos', hideIfAllValuesAreNull: true, default: 0, type: 'integer' } → Entero (5.7 → 5)\n * - { accessor: 'weight', type: 'number', default: 2.5 } → Decimal preservado (5.7 → 5.7)\n * - { accessor: 'status', default: 'active' } → Se autorellena con 'active' en creación\n * - { accessor: 'name' } → Siempre visible, sin valor por defecto (cadena vacía)\n * - inputValues$ emite { motorPos: 5, weight: 2.3 } → actualiza inputs dinámicamente\n * - customActions con CREATE → Muestra botón \"+\" en header\n * - customActions con UPDATE → Botón \"edit\" activa modo edición\n * - customActions con custom → Botón personalizado emite evento\n */@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-table',\n standalone: true,\n imports: [IconComponent, ModalComponent],\n templateUrl: './table.component.html',\n styleUrl: './table.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\n // Servicios inyectados\n /* v8 ignore next 6 */\n private readonly modalService = inject(ModalService);\n private readonly visibilityService = inject(TableColumnVisibilityService);\n private readonly dataUtils = inject(TableDataUtilsService);\n private readonly dataConverter = inject(TableDataConverterService);\n private readonly selectionService = inject(TableSelectionService);\n private readonly crudService = inject(TableCrudStateService);\n\n // Inputs\n /* v8 ignore next */\n readonly data$ = input.required<Observable<T[]>>();\n /* v8 ignore next */\n readonly columns = input<TableColDef[]>([]);\n /* v8 ignore next */\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\n /* v8 ignore next */\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\n /* v8 ignore next */\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\n /* v8 ignore next */\n readonly multiple = input(true); // Permite selección múltiple por defecto\n /* v8 ignore next */\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\n /* v8 ignore next */\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\n /* v8 ignore next */\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\n\n // Outputs - Acciones unificadas (Angular 18+ output API)\n /* v8 ignore next */\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\n\n // Outputs - Utilidades\n /* v8 ignore next 3 */\n readonly searchTerm = output<string>();\n readonly errorEvent = output<string>();\n readonly selectable = output<T[]>();\n\n // Estado principal\n /* v8 ignore next 2 */\n readonly data = signal<T[]>([]);\n readonly searchValue = signal<string>('');\n\n // Estado de selección (delegado a servicio)\n /* v8 ignore next 4 */\n private readonly selectionState = this.selectionService.createSelectionState<T>();\n readonly selectedItems = this.selectionState.selectedItems;\n readonly selectAllChecked = this.selectionState.selectAllChecked;\n readonly selectAllIndeterminate = this.selectionState.selectAllIndeterminate;\n\n // Estado CRUD (delegado a servicio)\n /* v8 ignore next 5 */\n private readonly crudState = this.crudService.createCrudState<T>();\n readonly creating = this.crudState.creating;\n readonly newRow = this.crudState.newRow;\n readonly editing = this.crudState.editing;\n readonly editRow = this.crudState.editRow;\n\n // Keys visibles computed automáticamente\n /* v8 ignore next 7 */\n readonly keys = computed(() =>\n this.visibilityService.updateVisibleKeys(\n this.columns(),\n this.data(),\n this.creating(),\n this.editing()\n )\n );\n\n // Computed - Detecta acciones CRUD y custom\n /* v8 ignore next 5 */\n readonly hasAnyActions = computed(() => this.customActions().length > 0);\n readonly hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'));\n readonly hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'));\n readonly hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'));\n readonly hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'));\n\n // Table max height computed\n /* v8 ignore next 3 */\n readonly tableMaxHeight = computed(() =>\n this.dataUtils.getTableMaxHeight(this.size())\n );\n\n /* v8 ignore next 2 */\n private dataSub?: Subscription;\n private inputValuesSub?: Subscription;\n\n /**\n * Maneja input de creación/edición de forma unificada\n */\n private handleInput(\n event: Event,\n key: string,\n col: TableColDef | undefined,\n isEdit: boolean\n ): void {\n const updateFn = isEdit\n ? this.crudState.updateEditRow.bind(this.crudState)\n : this.crudState.updateNewRow.bind(this.crudState);\n\n const value = getInputValue(event, col);\n if (value !== undefined) {\n updateFn(key, value);\n }\n }\n\n /**\n * Maneja confirmación modal de forma genérica\n */\n private async handleConfirmAction(\n title: string,\n message: string,\n confirmText: string,\n action: () => void\n ): Promise<void> {\n if (this.noConfirm()) {\n action();\n return;\n }\n\n const confirmed = await this.modalService.confirm(\n title,\n message,\n confirmText,\n 'Cancelar'\n );\n\n if (confirmed) {\n action();\n }\n }\n\n\n\n ngOnInit() {\n const data$ = this.data$();\n if (!data$) return;\n this.dataSub = data$.subscribe({\n next: (items) => {\n this.dataUtils.applySorting(items, this.columns());\n this.data.set(items);\n this.preserveSelection();\n },\n error: (err: unknown) =>\n this.errorEvent.emit(getErrorMessage(err)),\n });\n\n // Suscribirse a inputValues$ para actualizar valores dinámicamente en creación/edición\n const inputValues$ = this.inputValues$();\n if (inputValues$) {\n this.inputValuesSub = inputValues$.subscribe({\n next: (partialValues) => {\n this.crudState.applyInputValues(partialValues);\n },\n error: (err: unknown) =>\n console.warn('Error en inputValues$:', getErrorMessage(err)),\n });\n }\n }\n\n ngOnDestroy() {\n this.dataSub?.unsubscribe();\n this.inputValuesSub?.unsubscribe();\n\n // Close any open modal when component is destroyed\n this.modalService.closeModal();\n }\n\n onInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput(event, key, col, false);\n }\n\n onEditInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput(event, key, col, true);\n }\n\n async onDelete(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar eliminación',\n '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\n 'Eliminar',\n () => this.actionClick.emit({ action: 'delete', row })\n );\n }\n\n async onCancel(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar cancelación',\n '¿Está seguro de que desea cancelar este elemento?',\n 'Cancelar elemento',\n () => this.actionClick.emit({ action: 'cancel', row })\n );\n }\n\n startCreate(): void {\n this.crudState.startCreate(this.columns(), this.data());\n }\n\n cancelCreate(): void {\n this.crudState.cancelCreate();\n }\n\n saveCreate(): void {\n const current = this.newRow();\n if (current) {\n const convertedRow = this.convertRowTypes(current);\n this.actionClick.emit({ action: 'create', row: convertedRow as T });\n this.cancelCreate();\n }\n }\n\n onEdit(row: T): void {\n this.crudState.startEdit(row, this.columns(), this.data());\n }\n\n cancelEdit(): void {\n this.crudState.cancelEdit();\n }\n\n saveEdit(row: T): void {\n const changes = this.editRow();\n if (changes) {\n const convertedChanges = this.convertRowTypes(changes);\n const updatedRow = { ...row, ...convertedChanges } as T;\n this.actionClick.emit({ action: 'update', row: updatedRow });\n this.cancelEdit();\n }\n }\n\n /**\n * Convierte todos los valores de una fila según los tipos definidos en las columnas\n * Asegura que los datos emitidos tengan el tipo correcto (integer, number, boolean, etc.)\n */\n private convertRowTypes(row: Partial<T>): Partial<T> {\n const converted: Record<string, unknown> = {};\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\n\n for (const [key, value] of Object.entries(row)) {\n const col = columnsMap.get(key);\n if (col) {\n converted[key] = this.dataConverter.convertCellValue(value, col);\n } else {\n converted[key] = value;\n }\n }\n\n return converted as Partial<T>;\n }\n\n /**\n * TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).\n */\n readonly trackById = trackById<T>;\n\n /**\n * Verifica si una acción personalizada debe mostrarse para una fila específica\n */\n readonly shouldShowAction = shouldShowAction<T>;\n\n /**\n * Obtiene el tooltip de una acción\n */\n readonly getActionTooltip = getActionTooltip;\n\n /**\n * Maneja el click en una acción personalizada dinámica\n * UPDATE activa el modo edición, otras acciones emiten directamente\n * Si la acción tiene configuración de confirmación, muestra modal antes de ejecutar\n */\n onDynamicAction(action: CustomTableAction, row: T): void {\n if (action.name === 'update') {\n this.onEdit(row);\n return;\n }\n\n if (action.name === 'delete') {\n void this.onDelete(row);\n return;\n }\n\n if (action.name === 'cancel') {\n void this.onCancel(row);\n return;\n }\n\n // Si la acción tiene confirmación configurada, mostrar modal\n if (action.confirmation) {\n void this.handleActionWithConfirmation(action, row);\n return;\n }\n\n // Sin confirmación, emitir directamente\n this.actionClick.emit({ action: action.name, row });\n }\n\n /**\n * Maneja acciones que requieren confirmación del usuario\n */\n private async handleActionWithConfirmation(action: CustomTableAction, row: T): Promise<void> {\n if (!action.confirmation) return;\n\n const confirmed = await this.modalService.confirm(\n action.confirmation.title,\n action.confirmation.message,\n action.confirmation.confirmText ?? 'Confirmar',\n action.confirmation.cancelText ?? 'Cancelar'\n );\n\n if (confirmed) {\n this.actionClick.emit({ action: action.name, row });\n }\n }\n\n /**\n * Handles search input changes with debouncing\n */\n onSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n const value = target.value;\n this.searchValue.set(value);\n this.searchTerm.emit(value);\n }\n\n /**\n * Clears the search input\n */\n clearSearch(): void {\n this.searchValue.set('');\n this.searchTerm.emit('');\n }\n\n // Referencias readonly a métodos de servicios (evita wrappers innecesarios)\n readonly getCellValue = this.dataUtils.getCellValue.bind(this.dataUtils);\n readonly getDisplayValue = this.dataUtils.getDisplayValue.bind(this.dataUtils);\n readonly getEnumDisplayValue = this.dataUtils.getEnumDisplayValue.bind(this.dataUtils);\n readonly getEnumOptions = this.dataUtils.getEnumOptions.bind(this.dataUtils);\n readonly getCellColor = this.dataUtils.getCellColor.bind(this.dataUtils);\n\n /**\n * Selection methods\n */\n clearSelection(): void {\n this.selectionState.clearSelection();\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n /**\n * Mantiene la selección existente después de actualizar los datos,\n * eliminando solo los IDs que ya no existen en los nuevos datos\n */\n private preserveSelection(): void {\n this.selectionState.preserveSelection(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleSelectAll(): void {\n this.selectionState.toggleSelectAll(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleItemSelection(item: T): void {\n this.selectionState.toggleItemSelection(item, this.multiple());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n isItemSelected(item: T): boolean {\n return this.selectionState.isItemSelected(item);\n }\n\n\n\n // Métodos de visibilidad delegados a servicio\n isColumnVisible(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisible(column, this.data(), {\n creating: this.creating(),\n row: this.newRow() ?? undefined\n });\n }\n\n isColumnVisibleInHeader(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisibleInHeader(\n column,\n this.data(),\n this.creating(),\n this.editing()\n );\n }\n\n isColumnVisibleForRow(column: TableColDef, row: T): boolean {\n return this.visibilityService.isColumnVisibleForRow(\n column,\n row,\n this.data(),\n this.editing()\n );\n }\n\n /**\n * Obtiene el color de una acción considerando el tema actual.\n * Si la acción tiene color explícito, lo usa. Si no, aplica color por tema.\n */\n getActionColor(action: CustomTableAction): string | undefined {\n // Delete siempre en rojo (color warn de Material)\n if (action.name === 'delete') {\n return undefined; // Deja que el atributo [color]=\"warn\" lo maneje\n }\n\n // Si la acción tiene color explícito (rojo/verde para toggles), respetarlo\n if (action.color) {\n return action.color;\n }\n\n // Para acciones sin color explícito, usar el color de dark mode\n return '#e9ecef';\n }\n}\n","<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" color=\"dark\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar búsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" color=\"dark\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" color=\"dark\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" color=\"dark\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" color=\"dark\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edición: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\" [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" color=\"dark\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />"]}
|
|
1
|
+
{"version":3,"file":"table.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/table/table.component.ts","../../../../../libs/ui/src/lib/table/table.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n type OnInit,\n type OnDestroy,\n Component,\n ChangeDetectionStrategy,\n input,\n signal,\n computed,\n output,\n inject,\n} from '@angular/core';\nimport type { Observable, Subscription } from 'rxjs';\nimport { IconComponent } from '../icon';\nimport { TableColumnVisibilityService } from './table-column-visibility.service';\nimport { TableDataUtilsService } from './table-data-utils.service';\nimport { TableDataConverterService } from './table-data-converter.service';\nimport { TableSelectionService } from './table-selection.service';\nimport { TableCrudStateService } from './table-crud-state.service';\nimport type { TableColDef, CustomTableAction } from './table.types';\nimport { ModalComponent, ModalService } from '../modal';\nimport {\n booleanAttribute,\n getErrorMessage,\n getInputValue,\n trackById,\n shouldShowAction,\n getActionTooltip,\n} from './table.utils';\n\n/**\n * C80TableComponent - Componente de tabla avanzado con funcionalidades CRUD\n *\n * COMPORTAMIENTO DE VISIBILIDAD DE COLUMNAS:\n * ========================================\n *\n * 1. PRIORIDAD MÁXIMA - visible: false\n * - La columna se oculta SIEMPRE, sin excepciones\n * - Ni en modo creación ni en modo edición se muestra\n *\n * 2. OCULTACIÓN AUTOMÁTICA - hideIfAllValuesAreNull: true\n * - La columna se oculta solo si TODOS los valores actuales están vacíos\n * - Valores considerados vacíos: null, undefined, '', [], {}\n * - Valores NO vacíos: 0, false (son valores válidos)\n * - EXCEPCIONES IMPORTANTES:\n * * En modo creación (creating=true) estas columnas SÍ se muestran\n * * En modo edición de una fila específica se muestran SOLO si esa fila tiene valor\n *\n * 3. POR DEFECTO - Columnas normales\n * - Se muestran siempre (visualización, creación y edición)\n *\n * VALORES POR DEFECTO EN CREACIÓN:\n * ===============================\n *\n * - Propiedad `default?: unknown` permite definir valores por defecto para modo creación\n * - Solo se aplica cuando se inicia el modo creación (startCreate)\n * - Puede ser cualquier tipo: string, number, boolean, etc.\n * - Si no se especifica `default`, se usa cadena vacía ('')\n *\n * VALORES DINÁMICOS EN CREACIÓN Y EDICIÓN:\n * =======================================\n *\n * - Input `inputValues$?: Observable<Partial<T>>` permite actualizar valores dinámicamente\n * - Solo se aplica durante modo creación (creating=true) o edición (editing!=null)\n * - Los valores se aplican automáticamente cuando el Observable emite\n * - Permite cambios múltiples durante el mismo modo de creación/edición\n * - Los nuevos valores sobrescriben los existentes (spread operator)\n *\n * TIPOS DE DATOS SOPORTADOS:\n * =========================\n *\n * - 'string': Texto normal (default)\n * - 'number': Números decimales (preserva decimales: 5.3 → 5.3)\n * - 'integer': Números enteros (convierte a entero: 5.3 → 5)\n * - 'boolean': Verdadero/Falso (checkbox)\n * - 'password': Texto oculto (input type=\"password\")\n * - 'enum': Lista de opciones predefinidas (select)\n *\n * SISTEMA DE ACCIONES UNIFICADO (customActions):\n * =============================================\n *\n * Input: `customActions: CustomTableAction[]` - Array de acciones dinámicas\n * Output: `(actionClick)` - Evento unificado que emite { action: string, row: T }\n *\n * ACCIONES CRUD PREDEFINIDAS (TABLE_CRUD_ACTIONS):\n * ------------------------------------------------\n * - CREATE: Solo aparece como botón \"+\" en header (no en filas)\n * - UPDATE: Activa modo edición (muestra inputs), botón \"✓\" guarda cambios\n * - DELETE: Muestra confirmación y emite evento delete\n * - CANCEL: Muestra confirmación y emite evento cancel (opcional)\n *\n * ACCIONES PERSONALIZADAS (Custom Actions):\n * -----------------------------------------\n * Interfaz: { name: string, icon: IconType, condition?: (row) => boolean, tooltip?: string }\n * - name: ID único de la acción\n * - icon: Icono del botón (ej: 'settings', 'upload', 'refresh')\n * - condition: Función opcional para mostrar/ocultar según estado de fila\n * - tooltip: Texto al hacer hover (default: name)\n *\n * MANEJO EN COMPONENTE:\n * --------------------\n * ```typescript\n * // 1. Definir acciones en constants:\n * export const ENTITY_TABLE_ACTIONS: CustomTableAction[] = [\n * TABLE_CRUD_ACTIONS.CREATE,\n * TABLE_CRUD_ACTIONS.UPDATE,\n * { name: 'custom-action', icon: 'settings', tooltip: 'Configurar' },\n * TABLE_CRUD_ACTIONS.DELETE\n * ];\n *\n * // 2. En el componente:\n * readonly tableActions = ENTITY_TABLE_ACTIONS;\n *\n * handleAction({ action, row }) {\n * const entity = row as unknown as EntityType;\n * switch (action) {\n * case 'create': this.onCreate(row); break;\n * case 'update': this.onUpdate(entity); break;\n * case 'delete': this.onDelete(entity.id); break;\n * case 'custom-action': this.onCustom(entity); break;\n * }\n * }\n * ```\n *\n * ACCIONES CON CONDICIÓN:\n * ----------------------\n * ```typescript\n * {\n * name: 'enable',\n * icon: 'toggleOn',\n * tooltip: 'Habilitar',\n * condition: (row) => row['enabled'] === false\n * }\n * ```\n *\n * CONSTANTES REUTILIZABLES:\n * ------------------------\n * - TABLE_CRUD_ACTIONS: Objeto con CREATE, UPDATE, DELETE, CANCEL\n * - BASIC_CRUD_ACTIONS: Array con [CREATE, UPDATE, DELETE]\n * Importar desde: `@shared` o `@shared/constants`\n *\n * EJEMPLOS COMPLETOS:\n * ------------------\n * - { accessor: 'id', visible: false } → NUNCA se muestra\n * - { accessor: 'motorPos', hideIfAllValuesAreNull: true, default: 0, type: 'integer' } → Entero (5.7 → 5)\n * - { accessor: 'weight', type: 'number', default: 2.5 } → Decimal preservado (5.7 → 5.7)\n * - { accessor: 'status', default: 'active' } → Se autorellena con 'active' en creación\n * - { accessor: 'name' } → Siempre visible, sin valor por defecto (cadena vacía)\n * - inputValues$ emite { motorPos: 5, weight: 2.3 } → actualiza inputs dinámicamente\n * - customActions con CREATE → Muestra botón \"+\" en header\n * - customActions con UPDATE → Botón \"edit\" activa modo edición\n * - customActions con custom → Botón personalizado emite evento\n */@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-table',\n standalone: true,\n imports: [IconComponent, ModalComponent],\n templateUrl: './table.component.html',\n styleUrl: './table.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TableComponent<T extends Record<string, unknown>> implements OnInit, OnDestroy {\n // Servicios inyectados\n /* v8 ignore next 6 */\n private readonly modalService = inject(ModalService);\n private readonly visibilityService = inject(TableColumnVisibilityService);\n private readonly dataUtils = inject(TableDataUtilsService);\n private readonly dataConverter = inject(TableDataConverterService);\n private readonly selectionService = inject(TableSelectionService);\n private readonly crudService = inject(TableCrudStateService);\n\n // Inputs\n /* v8 ignore next */\n readonly data$ = input.required<Observable<T[]>>();\n /* v8 ignore next */\n readonly columns = input<TableColDef[]>([]);\n /* v8 ignore next */\n readonly inputValues$ = input<Observable<Partial<T>>>(); // Observable para actualizar valores de inputs dinámicamente en creación/edición\n /* v8 ignore next */\n readonly customActions = input<CustomTableAction[]>([]); // Acciones personalizadas dinámicas\n /* v8 ignore next */\n readonly size = input(0); // Tamaño de la tabla (0 = sin límite, > 0 aplica max-height)\n /* v8 ignore next */\n readonly multiple = input(true); // Permite selección múltiple por defecto\n /* v8 ignore next */\n readonly searchable = input(false, { transform: booleanAttribute }); // Si es true, muestra barra de búsqueda\n /* v8 ignore next */\n readonly allowSelection = input(false, { transform: booleanAttribute }); // Si es true, permite selección de filas\n /* v8 ignore next */\n readonly noConfirm = input(false, { transform: booleanAttribute }); // Si es true, no muestra confirmaciones modales\n\n // Outputs - Acciones unificadas (Angular 18+ output API)\n /* v8 ignore next */\n readonly actionClick = output<{ action: string; row: T }>(); // Output unificado para TODAS las acciones (CRUD + custom)\n\n // Outputs - Utilidades\n /* v8 ignore next 3 */\n readonly searchTerm = output<string>();\n readonly errorEvent = output<string>();\n readonly selectable = output<T[]>();\n\n // Estado principal\n /* v8 ignore next 2 */\n readonly data = signal<T[]>([]);\n readonly searchValue = signal<string>('');\n\n // Estado de selección (delegado a servicio)\n /* v8 ignore next 4 */\n private readonly selectionState = this.selectionService.createSelectionState<T>();\n readonly selectedItems = this.selectionState.selectedItems;\n readonly selectAllChecked = this.selectionState.selectAllChecked;\n readonly selectAllIndeterminate = this.selectionState.selectAllIndeterminate;\n\n // Estado CRUD (delegado a servicio)\n /* v8 ignore next 5 */\n private readonly crudState = this.crudService.createCrudState<T>();\n readonly creating = this.crudState.creating;\n readonly newRow = this.crudState.newRow;\n readonly editing = this.crudState.editing;\n readonly editRow = this.crudState.editRow;\n\n // Keys visibles computed automáticamente\n /* v8 ignore next 7 */\n readonly keys = computed(() =>\n this.visibilityService.updateVisibleKeys(\n this.columns(),\n this.data(),\n this.creating(),\n this.editing()\n )\n );\n\n // Computed - Detecta acciones CRUD y custom\n /* v8 ignore next 5 */\n readonly hasAnyActions = computed(() => this.customActions().length > 0);\n readonly hasCrudCreate = computed(() => this.customActions().some(a => a.name === 'create'));\n readonly hasCrudUpdate = computed(() => this.customActions().some(a => a.name === 'update'));\n readonly hasCrudDelete = computed(() => this.customActions().some(a => a.name === 'delete'));\n readonly hasCrudCancel = computed(() => this.customActions().some(a => a.name === 'cancel'));\n\n // Table max height computed\n /* v8 ignore next 3 */\n readonly tableMaxHeight = computed(() =>\n this.dataUtils.getTableMaxHeight(this.size())\n );\n\n /* v8 ignore next 2 */\n private dataSub?: Subscription;\n private inputValuesSub?: Subscription;\n\n /**\n * Maneja input de creación/edición de forma unificada\n */\n private handleInput(\n event: Event,\n key: string,\n col: TableColDef | undefined,\n isEdit: boolean\n ): void {\n const updateFn = isEdit\n ? this.crudState.updateEditRow.bind(this.crudState)\n : this.crudState.updateNewRow.bind(this.crudState);\n\n const value = getInputValue(event, col);\n if (value !== undefined) {\n updateFn(key, value);\n }\n }\n\n /**\n * Maneja confirmación modal de forma genérica\n */\n private async handleConfirmAction(\n title: string,\n message: string,\n confirmText: string,\n action: () => void\n ): Promise<void> {\n if (this.noConfirm()) {\n action();\n return;\n }\n\n const confirmed = await this.modalService.confirm(\n title,\n message,\n confirmText,\n 'Cancelar'\n );\n\n if (confirmed) {\n action();\n }\n }\n\n\n\n ngOnInit() {\n const data$ = this.data$();\n if (!data$) return;\n this.dataSub = data$.subscribe({\n next: (items) => {\n this.dataUtils.applySorting(items, this.columns());\n this.data.set(items);\n this.preserveSelection();\n },\n error: (err: unknown) =>\n this.errorEvent.emit(getErrorMessage(err)),\n });\n\n // Suscribirse a inputValues$ para actualizar valores dinámicamente en creación/edición\n const inputValues$ = this.inputValues$();\n if (inputValues$) {\n this.inputValuesSub = inputValues$.subscribe({\n next: (partialValues) => {\n this.crudState.applyInputValues(partialValues);\n },\n error: (err: unknown) =>\n console.warn('Error en inputValues$:', getErrorMessage(err)),\n });\n }\n }\n\n ngOnDestroy() {\n this.dataSub?.unsubscribe();\n this.inputValuesSub?.unsubscribe();\n\n // Close any open modal when component is destroyed\n this.modalService.closeModal();\n }\n\n onInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput(event, key, col, false);\n }\n\n onEditInput(event: Event, key: string, col?: TableColDef): void {\n this.handleInput(event, key, col, true);\n }\n\n async onDelete(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar eliminación',\n '¿Está seguro de que desea eliminar este elemento? Esta acción no se puede deshacer.',\n 'Eliminar',\n () => this.actionClick.emit({ action: 'delete', row })\n );\n }\n\n async onCancel(row: T): Promise<void> {\n await this.handleConfirmAction(\n 'Confirmar cancelación',\n '¿Está seguro de que desea cancelar este elemento?',\n 'Cancelar elemento',\n () => this.actionClick.emit({ action: 'cancel', row })\n );\n }\n\n startCreate(): void {\n this.crudState.startCreate(this.columns(), this.data());\n }\n\n cancelCreate(): void {\n this.crudState.cancelCreate();\n }\n\n saveCreate(): void {\n const current = this.newRow();\n if (current) {\n const convertedRow = this.convertRowTypes(current);\n this.actionClick.emit({ action: 'create', row: convertedRow as T });\n this.cancelCreate();\n }\n }\n\n onEdit(row: T): void {\n this.crudState.startEdit(row, this.columns(), this.data());\n }\n\n cancelEdit(): void {\n this.crudState.cancelEdit();\n }\n\n saveEdit(row: T): void {\n const changes = this.editRow();\n if (changes) {\n const convertedChanges = this.convertRowTypes(changes);\n const updatedRow = { ...row, ...convertedChanges } as T;\n this.actionClick.emit({ action: 'update', row: updatedRow });\n this.cancelEdit();\n }\n }\n\n /**\n * Convierte todos los valores de una fila según los tipos definidos en las columnas\n * Asegura que los datos emitidos tengan el tipo correcto (integer, number, boolean, etc.)\n */\n private convertRowTypes(row: Partial<T>): Partial<T> {\n const converted: Record<string, unknown> = {};\n const columnsMap = new Map(this.columns().map(col => [col.accessor, col]));\n\n for (const [key, value] of Object.entries(row)) {\n const col = columnsMap.get(key);\n if (col) {\n converted[key] = this.dataConverter.convertCellValue(value, col);\n } else {\n converted[key] = value;\n }\n }\n\n return converted as Partial<T>;\n }\n\n /**\n * TrackBy function for ngFor to avoid DOM re-creation (NG0956 warning).\n */\n readonly trackById = trackById<T>;\n\n /**\n * Verifica si una acción personalizada debe mostrarse para una fila específica\n */\n readonly shouldShowAction = shouldShowAction<T>;\n\n /**\n * Obtiene el tooltip de una acción\n */\n readonly getActionTooltip = getActionTooltip;\n\n /**\n * Maneja el click en una acción personalizada dinámica\n * UPDATE activa el modo edición, otras acciones emiten directamente\n * Si la acción tiene configuración de confirmación, muestra modal antes de ejecutar\n */\n onDynamicAction(action: CustomTableAction, row: T): void {\n if (action.name === 'update') {\n this.onEdit(row);\n return;\n }\n\n if (action.name === 'delete') {\n void this.onDelete(row);\n return;\n }\n\n if (action.name === 'cancel') {\n void this.onCancel(row);\n return;\n }\n\n // Si la acción tiene confirmación configurada, mostrar modal\n if (action.confirmation) {\n void this.handleActionWithConfirmation(action, row);\n return;\n }\n\n // Sin confirmación, emitir directamente\n this.actionClick.emit({ action: action.name, row });\n }\n\n /**\n * Maneja acciones que requieren confirmación del usuario\n */\n private async handleActionWithConfirmation(action: CustomTableAction, row: T): Promise<void> {\n if (!action.confirmation) return;\n\n const confirmed = await this.modalService.confirm(\n action.confirmation.title,\n action.confirmation.message,\n action.confirmation.confirmText ?? 'Confirmar',\n action.confirmation.cancelText ?? 'Cancelar'\n );\n\n if (confirmed) {\n this.actionClick.emit({ action: action.name, row });\n }\n }\n\n /**\n * Handles search input changes with debouncing\n */\n onSearchInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n const value = target.value;\n this.searchValue.set(value);\n this.searchTerm.emit(value);\n }\n\n /**\n * Clears the search input\n */\n clearSearch(): void {\n this.searchValue.set('');\n this.searchTerm.emit('');\n }\n\n // Referencias readonly a métodos de servicios (evita wrappers innecesarios)\n readonly getCellValue = this.dataUtils.getCellValue.bind(this.dataUtils);\n readonly getDisplayValue = this.dataUtils.getDisplayValue.bind(this.dataUtils);\n readonly getEnumDisplayValue = this.dataUtils.getEnumDisplayValue.bind(this.dataUtils);\n readonly getEnumOptions = this.dataUtils.getEnumOptions.bind(this.dataUtils);\n readonly getCellColor = this.dataUtils.getCellColor.bind(this.dataUtils);\n\n /**\n * Selection methods\n */\n clearSelection(): void {\n this.selectionState.clearSelection();\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n /**\n * Mantiene la selección existente después de actualizar los datos,\n * eliminando solo los IDs que ya no existen en los nuevos datos\n */\n private preserveSelection(): void {\n this.selectionState.preserveSelection(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleSelectAll(): void {\n this.selectionState.toggleSelectAll(this.data());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n toggleItemSelection(item: T): void {\n this.selectionState.toggleItemSelection(item, this.multiple());\n this.selectionService.emitSelection(this.selectionState as never, this.data(), this.selectable);\n }\n\n isItemSelected(item: T): boolean {\n return this.selectionState.isItemSelected(item);\n }\n\n\n\n // Métodos de visibilidad delegados a servicio\n isColumnVisible(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisible(column, this.data(), {\n creating: this.creating(),\n row: this.newRow() ?? undefined\n });\n }\n\n isColumnVisibleInHeader(column: TableColDef): boolean {\n return this.visibilityService.isColumnVisibleInHeader(\n column,\n this.data(),\n this.creating(),\n this.editing()\n );\n }\n\n isColumnVisibleForRow(column: TableColDef, row: T): boolean {\n return this.visibilityService.isColumnVisibleForRow(\n column,\n row,\n this.data(),\n this.editing()\n );\n }\n\n /**\n * Obtiene el color de una acción considerando el tema actual.\n * Si la acción tiene color explícito, lo usa. Si no, aplica color por tema.\n */\n getActionColor(action: CustomTableAction): string | undefined {\n // Delete siempre en rojo (color warn de Material)\n if (action.name === 'delete') {\n return undefined; // Deja que el atributo [color]=\"warn\" lo maneje\n }\n\n // Si la acción tiene color explícito (rojo/verde para toggles), respetarlo\n if (action.color) {\n return action.color;\n }\n\n // Para acciones sin color explícito, usar el color de dark mode\n return '#e9ecef';\n }\n}\n","<!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n<div class=\"table-responsive\" [style.max-height]=\"tableMaxHeight()\" [style.overflow-y]=\"size() > 0 ? 'auto' : 'visible'\">\n <!-- Search Bar -->\n @if (searchable()) {\n <div class=\"search-container\">\n <div class=\"search-input-wrapper\">\n <div class=\"input-group\">\n <span class=\"input-group-text\">\n <c80-icon icon=\"search\" [size]=\".65\" [button]=\"false\" />\n </span>\n <input type=\"text\" class=\"form-control search-input\" placeholder=\"Buscar...\" [value]=\"searchValue()\" (input)=\"onSearchInput($event)\" aria-label=\"Buscar en la tabla\" />\n @if (searchValue()) {\n <button class=\"btn btn-outline-secondary btn-borrar\" type=\"button\" (click)=\"clearSearch()\" title=\"Limpiar búsqueda\">\n <c80-icon icon=\"cancel\" [size]=\".6\" />\n </button>\n }\n </div>\n </div>\n </div>\n }\n\n <table class=\"table table-bordered table-hover align-middle\">\n <thead class=\"thead table-light sticky-header\">\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <th class=\"text-center selection-column\">\n @if (multiple()) {\n <input type=\"checkbox\" [checked]=\"selectAllChecked()\" [indeterminate]=\"selectAllIndeterminate()\" (change)=\"toggleSelectAll()\" aria-label=\"Seleccionar todo\" />\n }\n </th>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleInHeader(col)) {\n @if (col.type === 'boolean') {\n <th class=\"text-center boolean-column\">{{ col.label }}</th>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <th class=\"text-center number-column\">{{ col.label }}</th>\n }\n @else {\n <th>{{ col.label }}</th>\n }\n }\n }\n @if (hasAnyActions()) {\n <th class=\"table-actions-header\">\n <div class=\"actions-wrapper\">\n <span>Actions</span>\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"add\" [disabled]=\"creating()\" title=\"Agregar\" [size]=\".6\" (iconClick)=\"startCreate()\" />\n }\n </div>\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of data(); track trackById(i, row); let i = $index) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <input type=\"checkbox\" [checked]=\"isItemSelected(row)\" (change)=\"toggleItemSelection(row)\" [attr.aria-label]=\"'Seleccionar fila ' + (i + 1)\" />\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisibleForRow(col, row)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center boolean-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!editRow()?.[col.accessor]\" (change)=\"onEditInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n @if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n <br />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n <br />\n }\n }\n </td>\n }\n @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (editing() === row['id'] && !col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n </td>\n }\n @else {\n <td>\n @if (editing() === row['id'] && !col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"editRow()?.[col.accessor] ?? ''\" (change)=\"onEditInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" [type]=\"col.type === 'password' ? 'password' : 'text'\" [value]=\"editRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onEditInput($event, col.accessor, col)\" />\n }\n }\n @else {\n @if (col.type === 'password') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">******</span>\n }\n @else if (col.type === 'enum') {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{\n getEnumDisplayValue(getCellValue(row, col.accessor), col)\n }}</span>\n }\n @else if (getCellValue(row, col.accessor) === true) {\n <c80-icon icon=\"check\" [size]=\".7\" />\n }\n @else if (getCellValue(row, col.accessor) === false) {\n <c80-icon icon=\"cancel\" [size]=\".7\" />\n }\n @else {\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span [style.color]=\"getCellColor(getCellValue(row, col.accessor), col)\">{{ getDisplayValue(getCellValue(row,\n col.accessor), col) }}</span>\n }\n }\n </td>\n }\n }\n }\n @if (hasAnyActions()) {\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (editing() === row['id']) {\n <!-- Modo edición: mostrar guardar y cancelar -->\n @if (hasCrudUpdate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveEdit(row)\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelEdit()\" [size]=\".7\" />\n }\n @else {\n @for (action of customActions(); track action.name) {\n @if (shouldShowAction(action, row)) {\n <c80-icon button [icon]=\"action.icon\" [customColor]=\"getActionColor(action)\" [color]=\"action.name === 'delete' ? 'warn' : 'primary'\" [title]=\"getActionTooltip(action)\" (iconClick)=\"onDynamicAction(action, row)\"\n [size]=\".7\" />\n }\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n @if (creating() && hasCrudCreate()) {\n <tr>\n @if (allowSelection() && data().length !== 0) {\n <td class=\"text-center selection-column\">\n <!-- Empty cell for alignment -->\n </td>\n }\n @for (col of columns(); track col) {\n @if (isColumnVisible(col)) {\n @if (col.type === 'boolean') {\n <td class=\"text-center\">\n @if (!col.readOnly) {\n <input type=\"checkbox\" [checked]=\"!!newRow()?.[col.accessor]\" (change)=\"onInput($event, col.accessor, col)\" [attr.aria-label]=\"col.label\" />\n }\n @else {\n <!-- ReadOnly boolean column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else if (col.type === 'number' || col.type === 'integer') {\n <td class=\"text-center number-column\">\n @if (!col.readOnly) {\n <input class=\"form-control form-control-sm\" type=\"number\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" [min]=\"col.min\" [max]=\"col.max\" [step]=\"col.type === 'integer' ? '1' : 'any'\"\n (input)=\"onInput($event, col.accessor, col)\" />\n }\n @else {\n <!-- ReadOnly number column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n } @else {\n <td>\n @if (!col.readOnly) {\n @if (col.type === 'enum') {\n <select class=\"form-control form-control-sm\" [value]=\"newRow()?.[col.accessor] ?? ''\" (change)=\"onInput($event, col.accessor, col)\">\n <option value=\"\">{{ col.label }}</option>\n @for (option of getEnumOptions(col); track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n }\n @else {\n <input class=\"form-control form-control-sm\" type=\"text\" [value]=\"newRow()?.[col.accessor] ?? ''\" [placeholder]=\"col.label\" (input)=\"onInput($event, col.accessor, col)\" />\n }\n }\n @else {\n <!-- ReadOnly column in create mode shows empty -->\n <span class=\"text-muted\">-</span>\n }\n </td>\n }\n }\n }\n <td class=\"text-center actions-cell\">\n <div class=\"actions-container\">\n @if (hasCrudCreate()) {\n <c80-icon button icon=\"check\" title=\"Guardar\" (iconClick)=\"saveCreate()\" [size]=\".7\" />\n }\n <c80-icon button icon=\"cancel\" color=\"warn\" title=\"Cancelar\" (iconClick)=\"cancelCreate()\" [size]=\".7\" />\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n @if (data().length === 0 && !creating()) {\n <div class=\"text-center text-muted py-3 small\">\n No hay datos para mostrar.\n </div>\n }\n</div>\n\n<c80-modal />"]}
|
|
@@ -7,7 +7,7 @@ export declare class CardLevelComponent {
|
|
|
7
7
|
readonly cardWidth: import("@angular/core").Signal<string>;
|
|
8
8
|
isBidirectional: import("@angular/core").Signal<boolean>;
|
|
9
9
|
bidirectionalFillPercent: import("@angular/core").Signal<number>;
|
|
10
|
-
fillDirection: import("@angular/core").Signal<"
|
|
10
|
+
fillDirection: import("@angular/core").Signal<"left" | "right">;
|
|
11
11
|
fillColor: import("@angular/core").Signal<"var(--color-danger)" | "var(--color-warning)" | "var(--color-success)">;
|
|
12
12
|
static ɵfac: i0.ɵɵFactoryDeclaration<CardLevelComponent, never>;
|
|
13
13
|
static ɵcmp: i0.ɵɵComponentDeclaration<CardLevelComponent, "c80-card-level", never, { "cardLevelData": { "alias": "cardLevelData"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
@@ -13,5 +13,5 @@ export declare class SnackbarComponent {
|
|
|
13
13
|
private clearTimer;
|
|
14
14
|
private applyPosition;
|
|
15
15
|
static ɵfac: i0.ɵɵFactoryDeclaration<SnackbarComponent, never>;
|
|
16
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SnackbarComponent, "
|
|
16
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SnackbarComponent, "c80-snackbar", never, {}, {}, never, never, true, never>;
|
|
17
17
|
}
|