@c80/ui 1.0.54 → 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.
Files changed (105) hide show
  1. package/esm2022/index.js +5 -0
  2. package/esm2022/index.js.map +1 -1
  3. package/esm2022/lib/action-list/action-list.component.js +23 -0
  4. package/esm2022/lib/action-list/action-list.component.js.map +1 -0
  5. package/esm2022/lib/action-list/action-list.types.js +2 -0
  6. package/esm2022/lib/action-list/action-list.types.js.map +1 -0
  7. package/esm2022/lib/action-list/index.js +3 -0
  8. package/esm2022/lib/action-list/index.js.map +1 -0
  9. package/esm2022/lib/card-level/card-level.component.js +7 -0
  10. package/esm2022/lib/card-level/card-level.component.js.map +1 -1
  11. package/esm2022/lib/header/header.component.js +18 -0
  12. package/esm2022/lib/header/header.component.js.map +1 -0
  13. package/esm2022/lib/header/header.types.js +2 -0
  14. package/esm2022/lib/header/header.types.js.map +1 -0
  15. package/esm2022/lib/header/index.js +3 -0
  16. package/esm2022/lib/header/index.js.map +1 -0
  17. package/esm2022/lib/icon/icon.component.js +22 -11
  18. package/esm2022/lib/icon/icon.component.js.map +1 -1
  19. package/esm2022/lib/icon/icon.constants.js +3 -1
  20. package/esm2022/lib/icon/icon.constants.js.map +1 -1
  21. package/esm2022/lib/icon/icon.definitions.js +19 -5
  22. package/esm2022/lib/icon/icon.definitions.js.map +1 -1
  23. package/esm2022/lib/icon/icon.types.js.map +1 -1
  24. package/esm2022/lib/icon/icon.utils.js +3 -0
  25. package/esm2022/lib/icon/icon.utils.js.map +1 -1
  26. package/esm2022/lib/icon/index.js +1 -0
  27. package/esm2022/lib/icon/index.js.map +1 -1
  28. package/esm2022/lib/icon/theme.service.js +39 -0
  29. package/esm2022/lib/icon/theme.service.js.map +1 -0
  30. package/esm2022/lib/info-list/index.js +3 -0
  31. package/esm2022/lib/info-list/index.js.map +1 -0
  32. package/esm2022/lib/info-list/info-list.component.js +12 -0
  33. package/esm2022/lib/info-list/info-list.component.js.map +1 -0
  34. package/esm2022/lib/info-list/info-list.types.js +2 -0
  35. package/esm2022/lib/info-list/info-list.types.js.map +1 -0
  36. package/esm2022/lib/input-field/index.js +2 -0
  37. package/esm2022/lib/input-field/index.js.map +1 -0
  38. package/esm2022/lib/input-field/input-field.component.js +37 -0
  39. package/esm2022/lib/input-field/input-field.component.js.map +1 -0
  40. package/esm2022/lib/modal/modal.component.js +6 -6
  41. package/esm2022/lib/modal/modal.component.js.map +1 -1
  42. package/esm2022/lib/profile-stats/index.js +3 -0
  43. package/esm2022/lib/profile-stats/index.js.map +1 -0
  44. package/esm2022/lib/profile-stats/profile-stats.component.js +12 -0
  45. package/esm2022/lib/profile-stats/profile-stats.component.js.map +1 -0
  46. package/esm2022/lib/profile-stats/profile-stats.types.js +2 -0
  47. package/esm2022/lib/profile-stats/profile-stats.types.js.map +1 -0
  48. package/esm2022/lib/snackbar/snackbar.component.js +2 -2
  49. package/esm2022/lib/snackbar/snackbar.component.js.map +1 -1
  50. package/esm2022/lib/stat-card/stat-card.component.js +6 -6
  51. package/esm2022/lib/stat-card/stat-card.component.js.map +1 -1
  52. package/esm2022/lib/tab/c80-tab.component.js +7 -7
  53. package/esm2022/lib/tab/c80-tab.component.js.map +1 -1
  54. package/esm2022/lib/tab/directives/c80-tab-item.directive.js.map +1 -0
  55. package/esm2022/lib/tab/directives/c80-tab-label.directive.js.map +1 -0
  56. package/esm2022/lib/tab/index.js +3 -3
  57. package/esm2022/lib/tab/index.js.map +1 -1
  58. package/esm2022/lib/table/table-column-visibility.service.js.map +1 -1
  59. package/esm2022/lib/table/table-crud-state.service.js.map +1 -1
  60. package/esm2022/lib/table/table-data-converter.service.js.map +1 -1
  61. package/esm2022/lib/table/table-data-utils.service.js.map +1 -1
  62. package/esm2022/lib/table/table.component.js +26 -7
  63. package/esm2022/lib/table/table.component.js.map +1 -1
  64. package/esm2022/lib/table/table.types.js.map +1 -1
  65. package/esm2022/lib/table/table.utils.js.map +1 -1
  66. package/index.d.ts +5 -0
  67. package/lib/action-list/action-list.component.d.ts +10 -0
  68. package/lib/action-list/action-list.types.d.ts +8 -0
  69. package/lib/action-list/index.d.ts +2 -0
  70. package/lib/card-level/card-level.component.d.ts +1 -1
  71. package/lib/header/header.component.d.ts +9 -0
  72. package/lib/header/header.types.d.ts +3 -0
  73. package/lib/header/index.d.ts +2 -0
  74. package/lib/icon/icon.component.d.ts +7 -4
  75. package/lib/icon/icon.constants.d.ts +2 -0
  76. package/lib/icon/icon.types.d.ts +3 -1
  77. package/lib/icon/index.d.ts +1 -0
  78. package/lib/icon/theme.service.d.ts +10 -0
  79. package/lib/info-list/index.d.ts +2 -0
  80. package/lib/info-list/info-list.component.d.ts +7 -0
  81. package/lib/info-list/info-list.types.d.ts +4 -0
  82. package/lib/input-field/index.d.ts +1 -0
  83. package/lib/input-field/input-field.component.d.ts +19 -0
  84. package/lib/modal/modal.component.d.ts +3 -3
  85. package/lib/profile-stats/index.d.ts +2 -0
  86. package/lib/profile-stats/profile-stats.component.d.ts +7 -0
  87. package/lib/profile-stats/profile-stats.types.d.ts +4 -0
  88. package/lib/snackbar/snackbar.component.d.ts +1 -1
  89. package/lib/stat-card/stat-card.component.d.ts +3 -3
  90. package/lib/tab/c80-tab.component.d.ts +5 -5
  91. package/lib/tab/index.d.ts +3 -3
  92. package/lib/table/table-column-visibility.service.d.ts +5 -5
  93. package/lib/table/table-crud-state.service.d.ts +3 -3
  94. package/lib/table/table-data-converter.service.d.ts +2 -2
  95. package/lib/table/table-data-utils.service.d.ts +6 -6
  96. package/lib/table/table.component.d.ts +14 -14
  97. package/lib/table/table.types.d.ts +1 -1
  98. package/lib/table/table.utils.d.ts +2 -2
  99. package/package.json +1 -1
  100. package/esm2022/lib/tab/c80-tab-item.directive.js.map +0 -1
  101. package/esm2022/lib/tab/c80-tab-label.directive.js.map +0 -1
  102. /package/esm2022/lib/tab/{c80-tab-item.directive.js → directives/c80-tab-item.directive.js} +0 -0
  103. /package/esm2022/lib/tab/{c80-tab-label.directive.js → directives/c80-tab-label.directive.js} +0 -0
  104. /package/lib/tab/{c80-tab-item.directive.d.ts → directives/c80-tab-item.directive.d.ts} +0 -0
  105. /package/lib/tab/{c80-tab-label.directive.d.ts → directives/c80-tab-label.directive.d.ts} +0 -0
