@tinya-code/gas-admin-ui 0.0.0-stage → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +63 -2
  2. package/fesm2022/tinya-code-gas-admin-ui-api.service-CZrUeclM.mjs +281 -0
  3. package/fesm2022/tinya-code-gas-admin-ui-api.service-CZrUeclM.mjs.map +1 -0
  4. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs +84 -0
  5. package/fesm2022/tinya-code-gas-admin-ui-badge-EeCA_l-o.mjs.map +1 -0
  6. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs +140 -0
  7. package/fesm2022/tinya-code-gas-admin-ui-bar-chart-G7sEMSBY.mjs.map +1 -0
  8. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs +113 -0
  9. package/fesm2022/tinya-code-gas-admin-ui-boolean-B2ASKL0E.mjs.map +1 -0
  10. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs +163 -0
  11. package/fesm2022/tinya-code-gas-admin-ui-button-BQjNW8KB.mjs.map +1 -0
  12. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-r-RXDE37.mjs +1022 -0
  13. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-r-RXDE37.mjs.map +1 -0
  14. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs +278 -0
  15. package/fesm2022/tinya-code-gas-admin-ui-chart-line-BjdlKHoH.mjs.map +1 -0
  16. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-BBzWUuHl.mjs +101 -0
  17. package/fesm2022/tinya-code-gas-admin-ui-condition-evaluator-BBzWUuHl.mjs.map +1 -0
  18. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs +141 -0
  19. package/fesm2022/tinya-code-gas-admin-ui-currency-BvuF3Z63.mjs.map +1 -0
  20. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-LD8AM3Rn.mjs +89 -0
  21. package/fesm2022/tinya-code-gas-admin-ui-data-source.service-LD8AM3Rn.mjs.map +1 -0
  22. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs +107 -0
  23. package/fesm2022/tinya-code-gas-admin-ui-date-1SJGXZrd.mjs.map +1 -0
  24. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs +140 -0
  25. package/fesm2022/tinya-code-gas-admin-ui-display-badge-fwk6sDU7.mjs.map +1 -0
  26. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs +119 -0
  27. package/fesm2022/tinya-code-gas-admin-ui-display-date-D7zLiDiG.mjs.map +1 -0
  28. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs +125 -0
  29. package/fesm2022/tinya-code-gas-admin-ui-display-file-BiIhqvQC.mjs.map +1 -0
  30. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs +152 -0
  31. package/fesm2022/tinya-code-gas-admin-ui-display-image-C1dhnZi1.mjs.map +1 -0
  32. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs +211 -0
  33. package/fesm2022/tinya-code-gas-admin-ui-display-list-DOEuUbGe.mjs.map +1 -0
  34. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs +116 -0
  35. package/fesm2022/tinya-code-gas-admin-ui-display-number-DDMzr4Hn.mjs.map +1 -0
  36. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs +111 -0
  37. package/fesm2022/tinya-code-gas-admin-ui-display-text-B8CdVNpv.mjs.map +1 -0
  38. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs +107 -0
  39. package/fesm2022/tinya-code-gas-admin-ui-email-CT_O5ihA.mjs.map +1 -0
  40. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs +109 -0
  41. package/fesm2022/tinya-code-gas-admin-ui-empty-state-BMc0QtoT.mjs.map +1 -0
  42. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-Ci0UpXtV.mjs +45 -0
  43. package/fesm2022/tinya-code-gas-admin-ui-error-mapper.service-Ci0UpXtV.mjs.map +1 -0
  44. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs +50 -0
  45. package/fesm2022/tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs.map +1 -0
  46. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs +24 -0
  47. package/fesm2022/tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs.map +1 -0
  48. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs +27 -0
  49. package/fesm2022/tinya-code-gas-admin-ui-field-path-B4-FTBGZ.mjs.map +1 -0
  50. package/fesm2022/tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs +408 -0
  51. package/fesm2022/tinya-code-gas-admin-ui-file-Dg2N3XQ2.mjs.map +1 -0
  52. package/fesm2022/tinya-code-gas-admin-ui-form-view-BwGupSbi.mjs +4514 -0
  53. package/fesm2022/tinya-code-gas-admin-ui-form-view-BwGupSbi.mjs.map +1 -0
  54. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs +82 -0
  55. package/fesm2022/tinya-code-gas-admin-ui-format-badge-CK8ct5Wk.mjs.map +1 -0
  56. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs +105 -0
  57. package/fesm2022/tinya-code-gas-admin-ui-format-boolean-ClzezZz-.mjs.map +1 -0
  58. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs +65 -0
  59. package/fesm2022/tinya-code-gas-admin-ui-format-currency-CVmniKml.mjs.map +1 -0
  60. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs +65 -0
  61. package/fesm2022/tinya-code-gas-admin-ui-format-date-Dr1YsDd_.mjs.map +1 -0
  62. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs +65 -0
  63. package/fesm2022/tinya-code-gas-admin-ui-format-number-CWCjpI4n.mjs.map +1 -0
  64. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs +59 -0
  65. package/fesm2022/tinya-code-gas-admin-ui-format-text-DBOgJkH0.mjs.map +1 -0
  66. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs +94 -0
  67. package/fesm2022/tinya-code-gas-admin-ui-format-thumbnail-PCRvxWKt.mjs.map +1 -0
  68. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs +72 -0
  69. package/fesm2022/tinya-code-gas-admin-ui-gap-sorting-iTdy_DYG.mjs.map +1 -0
  70. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs +238 -0
  71. package/fesm2022/tinya-code-gas-admin-ui-group-h7-O8tt4.mjs.map +1 -0
  72. package/fesm2022/tinya-code-gas-admin-ui-image-Bjw9ImlS.mjs +416 -0
  73. package/fesm2022/tinya-code-gas-admin-ui-image-Bjw9ImlS.mjs.map +1 -0
  74. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-CeGueI57.mjs +439 -0
  75. package/fesm2022/tinya-code-gas-admin-ui-kanban-view-CeGueI57.mjs.map +1 -0
  76. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs +513 -0
  77. package/fesm2022/tinya-code-gas-admin-ui-key-value-nVdgg5at.mjs.map +1 -0
  78. package/fesm2022/tinya-code-gas-admin-ui-list-CMzl9MkX.mjs +637 -0
  79. package/fesm2022/tinya-code-gas-admin-ui-list-CMzl9MkX.mjs.map +1 -0
  80. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs +127 -0
  81. package/fesm2022/tinya-code-gas-admin-ui-metric-card-DnGMQL8l.mjs.map +1 -0
  82. package/fesm2022/tinya-code-gas-admin-ui-multiselect-CuWwAfdY.mjs +251 -0
  83. package/fesm2022/tinya-code-gas-admin-ui-multiselect-CuWwAfdY.mjs.map +1 -0
  84. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs +66 -0
  85. package/fesm2022/tinya-code-gas-admin-ui-notification.service-LjSULER6.mjs.map +1 -0
  86. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs +114 -0
  87. package/fesm2022/tinya-code-gas-admin-ui-number-JNr7glc8.mjs.map +1 -0
  88. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs +116 -0
  89. package/fesm2022/tinya-code-gas-admin-ui-phone-jR417hPf.mjs.map +1 -0
  90. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs +235 -0
  91. package/fesm2022/tinya-code-gas-admin-ui-quick-actions-DCQ6emmF.mjs.map +1 -0
  92. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs +8 -0
  93. package/fesm2022/tinya-code-gas-admin-ui-radio-mode-DxvN07DY.mjs.map +1 -0
  94. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs +124 -0
  95. package/fesm2022/tinya-code-gas-admin-ui-readonly-text-BL7-4qie.mjs.map +1 -0
  96. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs +249 -0
  97. package/fesm2022/tinya-code-gas-admin-ui-record-list-BiZfnd_7.mjs.map +1 -0
  98. package/fesm2022/tinya-code-gas-admin-ui-relation-B3W3Ynsp.mjs +309 -0
  99. package/fesm2022/tinya-code-gas-admin-ui-relation-B3W3Ynsp.mjs.map +1 -0
  100. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs +39 -0
  101. package/fesm2022/tinya-code-gas-admin-ui-relation-drawer.service-B0kT8EiW.mjs.map +1 -0
  102. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B_D5Jhp9.mjs +546 -0
  103. package/fesm2022/tinya-code-gas-admin-ui-render-registry-B_D5Jhp9.mjs.map +1 -0
  104. package/fesm2022/tinya-code-gas-admin-ui-rolldown-runtime-DpJrqANO.mjs +11 -0
  105. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CDrz9pVN.mjs +131 -0
  106. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CDrz9pVN.mjs.map +1 -0
  107. package/fesm2022/tinya-code-gas-admin-ui-seed-CNbQtREA.mjs +80 -0
  108. package/fesm2022/tinya-code-gas-admin-ui-seed-CNbQtREA.mjs.map +1 -0
  109. package/fesm2022/tinya-code-gas-admin-ui-select-DzaRfHXO.mjs +292 -0
  110. package/fesm2022/tinya-code-gas-admin-ui-select-DzaRfHXO.mjs.map +1 -0
  111. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs +119 -0
  112. package/fesm2022/tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map +1 -0
  113. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs +158 -0
  114. package/fesm2022/tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map +1 -0
  115. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs +26 -0
  116. package/fesm2022/tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map +1 -0
  117. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs +205 -0
  118. package/fesm2022/tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map +1 -0
  119. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs +432 -0
  120. package/fesm2022/tinya-code-gas-admin-ui-string-list-gleasqzD.mjs.map +1 -0
  121. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs +36 -0
  122. package/fesm2022/tinya-code-gas-admin-ui-template-interpolator-ewv7CkNX.mjs.map +1 -0
  123. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs +107 -0
  124. package/fesm2022/tinya-code-gas-admin-ui-text-CUPmL7W_.mjs.map +1 -0
  125. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs +223 -0
  126. package/fesm2022/tinya-code-gas-admin-ui-textarea-CGLSIW13.mjs.map +1 -0
  127. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs +107 -0
  128. package/fesm2022/tinya-code-gas-admin-ui-time-BcHzsTWf.mjs.map +1 -0
  129. package/fesm2022/tinya-code-gas-admin-ui-upload.service-C1g545w5.mjs +60 -0
  130. package/fesm2022/tinya-code-gas-admin-ui-upload.service-C1g545w5.mjs.map +1 -0
  131. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs +141 -0
  132. package/fesm2022/tinya-code-gas-admin-ui-url-GO4LZi__.mjs.map +1 -0
  133. package/fesm2022/tinya-code-gas-admin-ui.mjs +4400 -0
  134. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -0
  135. package/package.json +31 -3
  136. package/types/tinya-code-gas-admin-ui.d.ts +3091 -0