package/esm2022/index.js CHANGED
@@ -6,4 +6,9 @@ export * from './lib/modal';
6
6
  export * from './lib/select';
7
7
  export * from './lib/snackbar';
8
8
  export * from './lib/tab';
9
+ export * from './lib/info-list';
10
+ export * from './lib/action-list';
11
+ export * from './lib/header';
12
+ export * from './lib/profile-stats';
13
+ export * from './lib//input-field';
9
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../libs/ui/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC","sourcesContent":["export * from './lib/table';\nexport * from './lib/icon';\nexport * from './lib/stat-card';\nexport * from './lib/card-level';\nexport * from './lib/modal';\nexport * from './lib/select';\nexport * from './lib/snackbar';\nexport * from './lib/tab';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../libs/ui/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC","sourcesContent":["export * from './lib/table';\nexport * from './lib/icon';\nexport * from './lib/stat-card';\nexport * from './lib/card-level';\nexport * from './lib/modal';\nexport * from './lib/select';\nexport * from './lib/snackbar';\nexport * from './lib/tab';\nexport * from './lib/info-list';\nexport * from './lib/action-list';\nexport * from './lib/header';\nexport * from './lib/profile-stats';\nexport * from './lib//input-field';\n"]}
@@ -0,0 +1,23 @@
1
+ import { Component, input, output, ChangeDetectionStrategy } from '@angular/core';
2
+ import { IconComponent } from '../icon';
3
+ import * as i0 from "@angular/core";
4
+ export class ActionListComponent {
5
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : []));
6
+ actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : []));
7
+ actionClick = output();
8
+ onActionClick(action) {
9
+ if (typeof action.action === 'string') {
10
+ this.actionClick.emit(action.action);
11
+ }
12
+ else if (typeof action.action === 'function') {
13
+ action.action();
14
+ }
15
+ }
16
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ActionListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
17
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ActionListComponent, isStandalone: true, selector: "c80-action-list", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { actionClick: "actionClick" }, ngImport: i0, template: "<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>", styles: [".action-list__title{font-size:.875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-secondary);margin:1rem 0px .4rem}.action-list__item{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:var(--color-surface);border-radius:var(--radius-lg);margin-bottom:.75rem;border:none;width:100%;text-align:left;cursor:pointer;transition:all var(--transition-base)}.action-list__item:hover{transform:translate(2px);background:var(--color-bg-dark)}.action-list__item:last-child{margin-bottom:0}.action-list__item--danger .action-list__label{color:var(--color-accent)}.action-list__item--navigable:hover{transform:translate(2px);background:var(--color-bg-dark)}.action-list__info{display:flex;flex-direction:column;gap:.25rem}.action-list__label{font-size:1rem;font-weight:500;color:var(--color-text-primary)}.action-list__description{font-size:.875rem;color:var(--color-text-secondary)}\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 });
18
+ }
19
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ActionListComponent, decorators: [{
20
+ type: Component,
21
+ args: [{ selector: 'c80-action-list', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<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>", styles: [".action-list__title{font-size:.875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--color-text-secondary);margin:1rem 0px .4rem}.action-list__item{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:var(--color-surface);border-radius:var(--radius-lg);margin-bottom:.75rem;border:none;width:100%;text-align:left;cursor:pointer;transition:all var(--transition-base)}.action-list__item:hover{transform:translate(2px);background:var(--color-bg-dark)}.action-list__item:last-child{margin-bottom:0}.action-list__item--danger .action-list__label{color:var(--color-accent)}.action-list__item--navigable:hover{transform:translate(2px);background:var(--color-bg-dark)}.action-list__info{display:flex;flex-direction:column;gap:.25rem}.action-list__label{font-size:1rem;font-weight:500;color:var(--color-text-primary)}.action-list__description{font-size:.875rem;color:var(--color-text-secondary)}\n"] }]
22
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], actionClick: [{ type: i0.Output, args: ["actionClick"] }] } });
23
+ //# sourceMappingURL=action-list.component.js.map
@@ -0,0 +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;;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>"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=action-list.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-list.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/action-list/action-list.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface ActionItem {\n label: string;\n description?: string;\n icon?: string;\n action?: string | (() => void);\n isDanger?: boolean;\n isNavigable?: boolean;\n}"]}
@@ -0,0 +1,3 @@
1
+ export * from './action-list.component';
2
+ export * from './action-list.types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/action-list/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC","sourcesContent":["export * from './action-list.component';\nexport * from './action-list.types';"]}
@@ -1,37 +1,44 @@
1
1
  import { Component, input, computed, ChangeDetectionStrategy } from '@angular/core';
2
2
  import * as i0 from "@angular/core";
3
3
  export class CardLevelComponent {
4
+ /* v8 ignore next */
4
5
  cardLevelData = input.required(...(ngDevMode ? [{ debugName: "cardLevelData" }] : []));
5
6
  /* v8 ignore next */
6
7
  size = input(1, ...(ngDevMode ? [{ debugName: "size" }] : [])); // Multiplicador del tamaño base (220px)
7
8
  // ID único generado para el componente
9
+ /* v8 ignore next 5 */
8
10
  generatedId = computed(() => {
9
11
  const label = this.cardLevelData().label.toLowerCase().replaceAll(/\s+/g, '-');
10
12
  const randomNum = Math.floor(Math.random() * 10000);
11
13
  return `${label}-${randomNum}`;
12
14
  }, ...(ngDevMode ? [{ debugName: "generatedId" }] : []));
13
15
  // Ancho calculado de la card
16
+ /* v8 ignore next 4 */
14
17
  cardWidth = computed(() => {
15
18
  const baseWidth = 140;
16
19
  const calculatedWidth = baseWidth * this.size();
17
20
  return `${calculatedWidth}px`;
18
21
  }, ...(ngDevMode ? [{ debugName: "cardWidth" }] : []));
19
22
  // Detecta si el rango es bidireccional (min negativo, max positivo)
23
+ /* v8 ignore next 4 */
20
24
  isBidirectional = computed(() => {
21
25
  const data = this.cardLevelData();
22
26
  return data.min < 0 && data.max > 0;
23
27
  }, ...(ngDevMode ? [{ debugName: "isBidirectional" }] : []));
24
28
  // Calcula el porcentaje de fill para barras bidireccionales
29
+ /* v8 ignore next 4 */
25
30
  bidirectionalFillPercent = computed(() => {
26
31
  const data = this.cardLevelData();
27
32
  const totalRange = data.max - data.min;
28
33
  return Math.abs(data.value / totalRange) * 100;
29
34
  }, ...(ngDevMode ? [{ debugName: "bidirectionalFillPercent" }] : []));
30
35
  // Determina la dirección del fill (left/right)
36
+ /* v8 ignore next 3 */
31
37
  fillDirection = computed(() => {
32
38
  return this.cardLevelData().value >= 0 ? 'right' : 'left';
33
39
  }, ...(ngDevMode ? [{ debugName: "fillDirection" }] : []));
34
40
  // Color según el valor y umbrales
41
+ /* v8 ignore next 11 */
35
42
  fillColor = computed(() => {
36
43
  const data = this.cardLevelData();
37
44
  const absValue = Math.abs(data.value);
@@ -1 +1 @@
1
- {"version":3,"file":"card-level.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/card-level/card-level.component.ts","../../../../../libs/ui/src/lib/card-level/card-level.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;;AAYpF,MAAM,OAAO,kBAAkB;IAC7B,aAAa,GAAG,KAAK,CAAC,QAAQ,wDAAiB,CAAC;IAChD,oBAAoB;IACpB,IAAI,GAAG,KAAK,CAAS,CAAC,gDAAC,CAAC,CAAC,wCAAwC;IAEjE,uCAAuC;IAC9B,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC/E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;QACpD,OAAO,GAAG,KAAK,IAAI,SAAS,EAAE,CAAC;IACjC,CAAC,uDAAC,CAAC;IAEH,6BAA6B;IACpB,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE;QACjC,MAAM,SAAS,GAAG,GAAG,CAAC;QACtB,MAAM,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,GAAG,eAAe,IAAI,CAAC;IAChC,CAAC,qDAAC,CAAC;IAEH,oEAAoE;IACpE,eAAe,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IACtC,CAAC,2DAAC,CAAC;IAEH,4DAA4D;IAC5D,wBAAwB,GAAG,QAAQ,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;IACjD,CAAC,oEAAC,CAAC;IAEH,+CAA+C;IAC/C,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC5B,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5D,CAAC,yDAAC,CAAC;IAEH,kCAAkC;IAClC,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;YACxB,OAAO,qBAAqB,CAAC;QAC/B,CAAC;QACD,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,sBAAsB,CAAC;QAChC,CAAC;QACD,OAAO,sBAAsB,CAAC;IAChC,CAAC,qDAAC,CAAC;wGAnDQ,kBAAkB;4FAAlB,kBAAkB,0VCZ/B,qtCAyBgE;;4FDbnD,kBAAkB;kBAT9B,SAAS;+BAEE,gBAAgB,cACd,IAAI,WACP,EAAE,mBAGM,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, computed, ChangeDetectionStrategy } from '@angular/core';\nimport type { CardLevelData } from './card-level.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-card-level',\n standalone: true,\n imports: [],\n templateUrl: './card-level.component.html',\n styleUrl: './card-level.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CardLevelComponent {\n cardLevelData = input.required<CardLevelData>();\n /* v8 ignore next */\n size = input<number>(1); // Multiplicador del tamaño base (220px)\n\n // ID único generado para el componente\n readonly generatedId = computed(() => {\n const label = this.cardLevelData().label.toLowerCase().replaceAll(/\\s+/g, '-');\n const randomNum = Math.floor(Math.random() * 10000);\n return `${label}-${randomNum}`;\n });\n\n // Ancho calculado de la card\n readonly cardWidth = computed(() => {\n const baseWidth = 140;\n const calculatedWidth = baseWidth * this.size();\n return `${calculatedWidth}px`;\n });\n\n // Detecta si el rango es bidireccional (min negativo, max positivo)\n isBidirectional = computed(() => {\n const data = this.cardLevelData();\n return data.min < 0 && data.max > 0;\n });\n\n // Calcula el porcentaje de fill para barras bidireccionales\n bidirectionalFillPercent = computed(() => {\n const data = this.cardLevelData();\n const totalRange = data.max - data.min;\n return Math.abs(data.value / totalRange) * 100;\n });\n\n // Determina la dirección del fill (left/right)\n fillDirection = computed(() => {\n return this.cardLevelData().value >= 0 ? 'right' : 'left';\n });\n\n // Color según el valor y umbrales\n fillColor = computed(() => {\n const data = this.cardLevelData();\n const absValue = Math.abs(data.value);\n const absHigh = Math.abs(data.high);\n const absLow = Math.abs(data.low);\n\n if (absValue >= absHigh) {\n return 'var(--color-danger)';\n }\n if (absValue >= absLow) {\n return 'var(--color-warning)';\n }\n return 'var(--color-success)';\n });\n}\n","<!-- eslint-disable @angular-eslint/template/no-inline-styles -->\n<div class=\"card-level-container\" [style.width]=\"cardWidth()\">\n <label [for]=\"generatedId()\">\n <strong>{{ cardLevelData().label }}</strong>\n\n <span class=\"value-display\">\n @if (isBidirectional()) {\n <!-- Barra bidireccional desde el centro -->\n <div class=\"bidirectional-meter\">\n <div class=\"meter-track\">\n <div class=\"center-line\"></div>\n <div class=\"meter-fill\" [class.fill-left]=\"fillDirection() === 'left'\" [class.fill-right]=\"fillDirection() === 'right'\" [style.width.%]=\"bidirectionalFillPercent()\" [style.background]=\"fillColor()\">\n </div>\n </div>\n </div>\n } @else {\n <!-- Meter estándar para rangos unidireccionales -->\n <meter [id]=\"generatedId()\" [optimum]=\"cardLevelData().optimum\" [min]=\"cardLevelData().min\" [max]=\"cardLevelData().max\" [low]=\"cardLevelData().low\" [high]=\"cardLevelData().high\" [value]=\"cardLevelData().value\">\n </meter>\n }\n\n {{ cardLevelData().value }}{{ cardLevelData().unit }}\n </span>\n </label>\n</div>\n<!-- eslint-enable @angular-eslint/template/no-inline-styles -->"]}
1
+ {"version":3,"file":"card-level.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/card-level/card-level.component.ts","../../../../../libs/ui/src/lib/card-level/card-level.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;;AAYpF,MAAM,OAAO,kBAAkB;IAC7B,oBAAoB;IACpB,aAAa,GAAG,KAAK,CAAC,QAAQ,wDAAiB,CAAC;IAChD,oBAAoB;IACpB,IAAI,GAAG,KAAK,CAAS,CAAC,gDAAC,CAAC,CAAC,wCAAwC;IAEjE,uCAAuC;IACvC,sBAAsB;IACb,WAAW,GAAG,QAAQ,CAAC,GAAG,EAAE;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC/E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC;QACpD,OAAO,GAAG,KAAK,IAAI,SAAS,EAAE,CAAC;IACjC,CAAC,uDAAC,CAAC;IAEH,6BAA6B;IAC7B,sBAAsB;IACb,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE;QACjC,MAAM,SAAS,GAAG,GAAG,CAAC;QACtB,MAAM,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,GAAG,eAAe,IAAI,CAAC;IAChC,CAAC,qDAAC,CAAC;IAEH,oEAAoE;IACpE,sBAAsB;IACtB,eAAe,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IACtC,CAAC,2DAAC,CAAC;IAEH,4DAA4D;IAC5D,sBAAsB;IACtB,wBAAwB,GAAG,QAAQ,CAAC,GAAG,EAAE;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC;IACjD,CAAC,oEAAC,CAAC;IAEH,+CAA+C;IAC/C,sBAAsB;IACtB,aAAa,GAAG,QAAQ,CAAC,GAAG,EAAE;QAC5B,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5D,CAAC,yDAAC,CAAC;IAEH,kCAAkC;IAClC,uBAAuB;IACvB,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;YACxB,OAAO,qBAAqB,CAAC;QAC/B,CAAC;QACD,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YACvB,OAAO,sBAAsB,CAAC;QAChC,CAAC;QACD,OAAO,sBAAsB,CAAC;IAChC,CAAC,qDAAC,CAAC;wGA1DQ,kBAAkB;4FAAlB,kBAAkB,0VCZ/B,qtCAyBgE;;4FDbnD,kBAAkB;kBAT9B,SAAS;+BAEE,gBAAgB,cACd,IAAI,WACP,EAAE,mBAGM,uBAAuB,CAAC,MAAM","sourcesContent":["import { Component, input, computed, ChangeDetectionStrategy } from '@angular/core';\nimport type { CardLevelData } from './card-level.interface';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-card-level',\n standalone: true,\n imports: [],\n templateUrl: './card-level.component.html',\n styleUrl: './card-level.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CardLevelComponent {\n /* v8 ignore next */\n cardLevelData = input.required<CardLevelData>();\n /* v8 ignore next */\n size = input<number>(1); // Multiplicador del tamaño base (220px)\n\n // ID único generado para el componente\n /* v8 ignore next 5 */\n readonly generatedId = computed(() => {\n const label = this.cardLevelData().label.toLowerCase().replaceAll(/\\s+/g, '-');\n const randomNum = Math.floor(Math.random() * 10000);\n return `${label}-${randomNum}`;\n });\n\n // Ancho calculado de la card\n /* v8 ignore next 4 */\n readonly cardWidth = computed(() => {\n const baseWidth = 140;\n const calculatedWidth = baseWidth * this.size();\n return `${calculatedWidth}px`;\n });\n\n // Detecta si el rango es bidireccional (min negativo, max positivo)\n /* v8 ignore next 4 */\n isBidirectional = computed(() => {\n const data = this.cardLevelData();\n return data.min < 0 && data.max > 0;\n });\n\n // Calcula el porcentaje de fill para barras bidireccionales\n /* v8 ignore next 4 */\n bidirectionalFillPercent = computed(() => {\n const data = this.cardLevelData();\n const totalRange = data.max - data.min;\n return Math.abs(data.value / totalRange) * 100;\n });\n\n // Determina la dirección del fill (left/right)\n /* v8 ignore next 3 */\n fillDirection = computed(() => {\n return this.cardLevelData().value >= 0 ? 'right' : 'left';\n });\n\n // Color según el valor y umbrales\n /* v8 ignore next 11 */\n fillColor = computed(() => {\n const data = this.cardLevelData();\n const absValue = Math.abs(data.value);\n const absHigh = Math.abs(data.high);\n const absLow = Math.abs(data.low);\n\n if (absValue >= absHigh) {\n return 'var(--color-danger)';\n }\n if (absValue >= absLow) {\n return 'var(--color-warning)';\n }\n return 'var(--color-success)';\n });\n}\n","<!-- eslint-disable @angular-eslint/template/no-inline-styles -->\n<div class=\"card-level-container\" [style.width]=\"cardWidth()\">\n <label [for]=\"generatedId()\">\n <strong>{{ cardLevelData().label }}</strong>\n\n <span class=\"value-display\">\n @if (isBidirectional()) {\n <!-- Barra bidireccional desde el centro -->\n <div class=\"bidirectional-meter\">\n <div class=\"meter-track\">\n <div class=\"center-line\"></div>\n <div class=\"meter-fill\" [class.fill-left]=\"fillDirection() === 'left'\" [class.fill-right]=\"fillDirection() === 'right'\" [style.width.%]=\"bidirectionalFillPercent()\" [style.background]=\"fillColor()\">\n </div>\n </div>\n </div>\n } @else {\n <!-- Meter estándar para rangos unidireccionales -->\n <meter [id]=\"generatedId()\" [optimum]=\"cardLevelData().optimum\" [min]=\"cardLevelData().min\" [max]=\"cardLevelData().max\" [low]=\"cardLevelData().low\" [high]=\"cardLevelData().high\" [value]=\"cardLevelData().value\">\n </meter>\n }\n\n {{ cardLevelData().value }}{{ cardLevelData().unit }}\n </span>\n </label>\n</div>\n<!-- eslint-enable @angular-eslint/template/no-inline-styles -->"]}
@@ -0,0 +1,18 @@
1
+ import { Location } from '@angular/common';
2
+ import { ChangeDetectionStrategy, Component, inject, input } from '@angular/core';
3
+ import { IconComponent } from '../icon';
4
+ import * as i0 from "@angular/core";
5
+ export class HeaderComponent {
6
+ location = inject(Location);
7
+ config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
8
+ onBackClick() {
9
+ this.location.back();
10
+ }
11
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.10", type: HeaderComponent, isStandalone: true, selector: "c80-header", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<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>", styles: [".header{display:flex;align-items:center;gap:1rem;margin-bottom:2rem;padding:1rem;border-bottom:1px solid var(--color-border)}.header__back-btn{flex-shrink:0}.header__title{font-size:1.5rem;font-weight:600;color:var(--color-text-primary);margin:0}.header__spacer{flex:1}@media(max-width:768px){.header{padding:.75rem;gap:.75rem;margin-bottom:1.5rem}.header__title{font-size:1.25rem}}\n"], dependencies: [{ kind: "component", type: IconComponent, selector: "c80-icon", inputs: ["icon", "color", "customColor", "disabled", "size", "button", "border", "type", "textLeft", "textRight", "dark"], outputs: ["iconClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13
+ }
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: HeaderComponent, decorators: [{
15
+ type: Component,
16
+ args: [{ selector: 'c80-header', standalone: true, imports: [IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<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>", styles: [".header{display:flex;align-items:center;gap:1rem;margin-bottom:2rem;padding:1rem;border-bottom:1px solid var(--color-border)}.header__back-btn{flex-shrink:0}.header__title{font-size:1.5rem;font-weight:600;color:var(--color-text-primary);margin:0}.header__spacer{flex:1}@media(max-width:768px){.header{padding:.75rem;gap:.75rem;margin-bottom:1.5rem}.header__title{font-size:1.25rem}}\n"] }]
17
+ }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }] } });
18
+ //# sourceMappingURL=header.component.js.map
@@ -0,0 +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;;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>"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=header.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"header.types.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/header/header.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface HeaderConfig {\n title: string;\n}"]}
@@ -0,0 +1,3 @@
1
+ export * from './header.component';
2
+ export * from './header.types';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/header/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,gBAAgB,CAAC","sourcesContent":["export * from './header.component';\nexport * from './header.types';"]}
@@ -1,14 +1,16 @@
1
1
  import { NgTemplateOutlet } from '@angular/common';
2
- import { Component, input, output, computed, ChangeDetectionStrategy } from '@angular/core';
3
- import { BASE_ICON_SIZE, BASE_ICON_COLORS, DISABLED_COLOR, DEFAULT_ICON_COLOR, DISABLED_OPACITY, SECONDARY_WARN_OPACITY, DEFAULT_OPACITY, OPACITY_REDUCED_COLORS, SVG_STROKE_ATTRS, } from './icon.constants';
2
+ import { Component, input, output, computed, ChangeDetectionStrategy, inject } from '@angular/core';
3
+ import { BASE_ICON_SIZE, BASE_ICON_COLORS, DISABLED_COLOR, DEFAULT_ICON_COLOR, DISABLED_OPACITY, SECONDARY_WARN_OPACITY, DEFAULT_OPACITY, OPACITY_REDUCED_COLORS, SVG_STROKE_ATTRS, THEME_DARK_COLOR, THEME_LIGHT_COLOR, } from './icon.constants';
4
4
  import { ICON_DEFINITIONS } from './icon.definitions';
5
5
  import { transformToBoolean, shouldIconUseFill } from './icon.utils';
6
+ import { ThemeService } from './theme.service';
6
7
  import * as i0 from "@angular/core";
7
- export class C80IconComponent {
8
+ export class IconComponent {
9
+ themeService = inject(ThemeService);
8
10
  /* v8 ignore next */
9
11
  icon = input('check', ...(ngDevMode ? [{ debugName: "icon" }] : [])); // Tipo de icono a mostrar
10
12
  /* v8 ignore next */
11
- color = input('dark', ...(ngDevMode ? [{ debugName: "color" }] : [])); // Color del icono (primary, secondary, warn, success, dark)
13
+ color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : [])); // Color del icono (primary, secondary, warn, success)
12
14
  /* v8 ignore next */
13
15
  customColor = input(undefined, ...(ngDevMode ? [{ debugName: "customColor" }] : [])); // Color personalizado (sobrescribe color)
14
16
  /* v8 ignore next */
@@ -25,21 +27,30 @@ export class C80IconComponent {
25
27
  textLeft = input(undefined, ...(ngDevMode ? [{ debugName: "textLeft" }] : [])); // Texto a la izquierda del icono
26
28
  /* v8 ignore next */
27
29
  textRight = input(undefined, ...(ngDevMode ? [{ debugName: "textRight" }] : [])); // Texto a la derecha del icono
30
+ /* v8 ignore next */
31
+ dark = input(false, ...(ngDevMode ? [{ debugName: "dark", transform: transformToBoolean }] : [{ transform: transformToBoolean }])); // Modo oscuro
28
32
  iconClick = output(); // Evento emitido al hacer click (solo si button=true)
29
33
  iconSize = computed(() => BASE_ICON_SIZE * this.size(), ...(ngDevMode ? [{ debugName: "iconSize" }] : []));
34
+ isDarkMode = computed(() => this.dark() || this.themeService.isDark(), ...(ngDevMode ? [{ debugName: "isDarkMode" }] : []));
30
35
  iconColor = computed(() => {
31
36
  if (this.disabled())
32
37
  return DISABLED_COLOR;
33
38
  const custom = this.customColor();
34
39
  if (custom)
35
40
  return custom;
36
- return BASE_ICON_COLORS[this.color()] ?? DEFAULT_ICON_COLOR;
41
+ const colorType = this.color();
42
+ // Si no hay color específico, usar color adaptativo al tema
43
+ if (!colorType) {
44
+ return this.themeService.isDark() ? THEME_DARK_COLOR : THEME_LIGHT_COLOR;
45
+ }
46
+ return BASE_ICON_COLORS[colorType] ?? DEFAULT_ICON_COLOR;
37
47
  }, ...(ngDevMode ? [{ debugName: "iconColor" }] : []));
38
48
  iconOpacity = computed(() => {
39
49
  if (this.disabled())
40
50
  return DISABLED_OPACITY;
41
51
  const hasCustomColor = this.customColor() !== undefined;
42
- const isOpacityReducedColor = OPACITY_REDUCED_COLORS.includes(this.color());
52
+ const colorType = this.color();
53
+ const isOpacityReducedColor = colorType && OPACITY_REDUCED_COLORS.includes(colorType);
43
54
  return !hasCustomColor && isOpacityReducedColor ? SECONDARY_WARN_OPACITY : DEFAULT_OPACITY;
44
55
  }, ...(ngDevMode ? [{ debugName: "iconOpacity" }] : []));
45
56
  // Optimización: Un solo lookup a ICON_DEFINITIONS
@@ -58,11 +69,11 @@ export class C80IconComponent {
58
69
  this.iconClick.emit(event);
59
70
  }
60
71
  }
61
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: C80IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
62
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: C80IconComponent, isStandalone: true, selector: "c80-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, customColor: { classPropertyName: "customColor", publicName: "customColor", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, button: { classPropertyName: "button", publicName: "button", isSignal: true, isRequired: false, transformFunction: null }, border: { classPropertyName: "border", publicName: "border", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, textLeft: { classPropertyName: "textLeft", publicName: "textLeft", isSignal: true, isRequired: false, transformFunction: null }, textRight: { classPropertyName: "textRight", publicName: "textRight", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { iconClick: "iconClick" }, ngImport: i0, template: "<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con m\u00FAltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}", styles: [":host .icon-wrapper{display:inline-flex;align-items:center;gap:8px;background:transparent;padding:0;border:none;outline:none;cursor:pointer;transition:opacity .2s}:host button.icon-wrapper:focus-visible{outline:none;outline-offset:2px;border-radius:4px}:host button.icon-wrapper:disabled{opacity:.5;cursor:default}:host .icon-content{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;min-width:0;min-height:0;padding:4px;margin:0 4px;transition:background .2s;box-sizing:border-box}:host button.icon-wrapper:hover:not(:disabled) .icon-content{background:var(--color-bg-hover)}:host button.icon-wrapper:active:not(:disabled) .icon-content{background:var(--color-bg-tertiary)}:host .icon-text{font-size:14px;line-height:1;white-space:nowrap;-webkit-user-select:none;user-select:none;color:var(--color-text-primary)}:host .icon-wrapper-border{border:1px solid var(--color-border-default);border-radius:4px;padding:4px 8px}:host button.icon-wrapper-border:hover:not(:disabled){border-color:var(--color-border-medium)}:host button.icon-wrapper-border:disabled{border-color:var(--color-border-light)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
73
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: IconComponent, isStandalone: true, selector: "c80-icon", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, customColor: { classPropertyName: "customColor", publicName: "customColor", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, button: { classPropertyName: "button", publicName: "button", isSignal: true, isRequired: false, transformFunction: null }, border: { classPropertyName: "border", publicName: "border", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, textLeft: { classPropertyName: "textLeft", publicName: "textLeft", isSignal: true, isRequired: false, transformFunction: null }, textRight: { classPropertyName: "textRight", publicName: "textRight", isSignal: true, isRequired: false, transformFunction: null }, dark: { classPropertyName: "dark", publicName: "dark", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { iconClick: "iconClick" }, ngImport: i0, template: "<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con m\u00FAltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}", styles: [":host{--icon-border-color: #e5e7eb;--icon-border-color-hover: #d1d5db;--icon-border-color-disabled: #f3f4f6;--icon-bg-hover: #f3f4f6;--icon-bg-active: #e5e7eb;--icon-text-color: #111827;--icon-border-radius: 4px;--icon-transition: .2s}:host .dark-mode{--icon-border-color: #374151;--icon-border-color-hover: #4b5563;--icon-border-color-disabled: #1f2937;--icon-bg-hover: #374151;--icon-bg-active: #4b5563;--icon-text-color: #f9fafb}:host .icon-wrapper{display:inline-flex;align-items:center;gap:8px;background:transparent;padding:0;border:none;outline:none;cursor:pointer;transition:opacity var(--icon-transition)}:host button.icon-wrapper:focus-visible{outline:none;outline-offset:2px;border-radius:var(--icon-border-radius)}:host button.icon-wrapper:disabled{opacity:.5;cursor:default}:host .icon-content{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;min-width:0;min-height:0;padding:4px;margin:0 4px;transition:background var(--icon-transition);box-sizing:border-box}:host button.icon-wrapper:hover:not(:disabled) .icon-content{background:var(--icon-bg-hover)}:host button.icon-wrapper:active:not(:disabled) .icon-content{background:var(--icon-bg-active)}:host .icon-text{font-size:14px;line-height:1;white-space:nowrap;-webkit-user-select:none;user-select:none;color:var(--icon-text-color)}:host .icon-wrapper-border{border:1px solid var(--icon-border-color);border-radius:var(--icon-border-radius);padding:4px 8px}:host button.icon-wrapper-border:hover:not(:disabled){border-color:var(--icon-border-color-hover)}:host button.icon-wrapper-border:disabled{border-color:var(--icon-border-color-disabled)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
63
74
  }
64
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: C80IconComponent, decorators: [{
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: IconComponent, decorators: [{
65
76
  type: Component,
66
- args: [{ selector: 'c80-icon', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con m\u00FAltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}", styles: [":host .icon-wrapper{display:inline-flex;align-items:center;gap:8px;background:transparent;padding:0;border:none;outline:none;cursor:pointer;transition:opacity .2s}:host button.icon-wrapper:focus-visible{outline:none;outline-offset:2px;border-radius:4px}:host button.icon-wrapper:disabled{opacity:.5;cursor:default}:host .icon-content{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;min-width:0;min-height:0;padding:4px;margin:0 4px;transition:background .2s;box-sizing:border-box}:host button.icon-wrapper:hover:not(:disabled) .icon-content{background:var(--color-bg-hover)}:host button.icon-wrapper:active:not(:disabled) .icon-content{background:var(--color-bg-tertiary)}:host .icon-text{font-size:14px;line-height:1;white-space:nowrap;-webkit-user-select:none;user-select:none;color:var(--color-text-primary)}:host .icon-wrapper-border{border:1px solid var(--color-border-default);border-radius:4px;padding:4px 8px}:host button.icon-wrapper-border:hover:not(:disabled){border-color:var(--color-border-medium)}:host button.icon-wrapper-border:disabled{border-color:var(--color-border-light)}\n"] }]
67
- }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], customColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "customColor", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], button: [{ type: i0.Input, args: [{ isSignal: true, alias: "button", required: false }] }], border: [{ type: i0.Input, args: [{ isSignal: true, alias: "border", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], textLeft: [{ type: i0.Input, args: [{ isSignal: true, alias: "textLeft", required: false }] }], textRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "textRight", required: false }] }], iconClick: [{ type: i0.Output, args: ["iconClick"] }] } });
77
+ args: [{ selector: 'c80-icon', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con m\u00FAltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}", styles: [":host{--icon-border-color: #e5e7eb;--icon-border-color-hover: #d1d5db;--icon-border-color-disabled: #f3f4f6;--icon-bg-hover: #f3f4f6;--icon-bg-active: #e5e7eb;--icon-text-color: #111827;--icon-border-radius: 4px;--icon-transition: .2s}:host .dark-mode{--icon-border-color: #374151;--icon-border-color-hover: #4b5563;--icon-border-color-disabled: #1f2937;--icon-bg-hover: #374151;--icon-bg-active: #4b5563;--icon-text-color: #f9fafb}:host .icon-wrapper{display:inline-flex;align-items:center;gap:8px;background:transparent;padding:0;border:none;outline:none;cursor:pointer;transition:opacity var(--icon-transition)}:host button.icon-wrapper:focus-visible{outline:none;outline-offset:2px;border-radius:var(--icon-border-radius)}:host button.icon-wrapper:disabled{opacity:.5;cursor:default}:host .icon-content{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;min-width:0;min-height:0;padding:4px;margin:0 4px;transition:background var(--icon-transition);box-sizing:border-box}:host button.icon-wrapper:hover:not(:disabled) .icon-content{background:var(--icon-bg-hover)}:host button.icon-wrapper:active:not(:disabled) .icon-content{background:var(--icon-bg-active)}:host .icon-text{font-size:14px;line-height:1;white-space:nowrap;-webkit-user-select:none;user-select:none;color:var(--icon-text-color)}:host .icon-wrapper-border{border:1px solid var(--icon-border-color);border-radius:var(--icon-border-radius);padding:4px 8px}:host button.icon-wrapper-border:hover:not(:disabled){border-color:var(--icon-border-color-hover)}:host button.icon-wrapper-border:disabled{border-color:var(--icon-border-color-disabled)}\n"] }]
78
+ }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], customColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "customColor", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], button: [{ type: i0.Input, args: [{ isSignal: true, alias: "button", required: false }] }], border: [{ type: i0.Input, args: [{ isSignal: true, alias: "border", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], textLeft: [{ type: i0.Input, args: [{ isSignal: true, alias: "textLeft", required: false }] }], textRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "textRight", required: false }] }], dark: [{ type: i0.Input, args: [{ isSignal: true, alias: "dark", required: false }] }], iconClick: [{ type: i0.Output, args: ["iconClick"] }] } });
68
79
  //# sourceMappingURL=icon.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"icon.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/icon/icon.component.ts","../../../../../libs/ui/src/lib/icon/icon.component.html"],"names":[],"mappings":"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","sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport { Component, input, output, computed, ChangeDetectionStrategy } from '@angular/core';\nimport {\n BASE_ICON_SIZE,\n BASE_ICON_COLORS,\n DISABLED_COLOR,\n DEFAULT_ICON_COLOR,\n DISABLED_OPACITY,\n SECONDARY_WARN_OPACITY,\n DEFAULT_OPACITY,\n OPACITY_REDUCED_COLORS,\n SVG_STROKE_ATTRS,\n} from './icon.constants';\nimport { ICON_DEFINITIONS } from './icon.definitions';\nimport type { ColorType, ButtonType, IconType } from './icon.types';\nimport { transformToBoolean, shouldIconUseFill } from './icon.utils';\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-icon',\n standalone: true,\n imports: [NgTemplateOutlet],\n templateUrl: './icon.component.html',\n styleUrls: ['./icon.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class C80IconComponent {\n /* v8 ignore next */\n readonly icon = input<IconType>('check'); // Tipo de icono a mostrar\n /* v8 ignore next */\n readonly color = input<ColorType>('dark'); // Color del icono (primary, secondary, warn, success, dark)\n /* v8 ignore next */\n readonly customColor = input<string | undefined>(undefined); // Color personalizado (sobrescribe color)\n /* v8 ignore next */\n readonly disabled = input(false); // Estado deshabilitado\n /* v8 ignore next */\n readonly size = input(1); // Multiplicador de tamaño (1 = 24px)\n /* v8 ignore next */\n readonly button = input(false, { transform: transformToBoolean }); // Renderiza como botón clickeable\n /* v8 ignore next */\n readonly border = input(false, { transform: transformToBoolean }); // Agrega borde al wrapper\n /* v8 ignore next */\n readonly type = input<ButtonType>('button'); // Tipo de botón (button, submit, reset)\n /* v8 ignore next */\n readonly textLeft = input<string | undefined>(undefined); // Texto a la izquierda del icono\n /* v8 ignore next */\n readonly textRight = input<string | undefined>(undefined); // Texto a la derecha del icono\n\n readonly iconClick = output<Event>(); // Evento emitido al hacer click (solo si button=true)\n\n readonly iconSize = computed(() => BASE_ICON_SIZE * this.size());\n\n readonly iconColor = computed(() => {\n if (this.disabled()) return DISABLED_COLOR;\n\n const custom = this.customColor();\n if (custom) return custom;\n\n return BASE_ICON_COLORS[this.color()] ?? DEFAULT_ICON_COLOR;\n });\n\n readonly iconOpacity = computed(() => {\n if (this.disabled()) return DISABLED_OPACITY;\n\n const hasCustomColor = this.customColor() !== undefined;\n const isOpacityReducedColor = OPACITY_REDUCED_COLORS.includes(this.color());\n\n return !hasCustomColor && isOpacityReducedColor ? SECONDARY_WARN_OPACITY : DEFAULT_OPACITY;\n });\n\n // Optimización: Un solo lookup a ICON_DEFINITIONS\n readonly iconDefinition = computed(() => {\n return ICON_DEFINITIONS[this.icon()] ?? ICON_DEFINITIONS['default'];\n });\n\n readonly iconPath = computed(() => this.iconDefinition().path);\n\n readonly additionalShapes = computed(() => this.iconDefinition().additionalShapes ?? []);\n\n readonly shouldFillIcon = computed(() => shouldIconUseFill(this.icon()));\n\n readonly multiColorIcon = computed(() => this.iconDefinition().multiColor);\n\n readonly hasMultiPaths = computed(() => this.multiColorIcon() !== undefined);\n\n // Exponer constantes SVG al template\n readonly svgStrokeAttrs = SVG_STROKE_ATTRS;\n\n onButtonClick(event: Event): void {\n if (!this.disabled()) {\n this.iconClick.emit(event);\n }\n }\n}\n","<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con múltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}"]}