@@ -0,0 +1,119 @@
1
+ import * as i0 from "@angular/core";
2
+ import { Component, computed, input } from "@angular/core";
3
+ var Skeleton = class Skeleton {
4
+ lines = input(1, ...ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []);
5
+ height = input(16, ...ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []);
6
+ width = input("100%", ...ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []);
7
+ lineCount = computed(() => {
8
+ const lines = Math.floor(this.lines());
9
+ const count = Number.isFinite(lines) && lines > 0 ? lines : 1;
10
+ return Array.from({ length: count }, (_, index) => index);
11
+ }, ...ngDevMode ? [{ debugName: "lineCount" }] : /* istanbul ignore next */ []);
12
+ static ɵfac = i0.ɵɵngDeclareFactory({
13
+ minVersion: "12.0.0",
14
+ version: "22.2.3",
15
+ ngImport: i0,
16
+ type: Skeleton,
17
+ deps: [],
18
+ target: i0.ɵɵFactoryTarget.Component
19
+ });
20
+ static ɵcmp = i0.ɵɵngDeclareComponent({
21
+ minVersion: "17.0.0",
22
+ version: "22.2.3",
23
+ type: Skeleton,
24
+ isStandalone: true,
25
+ selector: "app-skeleton",
26
+ inputs: {
27
+ lines: {
28
+ classPropertyName: "lines",
29
+ publicName: "lines",
30
+ isSignal: true,
31
+ isRequired: false,
32
+ transformFunction: null
33
+ },
34
+ height: {
35
+ classPropertyName: "height",
36
+ publicName: "height",
37
+ isSignal: true,
38
+ isRequired: false,
39
+ transformFunction: null
40
+ },
41
+ width: {
42
+ classPropertyName: "width",
43
+ publicName: "width",
44
+ isSignal: true,
45
+ isRequired: false,
46
+ transformFunction: null
47
+ }
48
+ },
49
+ host: {
50
+ attributes: { "aria-hidden": "true" },
51
+ classAttribute: "block space-y-2"
52
+ },
53
+ ngImport: i0,
54
+ template: `
55
+ @for (line of lineCount(); track line) {
56
+ <div
57
+ class="animate-pulse rounded bg-neutral/15"
58
+ [style.height.px]="height()"
59
+ [style.width]="width()"
60
+ ></div>
61
+ }
62
+ `,
63
+ isInline: true
64
+ });
65
+ };
66
+ i0.ɵɵngDeclareClassMetadata({
67
+ minVersion: "12.0.0",
68
+ version: "22.2.3",
69
+ ngImport: i0,
70
+ type: Skeleton,
71
+ decorators: [{
72
+ type: Component,
73
+ args: [{
74
+ selector: "app-skeleton",
75
+ host: {
76
+ class: "block space-y-2",
77
+ "aria-hidden": "true"
78
+ },
79
+ template: `
80
+ @for (line of lineCount(); track line) {
81
+ <div
82
+ class="animate-pulse rounded bg-neutral/15"
83
+ [style.height.px]="height()"
84
+ [style.width]="width()"
85
+ ></div>
86
+ }
87
+ `
88
+ }]
89
+ }],
90
+ propDecorators: {
91
+ lines: [{
92
+ type: i0.Input,
93
+ args: [{
94
+ isSignal: true,
95
+ alias: "lines",
96
+ required: false
97
+ }]
98
+ }],
99
+ height: [{
100
+ type: i0.Input,
101
+ args: [{
102
+ isSignal: true,
103
+ alias: "height",
104
+ required: false
105
+ }]
106
+ }],
107
+ width: [{
108
+ type: i0.Input,
109
+ args: [{
110
+ isSignal: true,
111
+ alias: "width",
112
+ required: false
113
+ }]
114
+ }]
115
+ }
116
+ });
117
+ export { Skeleton as t };
118
+
119
+ //# sourceMappingURL=tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tinya-code-gas-admin-ui-skeleton-DnWK0tcZ.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/shared/components/skeleton/skeleton.ts"],"sourcesContent":["import { Component, computed, input } from '@angular/core';\n\n/**\n * Bloque de carga decorativo: oculto para lectores (`aria-hidden`); la\n * región que lo contiene debe exponer `aria-busy=\"true\"`.\n */\n@Component({\n selector: 'app-skeleton',\n host: { class: 'block space-y-2', 'aria-hidden': 'true' },\n template: `\n @for (line of lineCount(); track line) {\n <div\n class=\"animate-pulse rounded bg-neutral/15\"\n [style.height.px]=\"height()\"\n [style.width]=\"width()\"\n ></div>\n }\n `,\n})\nexport class Skeleton {\n /** Cantidad de barras (mínimo 1). */\n readonly lines = input(1);\n readonly height = input(16);\n readonly width = input('100%');\n\n readonly lineCount = computed(() => {\n const lines = Math.floor(this.lines());\n const count = Number.isFinite(lines) && lines > 0 ? lines : 1;\n return Array.from({ length: count }, (_, index) => index);\n });\n}\n"],"mappings":";;AAmBA,IAAa,WAAb,MAAa,SAAQ;CAEV,QAAQ,MAAM,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAChB,SAAS,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAClB,QAAQ,MAAM,QAAO,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAErB,YAAY,eAAc;EACjC,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAK,CAAE;EACrC,MAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;EAC5D,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAK,IAAK,GAAG,UAAU,KAAK;CAC1D,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAVS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAQ,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAR,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAQ,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA;GAAA,YAAA,EAAA,eAAA,OAAA;GAAA,gBAAA;EAAA;EAAA,UAAA;EAAA,UAVT;;;;;;;;;EAQT,UAAA;CAAA,CAAA;;AAEU,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAQ,YAAA,CAAA;EAbpB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,MAAM;IAAE,OAAO;IAAmB,eAAe;GAAM;GACvD,UAAU;;;;;;;;;EASX,CAAA"}
@@ -0,0 +1,158 @@
1
+ import { n as FieldAria } from "./tinya-code-gas-admin-ui-field-aria-BD1Wiggc.mjs";
2
+ import { t as childTree } from "./tinya-code-gas-admin-ui-field-node-CIK6KNN_.mjs";
3
+ import * as i0 from "@angular/core";
4
+ import { Component, computed, effect, input, signal } from "@angular/core";
5
+ import { FormField } from "@angular/forms/signals";
6
+ function slugify(value) {
7
+ return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
8
+ }
9
+ var FieldSlug = class FieldSlug {
10
+ field = input.required(...ngDevMode ? [{ debugName: "field" }] : /* istanbul ignore next */ []);
11
+ tree = input.required(...ngDevMode ? [{ debugName: "tree" }] : /* istanbul ignore next */ []);
12
+ exists = input(false, ...ngDevMode ? [{ debugName: "exists" }] : /* istanbul ignore next */ []);
13
+ manual = signal(false, ...ngDevMode ? [{ debugName: "manual" }] : /* istanbul ignore next */ []);
14
+ node = computed(() => childTree(this.tree(), this.field().key), ...ngDevMode ? [{ debugName: "node" }] : /* istanbul ignore next */ []);
15
+ state = computed(() => this.node()(), ...ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []);
16
+ locked = computed(() => this.field().lockAfterCreate !== false && this.exists(), ...ngDevMode ? [{ debugName: "locked" }] : /* istanbul ignore next */ []);
17
+ sourceValue = computed(() => childTree(this.tree(), this.field().from)().value(), ...ngDevMode ? [{ debugName: "sourceValue" }] : /* istanbul ignore next */ []);
18
+ constructor() {
19
+ effect(() => {
20
+ if (this.locked() || this.manual()) return;
21
+ this.state().value.set(slugify(String(this.sourceValue() ?? "")));
22
+ });
23
+ }
24
+ static ɵfac = i0.ɵɵngDeclareFactory({
25
+ minVersion: "12.0.0",
26
+ version: "22.2.3",
27
+ ngImport: i0,
28
+ type: FieldSlug,
29
+ deps: [],
30
+ target: i0.ɵɵFactoryTarget.Component
31
+ });
32
+ static ɵcmp = i0.ɵɵngDeclareComponent({
33
+ minVersion: "17.0.0",
34
+ version: "22.2.3",
35
+ type: FieldSlug,
36
+ isStandalone: true,
37
+ selector: "app-field-slug",
38
+ inputs: {
39
+ field: {
40
+ classPropertyName: "field",
41
+ publicName: "field",
42
+ isSignal: true,
43
+ isRequired: true,
44
+ transformFunction: null
45
+ },
46
+ tree: {
47
+ classPropertyName: "tree",
48
+ publicName: "tree",
49
+ isSignal: true,
50
+ isRequired: true,
51
+ transformFunction: null
52
+ },
53
+ exists: {
54
+ classPropertyName: "exists",
55
+ publicName: "exists",
56
+ isSignal: true,
57
+ isRequired: false,
58
+ transformFunction: null
59
+ }
60
+ },
61
+ ngImport: i0,
62
+ template: `
63
+ @if (locked()) {
64
+ <input
65
+ type="text"
66
+ class="field-input"
67
+ [id]="state().name()"
68
+ [value]="state().value()"
69
+ readonly
70
+ />
71
+ } @else {
72
+ <input
73
+ type="text"
74
+ class="field-input"
75
+ [id]="state().name()"
76
+ [formField]="node()"
77
+ [placeholder]="field().placeholder ?? ''"
78
+ (input)="manual.set(true)"
79
+ />
80
+ }
81
+ `,
82
+ isInline: true,
83
+ dependencies: [{
84
+ kind: "directive",
85
+ type: FieldAria,
86
+ selector: "input[id], select[id], textarea[id], output[id]"
87
+ }, {
88
+ kind: "directive",
89
+ type: FormField,
90
+ selector: "[formField]",
91
+ inputs: ["formField"],
92
+ exportAs: ["formField"]
93
+ }]
94
+ });
95
+ };
96
+ i0.ɵɵngDeclareClassMetadata({
97
+ minVersion: "12.0.0",
98
+ version: "22.2.3",
99
+ ngImport: i0,
100
+ type: FieldSlug,
101
+ decorators: [{
102
+ type: Component,
103
+ args: [{
104
+ selector: "app-field-slug",
105
+ imports: [FieldAria, FormField],
106
+ template: `
107
+ @if (locked()) {
108
+ <input
109
+ type="text"
110
+ class="field-input"
111
+ [id]="state().name()"
112
+ [value]="state().value()"
113
+ readonly
114
+ />
115
+ } @else {
116
+ <input
117
+ type="text"
118
+ class="field-input"
119
+ [id]="state().name()"
120
+ [formField]="node()"
121
+ [placeholder]="field().placeholder ?? ''"
122
+ (input)="manual.set(true)"
123
+ />
124
+ }
125
+ `
126
+ }]
127
+ }],
128
+ ctorParameters: () => [],
129
+ propDecorators: {
130
+ field: [{
131
+ type: i0.Input,
132
+ args: [{
133
+ isSignal: true,
134
+ alias: "field",
135
+ required: true
136
+ }]
137
+ }],
138
+ tree: [{
139
+ type: i0.Input,
140
+ args: [{
141
+ isSignal: true,
142
+ alias: "tree",
143
+ required: true
144
+ }]
145
+ }],
146
+ exists: [{
147
+ type: i0.Input,
148
+ args: [{
149
+ isSignal: true,
150
+ alias: "exists",
151
+ required: false
152
+ }]
153
+ }]
154
+ }
155
+ });
156
+ export { FieldSlug };
157
+
158
+ //# sourceMappingURL=tinya-code-gas-admin-ui-slug-DU58cbiY.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tinya-code-gas-admin-ui-slug-DU58cbiY.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/shared/utils/slugify.ts","../../../projects/gas-admin-ui/src/lib/fields/slug/slug.ts"],"sourcesContent":["/**\n * Normaliza texto a slug: minúsculas, sin acentos, separados por guiones.\n * Ej.: `Lomo Saltado Ñoño` → `lomo-saltado-nonio`.\n */\nexport function slugify(value: string): string {\n return value\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n","import { Component, computed, effect, input, signal } from '@angular/core';\nimport { FormField } from '@angular/forms/signals';\n\nimport type { SlugField } from '../../core/models/schema.model';\nimport { slugify } from '../../shared/utils/slugify';\nimport { FieldAria } from '../field-aria';\nimport { childTree, type RootTree } from '../field-node';\n\n/**\n * Slug autogenerado desde otro campo (base.md §5.1). Se regenera mientras el\n * usuario no lo edite a mano; queda bloqueado tras crear el registro si\n * `lockAfterCreate` no es `false`. La rama bloqueada no usa `formField`\n * (atributo `readonly` estático y sin sincronización).\n */\n@Component({\n selector: 'app-field-slug',\n imports: [FieldAria, FormField],\n template: `\n @if (locked()) {\n <input\n type=\"text\"\n class=\"field-input\"\n [id]=\"state().name()\"\n [value]=\"state().value()\"\n readonly\n />\n } @else {\n <input\n type=\"text\"\n class=\"field-input\"\n [id]=\"state().name()\"\n [formField]=\"node()\"\n [placeholder]=\"field().placeholder ?? ''\"\n (input)=\"manual.set(true)\"\n />\n }\n `,\n})\nexport class FieldSlug {\n readonly field = input.required<SlugField>();\n readonly tree = input.required<RootTree>();\n /** Si el registro ya existe (lo informa form-view, Fase 10). */\n readonly exists = input(false);\n\n /** Edición manual del usuario: corta la autogeneración. */\n protected readonly manual = signal(false);\n\n protected readonly node = computed(() => childTree<string>(this.tree(), this.field().key));\n protected readonly state = computed(() => this.node()());\n\n protected readonly locked = computed(\n () => this.field().lockAfterCreate !== false && this.exists(),\n );\n\n private readonly sourceValue = computed(() =>\n childTree<unknown>(this.tree(), this.field().from)().value(),\n );\n\n constructor() {\n effect(() => {\n if (this.locked() || this.manual()) {\n return;\n }\n this.state().value.set(slugify(String(this.sourceValue() ?? '')));\n });\n }\n}\n"],"mappings":";;;;;AAIA,SAAgB,QAAQ,OAAa;CACnC,OAAO,MACJ,UAAU,KAAK,CAAC,CAChB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,YAAW,CAAE,CACb,KAAI,CAAE,CACN,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE;AAC3B;AC0BA,IAAa,YAAb,MAAa,UAAS;CACX,QAAQ,MAAM,SAAqB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACnC,OAAO,MAAM,SAAoB,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAEjC,SAAS,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAGX,SAAS,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAEtB,OAAO,eAAe,UAAkB,KAAK,KAAI,GAAI,KAAK,MAAK,CAAE,CAAC,GAAG,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CACvE,QAAQ,eAAe,KAAK,KAAI,CAAE,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAErC,SAAS,eACpB,KAAK,MAAK,CAAE,CAAC,oBAAoB,SAAS,KAAK,OAAM,GAC5D,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAEgB,cAAc,eAC7B,UAAmB,KAAK,KAAI,GAAI,KAAK,MAAK,CAAE,CAAC,IAAI,CAAC,CAAA,CAAE,CAAC,MAAK,GAC3D,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAED,cAAA;EACE,aAAY;GACV,IAAI,KAAK,OAAM,KAAM,KAAK,OAAM,GAC9B;GAEF,KAAK,MAAK,CAAE,CAAC,MAAM,IAAI,QAAQ,OAAO,KAAK,YAAW,KAAM,EAAE,CAAC,CAAC;EAClE,CAAC;CACH;CA3BW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAS,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAT,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAS,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UArBV;;;;;;;;;;;;;;;;;;;;EAmBT,UAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MApBS;GAAS,UAAA;EAAA,GAAA;GAAA,MAAA;GAAA,MAAE;GAAS,UAAA;GAAA,QAAA,CAAA,WAAA;GAAA,UAAA,CAAA,WAAA;EAAA,CAAA;CAAA,CAAA;;AAsBnB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAS,YAAA,CAAA;EAxBrB,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,SAAS,CAAC,WAAW,SAAS;GAC9B,UAAU;;;;;;;;;;;;;;;;;;;;EAoBX,CAAA"}
@@ -0,0 +1,26 @@
1
+ function optionsFromRows(rows, { source, target, onlyActive, secondaryField }) {
2
+ const valueKey = source.valueField ?? target?.keyField ?? "id";
3
+ const labelKey = source.labelField ?? target?.titleField ?? valueKey;
4
+ const options = [];
5
+ for (const row of rows) {
6
+ if (onlyActive === true && row["active"] === false) continue;
7
+ const value = row[valueKey];
8
+ if (value === void 0 || value === null || value === "") continue;
9
+ const label = row[labelKey];
10
+ const primary = typeof label === "string" && label !== "" ? label : String(value);
11
+ options.push({
12
+ value: String(value),
13
+ label: withSecondary(primary, row, secondaryField)
14
+ });
15
+ }
16
+ return options;
17
+ }
18
+ function withSecondary(primary, row, key) {
19
+ if (key === void 0) return primary;
20
+ const secondary = row[key];
21
+ if (secondary === void 0 || secondary === null || secondary === "") return primary;
22
+ return `${primary} · ${String(secondary)}`;
23
+ }
24
+ export { optionsFromRows as t };
25
+
26
+ //# sourceMappingURL=tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tinya-code-gas-admin-ui-source-options-B9R4mw8-.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/core/utils/source-options.ts"],"sourcesContent":["import type { DataSource, ResourceSchema, SelectOption } from '../models/schema.model';\n\n/** Contexto de mapeo: la fuente declarada más las particularidades del campo. */\nexport interface RowsToOptions {\n /** Fuente de la que salieron las filas (F8 · R6.5). */\n source: DataSource;\n /** Schema del recurso destino: aporta `keyField`/`titleField` por defecto. */\n target: ResourceSchema | undefined;\n /** Descarta filas con `active: false` (`relation.onlyActive`). */\n onlyActive?: boolean;\n /** Dato secundario junto a la etiqueta («Juan Pérez · DNI 123»). */\n secondaryField?: string;\n}\n\n/**\n * Filas de una fuente declarada → opciones de desplegable (F8 · R6.5).\n *\n * Es el ÚNICO punto que traduce filas a `SelectOption`: antes esa regla\n * estaba escrita dos veces (en `relation` y cada consumidor montaba su\n * propia petición). Con `source` compartido, relaciones y desplegables con\n * datos remotos pasan por acá.\n *\n * Reglas, en orden:\n * - valor: `source.valueField` → `target.keyField` → `id`;\n * - etiqueta: `source.labelField` → `target.titleField` → el valor;\n * - fila sin valor (vacío o inexistente) no es opción: no hay qué seleccionar;\n * - `onlyActive` descarta las inactivas en el cliente — el back ya las excluye\n * de su FK, pero una lista cacheada puede traer una fila vieja.\n */\nexport function optionsFromRows(\n rows: readonly Record<string, unknown>[],\n { source, target, onlyActive, secondaryField }: RowsToOptions,\n): SelectOption[] {\n const valueKey = source.valueField ?? target?.keyField ?? 'id';\n const labelKey = source.labelField ?? target?.titleField ?? valueKey;\n const options: SelectOption[] = [];\n for (const row of rows) {\n if (onlyActive === true && row['active'] === false) continue;\n const value = row[valueKey];\n if (value === undefined || value === null || value === '') continue;\n const label = row[labelKey];\n const primary = typeof label === 'string' && label !== '' ? label : String(value);\n options.push({ value: String(value), label: withSecondary(primary, row, secondaryField) });\n }\n return options;\n}\n\n/** Etiqueta con su dato secundario, o la etiqueta tal cual si no hay. */\nfunction withSecondary(primary: string, row: Record<string, unknown>, key?: string): string {\n if (key === undefined) return primary;\n const secondary = row[key];\n if (secondary === undefined || secondary === null || secondary === '') return primary;\n return `${primary} · ${String(secondary)}`;\n}\n"],"mappings":"AA6BA,SAAgB,gBACd,MACA,EAAE,QAAQ,QAAQ,YAAY,kBAA+B;CAE7D,MAAM,WAAW,OAAO,cAAc,QAAQ,YAAY;CAC1D,MAAM,WAAW,OAAO,cAAc,QAAQ,cAAc;CAC5D,MAAM,UAA0B,CAAA;CAChC,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,eAAe,QAAQ,IAAI,cAAc,OAAO;EACpD,MAAM,QAAQ,IAAI;EAClB,IAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;EAC3D,MAAM,QAAQ,IAAI;EAClB,MAAM,UAAU,OAAO,UAAU,YAAY,UAAU,KAAK,QAAQ,OAAO,KAAK;EAChF,QAAQ,KAAK;GAAE,OAAO,OAAO,KAAK;GAAG,OAAO,cAAc,SAAS,KAAK,cAAc;EAAC,CAAE;CAC3F;CACA,OAAO;AACT;AAGA,SAAS,cAAc,SAAiB,KAA8B,KAAY;CAChF,IAAI,QAAQ,QAAW,OAAO;CAC9B,MAAM,YAAY,IAAI;CACtB,IAAI,cAAc,UAAa,cAAc,QAAQ,cAAc,IAAI,OAAO;CAC9E,OAAO,GAAG,QAAO,KAAM,OAAO,SAAS;AACzC"}
@@ -0,0 +1,205 @@
1
+ import * as i0 from "@angular/core";
2
+ import { Component, computed, input } from "@angular/core";
3
+ const COLOR_MAP = {
4
+ success: {
5
+ bar: "bg-emerald-500",
6
+ dot: "bg-emerald-500"
7
+ },
8
+ warning: {
9
+ bar: "bg-amber-500",
10
+ dot: "bg-amber-500"
11
+ },
12
+ danger: {
13
+ bar: "bg-rose-500",
14
+ dot: "bg-rose-500"
15
+ },
16
+ neutral: {
17
+ bar: "bg-neutral/40",
18
+ dot: "bg-neutral/40"
19
+ }
20
+ };
21
+ var StatusProgress = class StatusProgress {
22
+ widget = input.required(...ngDevMode ? [{ debugName: "widget" }] : /* istanbul ignore next */ []);
23
+ data = input(null, ...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
24
+ totalCount = computed(() => {
25
+ const d = this.data() || {};
26
+ return this.widget().segments.reduce((acc, seg) => {
27
+ const val = Number(d[seg.key]);
28
+ return acc + (isNaN(val) ? 0 : Math.max(0, val));
29
+ }, 0);
30
+ }, ...ngDevMode ? [{ debugName: "totalCount" }] : /* istanbul ignore next */ []);
31
+ calculatedSegments = computed(() => {
32
+ const d = this.data() || {};
33
+ const total = this.totalCount();
34
+ return this.widget().segments.map((seg) => {
35
+ const raw = Number(d[seg.key]);
36
+ const value = isNaN(raw) ? 0 : Math.max(0, raw);
37
+ const percentage = total > 0 ? value / total * 100 : 0;
38
+ const colors = COLOR_MAP[seg.color] || COLOR_MAP["neutral"];
39
+ return {
40
+ key: seg.key,
41
+ label: seg.label,
42
+ value,
43
+ percentage,
44
+ barClass: colors.bar,
45
+ dotClass: colors.dot
46
+ };
47
+ });
48
+ }, ...ngDevMode ? [{ debugName: "calculatedSegments" }] : /* istanbul ignore next */ []);
49
+ static ɵfac = i0.ɵɵngDeclareFactory({
50
+ minVersion: "12.0.0",
51
+ version: "22.2.3",
52
+ ngImport: i0,
53
+ type: StatusProgress,
54
+ deps: [],
55
+ target: i0.ɵɵFactoryTarget.Component
56
+ });
57
+ static ɵcmp = i0.ɵɵngDeclareComponent({
58
+ minVersion: "17.0.0",
59
+ version: "22.2.3",
60
+ type: StatusProgress,
61
+ isStandalone: true,
62
+ selector: "app-status-progress",
63
+ inputs: {
64
+ widget: {
65
+ classPropertyName: "widget",
66
+ publicName: "widget",
67
+ isSignal: true,
68
+ isRequired: true,
69
+ transformFunction: null
70
+ },
71
+ data: {
72
+ classPropertyName: "data",
73
+ publicName: "data",
74
+ isSignal: true,
75
+ isRequired: false,
76
+ transformFunction: null
77
+ }
78
+ },
79
+ ngImport: i0,
80
+ template: `
81
+ <article class="flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4">
82
+ <header class="mb-3 flex items-center justify-between">
83
+ <h2 class="text-sm font-semibold text-neutral-light">{{ widget().label }}</h2>
84
+ <span class="text-xs text-neutral" data-testid="total-count">
85
+ Total: {{ totalCount() }}
86
+ </span>
87
+ </header>
88
+
89
+ <!-- Barra segmentada -->
90
+ <div
91
+ class="flex h-3 w-full overflow-hidden rounded-full bg-neutral/10"
92
+ role="progressbar"
93
+ [attr.aria-valuenow]="totalCount()"
94
+ [attr.aria-valuemin]="0"
95
+ [attr.aria-valuemax]="totalCount()"
96
+ [attr.aria-label]="widget().label"
97
+ >
98
+ @if (totalCount() === 0) {
99
+ <div class="h-full w-full bg-neutral/20"></div>
100
+ } @else {
101
+ @for (seg of calculatedSegments(); track seg.key) {
102
+ @if (seg.percentage > 0) {
103
+ <div
104
+ [class]="seg.barClass"
105
+ [style.width.%]="seg.percentage"
106
+ [title]="seg.label + ': ' + seg.value + ' (' + seg.percentage.toFixed(1) + '%)'"
107
+ ></div>
108
+ }
109
+ }
110
+ }
111
+ </div>
112
+
113
+ <!-- Leyenda -->
114
+ <div class="mt-3.5 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
115
+ @for (seg of calculatedSegments(); track seg.key) {
116
+ <div class="flex items-center gap-1.5 text-neutral-light">
117
+ <span class="h-2 w-2 rounded-full" [class]="seg.dotClass"></span>
118
+ <span class="font-medium">{{ seg.label }}:</span>
119
+ <span class="text-neutral">{{ seg.value }} ({{ seg.percentage.toFixed(0) }}%)</span>
120
+ </div>
121
+ }
122
+ </div>
123
+ </article>
124
+ `,
125
+ isInline: true
126
+ });
127
+ };
128
+ i0.ɵɵngDeclareClassMetadata({
129
+ minVersion: "12.0.0",
130
+ version: "22.2.3",
131
+ ngImport: i0,
132
+ type: StatusProgress,
133
+ decorators: [{
134
+ type: Component,
135
+ args: [{
136
+ selector: "app-status-progress",
137
+ template: `
138
+ <article class="flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4">
139
+ <header class="mb-3 flex items-center justify-between">
140
+ <h2 class="text-sm font-semibold text-neutral-light">{{ widget().label }}</h2>
141
+ <span class="text-xs text-neutral" data-testid="total-count">
142
+ Total: {{ totalCount() }}
143
+ </span>
144
+ </header>
145
+
146
+ <!-- Barra segmentada -->
147
+ <div
148
+ class="flex h-3 w-full overflow-hidden rounded-full bg-neutral/10"
149
+ role="progressbar"
150
+ [attr.aria-valuenow]="totalCount()"
151
+ [attr.aria-valuemin]="0"
152
+ [attr.aria-valuemax]="totalCount()"
153
+ [attr.aria-label]="widget().label"
154
+ >
155
+ @if (totalCount() === 0) {
156
+ <div class="h-full w-full bg-neutral/20"></div>
157
+ } @else {
158
+ @for (seg of calculatedSegments(); track seg.key) {
159
+ @if (seg.percentage > 0) {
160
+ <div
161
+ [class]="seg.barClass"
162
+ [style.width.%]="seg.percentage"
163
+ [title]="seg.label + ': ' + seg.value + ' (' + seg.percentage.toFixed(1) + '%)'"
164
+ ></div>
165
+ }
166
+ }
167
+ }
168
+ </div>
169
+
170
+ <!-- Leyenda -->
171
+ <div class="mt-3.5 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs">
172
+ @for (seg of calculatedSegments(); track seg.key) {
173
+ <div class="flex items-center gap-1.5 text-neutral-light">
174
+ <span class="h-2 w-2 rounded-full" [class]="seg.dotClass"></span>
175
+ <span class="font-medium">{{ seg.label }}:</span>
176
+ <span class="text-neutral">{{ seg.value }} ({{ seg.percentage.toFixed(0) }}%)</span>
177
+ </div>
178
+ }
179
+ </div>
180
+ </article>
181
+ `
182
+ }]
183
+ }],
184
+ propDecorators: {
185
+ widget: [{
186
+ type: i0.Input,
187
+ args: [{
188
+ isSignal: true,
189
+ alias: "widget",
190
+ required: true
191
+ }]
192
+ }],
193
+ data: [{
194
+ type: i0.Input,
195
+ args: [{
196
+ isSignal: true,
197
+ alias: "data",
198
+ required: false
199
+ }]
200
+ }]
201
+ }
202
+ });
203
+ export { StatusProgress };
204
+
205
+ //# sourceMappingURL=tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tinya-code-gas-admin-ui-status-progress-DmeG8htE.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/widgets/status-progress/status-progress.ts"],"sourcesContent":["import { Component, computed, input } from '@angular/core';\n\nimport type { StatusProgressWidget } from '../../core/models/schema.model';\n\ninterface SegmentDisplay {\n key: string;\n label: string;\n value: number;\n percentage: number;\n barClass: string;\n dotClass: string;\n}\n\nconst COLOR_MAP: Record<string, { bar: string; dot: string }> = {\n success: { bar: 'bg-emerald-500', dot: 'bg-emerald-500' },\n warning: { bar: 'bg-amber-500', dot: 'bg-amber-500' },\n danger: { bar: 'bg-rose-500', dot: 'bg-rose-500' },\n neutral: { bar: 'bg-neutral/40', dot: 'bg-neutral/40' },\n};\n\n/**\n * Barra de distribución porcentual de estados operativos.\n */\n@Component({\n selector: 'app-status-progress',\n template: `\n <article class=\"flex h-full flex-col rounded-xl border border-neutral/20 bg-surface p-4\">\n <header class=\"mb-3 flex items-center justify-between\">\n <h2 class=\"text-sm font-semibold text-neutral-light\">{{ widget().label }}</h2>\n <span class=\"text-xs text-neutral\" data-testid=\"total-count\">\n Total: {{ totalCount() }}\n </span>\n </header>\n\n <!-- Barra segmentada -->\n <div\n class=\"flex h-3 w-full overflow-hidden rounded-full bg-neutral/10\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"totalCount()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"totalCount()\"\n [attr.aria-label]=\"widget().label\"\n >\n @if (totalCount() === 0) {\n <div class=\"h-full w-full bg-neutral/20\"></div>\n } @else {\n @for (seg of calculatedSegments(); track seg.key) {\n @if (seg.percentage > 0) {\n <div\n [class]=\"seg.barClass\"\n [style.width.%]=\"seg.percentage\"\n [title]=\"seg.label + ': ' + seg.value + ' (' + seg.percentage.toFixed(1) + '%)'\"\n ></div>\n }\n }\n }\n </div>\n\n <!-- Leyenda -->\n <div class=\"mt-3.5 flex flex-wrap items-center gap-x-4 gap-y-2 text-xs\">\n @for (seg of calculatedSegments(); track seg.key) {\n <div class=\"flex items-center gap-1.5 text-neutral-light\">\n <span class=\"h-2 w-2 rounded-full\" [class]=\"seg.dotClass\"></span>\n <span class=\"font-medium\">{{ seg.label }}:</span>\n <span class=\"text-neutral\">{{ seg.value }} ({{ seg.percentage.toFixed(0) }}%)</span>\n </div>\n }\n </div>\n </article>\n `,\n})\nexport class StatusProgress {\n readonly widget = input.required<StatusProgressWidget>();\n readonly data = input<Record<string, unknown> | null>(null);\n\n protected readonly totalCount = computed(() => {\n const d = this.data() || {};\n return this.widget().segments.reduce((acc, seg) => {\n const val = Number(d[seg.key]);\n return acc + (isNaN(val) ? 0 : Math.max(0, val));\n }, 0);\n });\n\n protected readonly calculatedSegments = computed<SegmentDisplay[]>(() => {\n const d = this.data() || {};\n const total = this.totalCount();\n\n return this.widget().segments.map((seg) => {\n const raw = Number(d[seg.key]);\n const value = isNaN(raw) ? 0 : Math.max(0, raw);\n const percentage = total > 0 ? (value / total) * 100 : 0;\n const colors = COLOR_MAP[seg.color] || COLOR_MAP['neutral'];\n\n return {\n key: seg.key,\n label: seg.label,\n value,\n percentage,\n barClass: colors.bar,\n dotClass: colors.dot,\n };\n });\n });\n}\n"],"mappings":";;AAaA,MAAM,YAA0D;CAC9D,SAAS;EAAE,KAAK;EAAkB,KAAK;CAAgB;CACvD,SAAS;EAAE,KAAK;EAAgB,KAAK;CAAc;CACnD,QAAQ;EAAE,KAAK;EAAe,KAAK;CAAa;CAChD,SAAS;EAAE,KAAK;EAAiB,KAAK;CAAe;AACtD;AAqDD,IAAa,iBAAb,MAAa,eAAc;CAChB,SAAS,MAAM,SAAgC,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAC/C,OAAO,MAAsC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAExC,aAAa,eAAc;EAC5C,MAAM,IAAI,KAAK,KAAI,KAAM,CAAA;EACzB,OAAO,KAAK,OAAM,CAAE,CAAC,SAAS,QAAQ,KAAK,QAAO;GAChD,MAAM,MAAM,OAAO,EAAE,IAAI,IAAI;GAC7B,OAAO,OAAO,MAAM,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,GAAG;EAChD,GAAG,CAAC;CACN,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAEiB,qBAAqB,eAAgC;EACtE,MAAM,IAAI,KAAK,KAAI,KAAM,CAAA;EACzB,MAAM,QAAQ,KAAK,WAAU;EAE7B,OAAO,KAAK,OAAM,CAAE,CAAC,SAAS,KAAK,QAAO;GACxC,MAAM,MAAM,OAAO,EAAE,IAAI,IAAI;GAC7B,MAAM,QAAQ,MAAM,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,GAAG;GAC9C,MAAM,aAAa,QAAQ,IAAK,QAAQ,QAAS,MAAM;GACvD,MAAM,SAAS,UAAU,IAAI,UAAU,UAAU;GAEjD,OAAO;IACL,KAAK,IAAI;IACT,OAAO,IAAI;IACX;IACA;IACA,UAAU,OAAO;IACjB,UAAU,OAAO;GAClB;EACH,CAAC;CACH,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,qBAAA,CAAA,+BAAA,CAAA,CAAA;CA/BS,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAd,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAc,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,UAAA;EAAA,UA9Cf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CT,UAAA;CAAA,CAAA;;AAEU,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAc,YAAA,CAAA;EAhD1B,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6CX,CAAA"}