1
+ {"version":3,"file":"icon.component.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/icon/icon.component.ts","../../../../../libs/ui/src/lib/icon/icon.component.html"],"names":[],"mappings":"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","sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport { Component, input, output, computed, ChangeDetectionStrategy, inject } from '@angular/core';\nimport {\n BASE_ICON_SIZE,\n BASE_ICON_COLORS,\n DISABLED_COLOR,\n DEFAULT_ICON_COLOR,\n DISABLED_OPACITY,\n SECONDARY_WARN_OPACITY,\n DEFAULT_OPACITY,\n OPACITY_REDUCED_COLORS,\n SVG_STROKE_ATTRS,\n THEME_DARK_COLOR,\n THEME_LIGHT_COLOR,\n} from './icon.constants';\nimport { ICON_DEFINITIONS } from './icon.definitions';\nimport type { ColorType, ButtonType, IconType } from './icon.types';\nimport { transformToBoolean, shouldIconUseFill } from './icon.utils';\nimport { ThemeService } from './theme.service';\n\n\n@Component({\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: 'c80-icon',\n standalone: true,\n imports: [NgTemplateOutlet],\n templateUrl: './icon.component.html',\n styleUrls: ['./icon.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class IconComponent {\n private readonly themeService = inject(ThemeService);\n\n /* v8 ignore next */\n readonly icon = input<IconType>('check'); // Tipo de icono a mostrar\n /* v8 ignore next */\n readonly color = input<ColorType | undefined>(undefined); // Color del icono (primary, secondary, warn, success)\n /* v8 ignore next */\n readonly customColor = input<string | undefined>(undefined); // Color personalizado (sobrescribe color)\n /* v8 ignore next */\n readonly disabled = input(false); // Estado deshabilitado\n /* v8 ignore next */\n readonly size = input(1); // Multiplicador de tamaño (1 = 24px)\n /* v8 ignore next */\n readonly button = input(false, { transform: transformToBoolean }); // Renderiza como botón clickeable\n /* v8 ignore next */\n readonly border = input(false, { transform: transformToBoolean }); // Agrega borde al wrapper\n /* v8 ignore next */\n readonly type = input<ButtonType>('button'); // Tipo de botón (button, submit, reset)\n /* v8 ignore next */\n readonly textLeft = input<string | undefined>(undefined); // Texto a la izquierda del icono\n /* v8 ignore next */\n readonly textRight = input<string | undefined>(undefined); // Texto a la derecha del icono\n /* v8 ignore next */\n readonly dark = input(false, { transform: transformToBoolean }); // Modo oscuro\n\n readonly iconClick = output<Event>(); // Evento emitido al hacer click (solo si button=true)\n\n readonly iconSize = computed(() => BASE_ICON_SIZE * this.size());\n\n readonly isDarkMode = computed(() => this.dark() || this.themeService.isDark());\n\n readonly iconColor = computed(() => {\n if (this.disabled()) return DISABLED_COLOR;\n\n const custom = this.customColor();\n if (custom) return custom;\n\n const colorType = this.color();\n\n // Si no hay color específico, usar color adaptativo al tema\n if (!colorType) {\n return this.themeService.isDark() ? THEME_DARK_COLOR : THEME_LIGHT_COLOR;\n }\n\n return BASE_ICON_COLORS[colorType] ?? DEFAULT_ICON_COLOR;\n });\n\n readonly iconOpacity = computed(() => {\n if (this.disabled()) return DISABLED_OPACITY;\n\n const hasCustomColor = this.customColor() !== undefined;\n const colorType = this.color();\n const isOpacityReducedColor = colorType && OPACITY_REDUCED_COLORS.includes(colorType);\n\n return !hasCustomColor && isOpacityReducedColor ? SECONDARY_WARN_OPACITY : DEFAULT_OPACITY;\n });\n\n // Optimización: Un solo lookup a ICON_DEFINITIONS\n readonly iconDefinition = computed(() => {\n return ICON_DEFINITIONS[this.icon()] ?? ICON_DEFINITIONS['default'];\n });\n\n readonly iconPath = computed(() => this.iconDefinition().path);\n\n readonly additionalShapes = computed(() => this.iconDefinition().additionalShapes ?? []);\n\n readonly shouldFillIcon = computed(() => shouldIconUseFill(this.icon()));\n\n readonly multiColorIcon = computed(() => this.iconDefinition().multiColor);\n\n readonly hasMultiPaths = computed(() => this.multiColorIcon() !== undefined);\n\n // Exponer constantes SVG al template\n readonly svgStrokeAttrs = SVG_STROKE_ATTRS;\n\n onButtonClick(event: Event): void {\n if (!this.disabled()) {\n this.iconClick.emit(event);\n }\n }\n}\n","<ng-template #svgContent>\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <svg [attr.width]=\"iconSize()\" [attr.height]=\"iconSize()\" viewBox=\"0 0 24 24\" fill=\"none\" [style.opacity]=\"iconOpacity()\">\n @for (shape of additionalShapes(); track $index) {\n @if (shape.type === 'circle') {\n <circle [attr.cx]=\"shape.cx\" [attr.cy]=\"shape.cy\" [attr.r]=\"shape.r\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'rect') {\n <rect [attr.x]=\"shape.x\" [attr.y]=\"shape.y\" [attr.width]=\"shape.width\" [attr.height]=\"shape.height\" [attr.rx]=\"shape.rx || null\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n } @else if (shape.type === 'path') {\n <path [attr.d]=\"shape.d\" [attr.stroke]=\"iconColor()\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\" [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\"\n [attr.fill]=\"shape.fill === 'color' ? iconColor() : 'none'\" />\n }\n }\n\n @if (hasMultiPaths()) {\n <!-- Iconos con múltiples paths y colores personalizados -->\n @for (path of multiColorIcon()!.paths; track $index) {\n <path [attr.d]=\"path\" [attr.fill]=\"multiColorIcon()!.colors[$index] || iconColor()\" stroke=\"none\" />\n }\n } @else {\n <!-- Iconos con un solo path -->\n <path [attr.d]=\"iconPath()\" [attr.stroke]=\"iconColor()\" [attr.fill]=\"shouldFillIcon() ? iconColor() : 'none'\" [attr.stroke-width]=\"svgStrokeAttrs.strokeWidth\" [attr.stroke-linecap]=\"svgStrokeAttrs.strokeLinecap\"\n [attr.stroke-linejoin]=\"svgStrokeAttrs.strokeLinejoin\" />\n }\n </svg>\n</ng-template>\n\n<ng-template #textContent>\n @if (textLeft()) {\n <span class=\"icon-text ms-3\">{{ textLeft() }}</span>\n }\n <!-- eslint-disable-next-line @angular-eslint/template/no-inline-styles -->\n <span class=\"icon-content\" [style.width.px]=\"iconSize() + 8\" [style.height.px]=\"iconSize() + 8\">\n <ng-container *ngTemplateOutlet=\"svgContent\" />\n </span>\n @if (textRight()) {\n <span class=\"icon-text me-3\">{{ textRight() }}</span>\n }\n</ng-template>\n\n@if (button()) {\n<button [type]=\"type()\" [disabled]=\"disabled()\" class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\" (click)=\"onButtonClick($event)\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</button>\n} @else {\n<span class=\"icon-wrapper\" [class.icon-wrapper-border]=\"border()\" [class.dark-mode]=\"isDarkMode()\">\n <ng-container *ngTemplateOutlet=\"textContent\" />\n</span>\n}"]}
@@ -3,7 +3,6 @@ export const BASE_ICON_COLORS = {
3
3
  secondary: '#6b7280',
4
4
  warn: '#e53935',
5
5
  success: '#4caf50',
6
- dark: '#e9ecef',
7
6
  };
8
7
  export const DISABLED_COLOR = '#bdbdbd';
9
8
  export const DEFAULT_ICON_COLOR = '#222';
@@ -11,6 +10,9 @@ export const DISABLED_OPACITY = 0.5;
11
10
  export const SECONDARY_WARN_OPACITY = 0.7;
12
11
  export const DEFAULT_OPACITY = 1;
13
12
  export const BASE_ICON_SIZE = 24;
13
+ // Colores adaptativos para tema
14
+ export const THEME_LIGHT_COLOR = '#111827'; // --color-text-primary en light mode
15
+ export const THEME_DARK_COLOR = '#f1f5f9'; // --color-text-primary en dark mode
14
16
  // Optimización: Colores que requieren opacidad reducida
15
17
  export const OPACITY_REDUCED_COLORS = ['secondary', 'warn'];
16
18
  // Optimización: Atributos SVG comunes
@@ -1 +1 @@
1
- {"version":3,"file":"icon.constants.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/icon/icon.constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAwC;IACnE,OAAO,EAAE,WAAW;IACpB,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AACxC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,wDAAwD;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAyB,CAAC,WAAW,EAAE,MAAM,CAAU,CAAC;AAE3F,sCAAsC;AACtC,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,OAAO;IACtB,cAAc,EAAE,OAAO;CACf,CAAC","sourcesContent":["import type { ColorType } from './icon.types';\n\nexport const BASE_ICON_COLORS: Readonly<Record<ColorType, string>> = {\n primary: '#003775c8',\n secondary: '#6b7280',\n warn: '#e53935',\n success: '#4caf50',\n dark: '#e9ecef',\n};\n\nexport const DISABLED_COLOR = '#bdbdbd';\nexport const DEFAULT_ICON_COLOR = '#222';\nexport const DISABLED_OPACITY = 0.5;\nexport const SECONDARY_WARN_OPACITY = 0.7;\nexport const DEFAULT_OPACITY = 1;\nexport const BASE_ICON_SIZE = 24;\n\n// Optimización: Colores que requieren opacidad reducida\nexport const OPACITY_REDUCED_COLORS: readonly ColorType[] = ['secondary', 'warn'] as const;\n\n// Optimización: Atributos SVG comunes\nexport const SVG_STROKE_ATTRS = {\n strokeWidth: '1',\n strokeLinecap: 'round',\n strokeLinejoin: 'round'\n} as const;\n"]}
1
+ {"version":3,"file":"icon.constants.js","sourceRoot":"","sources":["../../../../../libs/ui/src/lib/icon/icon.constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAwC;IACnE,OAAO,EAAE,WAAW;IACpB,SAAS,EAAE,SAAS;IACpB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AACxC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAC;AACpC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,CAAC;AAEjC,gCAAgC;AAChC,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAC,CAAC,qCAAqC;AACjF,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC,CAAE,oCAAoC;AAEhF,wDAAwD;AACxD,MAAM,CAAC,MAAM,sBAAsB,GAAyB,CAAC,WAAW,EAAE,MAAM,CAAU,CAAC;AAE3F,sCAAsC;AACtC,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,GAAG;IAChB,aAAa,EAAE,OAAO;IACtB,cAAc,EAAE,OAAO;CACf,CAAC","sourcesContent":["import type { ColorType } from './icon.types';\n\nexport const BASE_ICON_COLORS: Readonly<Record<ColorType, string>> = {\n primary: '#003775c8',\n secondary: '#6b7280',\n warn: '#e53935',\n success: '#4caf50',\n};\n\nexport const DISABLED_COLOR = '#bdbdbd';\nexport const DEFAULT_ICON_COLOR = '#222';\nexport const DISABLED_OPACITY = 0.5;\nexport const SECONDARY_WARN_OPACITY = 0.7;\nexport const DEFAULT_OPACITY = 1;\nexport const BASE_ICON_SIZE = 24;\n\n// Colores adaptativos para tema\nexport const THEME_LIGHT_COLOR = '#111827'; // --color-text-primary en light mode\nexport const THEME_DARK_COLOR = '#f1f5f9'; // --color-text-primary en dark mode\n\n// Optimización: Colores que requieren opacidad reducida\nexport const OPACITY_REDUCED_COLORS: readonly ColorType[] = ['secondary', 'warn'] as const;\n\n// Optimización: Atributos SVG comunes\nexport const SVG_STROKE_ATTRS = {\n strokeWidth: '1',\n strokeLinecap: 'round',\n strokeLinejoin: 'round'\n} as const;\n"]}
@@ -131,7 +131,8 @@ export const ICON_DEFINITIONS = {
131
131
  additionalShapes: [{ type: 'circle', cx: '12', cy: '12', r: '5', fill: 'color' }]
132
132
  },
133
133
  star: {
134
- path: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z'
134
+ path: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z',
135
+ fill: true
135
136
  },
136
137
  xCircle: {
137
138
  path: 'M15 9l-6 6m0-6l6 6',
@@ -151,10 +152,12 @@ export const ICON_DEFINITIONS = {
151
152
  path: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4m4-5l5 5m0 0l5-5m-5 5V3'
152
153
  },
153
154
  shield: {
154
- path: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z'
155
+ path: 'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z',
156
+ fill: true
155
157
  },
156
158
  person: {
157
- path: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z'
159
+ path: 'M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z',
160
+ fill: true
158
161
  },
159
162
  envelope: {
160
163
  path: 'M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z',
@@ -178,7 +181,8 @@ export const ICON_DEFINITIONS = {
178
181
  },
179
182
  people: {
180
183
  path: 'M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3z' +
181
- 'm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z'
184
+ 'm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z',
185
+ fill: true
182
186
  },
183
187
  boxSeam: {
184
188
  path: 'M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z',
@@ -283,11 +287,14 @@ export const ICON_DEFINITIONS = {
283
287
  menu: {
284
288
  path: 'M3 12h18M3 6h18M3 18h18'
285
289
  },
290
+ moreVert: {
291
+ path: 'M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z'
292
+ },
286
293
  arrowLeft: {
287
294
  path: 'm19 12H5m0 0 7 7m-7-7 7-7'
288
295
  },
289
296
  arrowRight: {
290
- path: 'm5 12 7 7m0 0 5-5m-5 5V5'
297
+ path: 'm9 18 6-6-6-6'
291
298
  },
292
299
  copy: {
293
300
  path: 'M8 4v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7.242a2 2 0 0 0-.602-1.43L16.083 2.57A2 2 0 0 0 14.685 2H10a2 2 0 0 0-2 2z',
@@ -344,6 +351,13 @@ export const ICON_DEFINITIONS = {
344
351
  logout: {
345
352
  path: 'M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4m7 14 5-5m0 0-5-5m5 5H9'
346
353
  },
354
+ heart: {
355
+ path: 'M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z'
356
+ },
357
+ user: {
358
+ path: 'M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2',
359
+ additionalShapes: [{ type: 'circle', cx: '12', cy: '7', r: '4' }]
360
+ },
347
361
  sun: {
348
362
  path: 'M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1z' +
349
363
  'M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1z' +