@neural-ui/core 1.2.0 → 1.3.0

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 (239) hide show
  1. package/README.md +56 -88
  2. package/accordion/package.json +4 -0
  3. package/alert/package.json +4 -0
  4. package/autocomplete/package.json +4 -0
  5. package/avatar/package.json +4 -0
  6. package/badge/package.json +4 -0
  7. package/block-ui/package.json +4 -0
  8. package/breadcrumb/package.json +4 -0
  9. package/button/package.json +4 -0
  10. package/card/package.json +4 -0
  11. package/chart/package.json +4 -0
  12. package/checkbox/package.json +4 -0
  13. package/chip/package.json +4 -0
  14. package/code-block/package.json +4 -0
  15. package/color-picker/package.json +4 -0
  16. package/command-palette/package.json +4 -0
  17. package/confirm-dialog/package.json +4 -0
  18. package/context-menu/package.json +4 -0
  19. package/dashboard-grid/package.json +4 -0
  20. package/date-input/package.json +4 -0
  21. package/divider/package.json +4 -0
  22. package/empty-state/package.json +4 -0
  23. package/fesm2022/neural-ui-core-accordion.mjs +162 -0
  24. package/fesm2022/neural-ui-core-accordion.mjs.map +1 -0
  25. package/fesm2022/neural-ui-core-alert.mjs +116 -0
  26. package/fesm2022/neural-ui-core-alert.mjs.map +1 -0
  27. package/fesm2022/neural-ui-core-autocomplete.mjs +332 -0
  28. package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -0
  29. package/fesm2022/neural-ui-core-avatar.mjs +109 -0
  30. package/fesm2022/neural-ui-core-avatar.mjs.map +1 -0
  31. package/fesm2022/neural-ui-core-badge.mjs +54 -0
  32. package/fesm2022/neural-ui-core-badge.mjs.map +1 -0
  33. package/fesm2022/neural-ui-core-block-ui.mjs +95 -0
  34. package/fesm2022/neural-ui-core-block-ui.mjs.map +1 -0
  35. package/fesm2022/neural-ui-core-breadcrumb.mjs +84 -0
  36. package/fesm2022/neural-ui-core-breadcrumb.mjs.map +1 -0
  37. package/fesm2022/neural-ui-core-button.mjs +125 -0
  38. package/fesm2022/neural-ui-core-button.mjs.map +1 -0
  39. package/fesm2022/neural-ui-core-card.mjs +69 -0
  40. package/fesm2022/neural-ui-core-card.mjs.map +1 -0
  41. package/fesm2022/neural-ui-core-chart.mjs +287 -0
  42. package/fesm2022/neural-ui-core-chart.mjs.map +1 -0
  43. package/fesm2022/neural-ui-core-checkbox.mjs +138 -0
  44. package/fesm2022/neural-ui-core-checkbox.mjs.map +1 -0
  45. package/fesm2022/neural-ui-core-chip.mjs +130 -0
  46. package/fesm2022/neural-ui-core-chip.mjs.map +1 -0
  47. package/fesm2022/neural-ui-core-code-block.mjs +250 -0
  48. package/fesm2022/neural-ui-core-code-block.mjs.map +1 -0
  49. package/fesm2022/neural-ui-core-color-picker.mjs +435 -0
  50. package/fesm2022/neural-ui-core-color-picker.mjs.map +1 -0
  51. package/fesm2022/neural-ui-core-command-palette.mjs +235 -0
  52. package/fesm2022/neural-ui-core-command-palette.mjs.map +1 -0
  53. package/fesm2022/neural-ui-core-confirm-dialog.mjs +118 -0
  54. package/fesm2022/neural-ui-core-confirm-dialog.mjs.map +1 -0
  55. package/fesm2022/neural-ui-core-context-menu.mjs +158 -0
  56. package/fesm2022/neural-ui-core-context-menu.mjs.map +1 -0
  57. package/fesm2022/neural-ui-core-dashboard-grid.mjs +144 -0
  58. package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -0
  59. package/fesm2022/neural-ui-core-date-input.mjs +1332 -0
  60. package/fesm2022/neural-ui-core-date-input.mjs.map +1 -0
  61. package/fesm2022/neural-ui-core-divider.mjs +54 -0
  62. package/fesm2022/neural-ui-core-divider.mjs.map +1 -0
  63. package/fesm2022/neural-ui-core-empty-state.mjs +84 -0
  64. package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -0
  65. package/fesm2022/neural-ui-core-filter-bar.mjs +118 -0
  66. package/fesm2022/neural-ui-core-filter-bar.mjs.map +1 -0
  67. package/fesm2022/neural-ui-core-icon.mjs +50 -0
  68. package/fesm2022/neural-ui-core-icon.mjs.map +1 -0
  69. package/fesm2022/neural-ui-core-image-viewer.mjs +309 -0
  70. package/fesm2022/neural-ui-core-image-viewer.mjs.map +1 -0
  71. package/fesm2022/neural-ui-core-input-otp.mjs +192 -0
  72. package/fesm2022/neural-ui-core-input-otp.mjs.map +1 -0
  73. package/fesm2022/neural-ui-core-input.mjs +320 -0
  74. package/fesm2022/neural-ui-core-input.mjs.map +1 -0
  75. package/fesm2022/neural-ui-core-knob.mjs +323 -0
  76. package/fesm2022/neural-ui-core-knob.mjs.map +1 -0
  77. package/fesm2022/neural-ui-core-meter-group.mjs +122 -0
  78. package/fesm2022/neural-ui-core-meter-group.mjs.map +1 -0
  79. package/fesm2022/neural-ui-core-modal.mjs +156 -0
  80. package/fesm2022/neural-ui-core-modal.mjs.map +1 -0
  81. package/fesm2022/neural-ui-core-multiselect.mjs +748 -0
  82. package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -0
  83. package/fesm2022/neural-ui-core-nav.mjs +952 -0
  84. package/fesm2022/neural-ui-core-nav.mjs.map +1 -0
  85. package/fesm2022/neural-ui-core-notification-center.mjs +264 -0
  86. package/fesm2022/neural-ui-core-notification-center.mjs.map +1 -0
  87. package/fesm2022/neural-ui-core-number-input.mjs +331 -0
  88. package/fesm2022/neural-ui-core-number-input.mjs.map +1 -0
  89. package/fesm2022/neural-ui-core-pagination.mjs +198 -0
  90. package/fesm2022/neural-ui-core-pagination.mjs.map +1 -0
  91. package/fesm2022/neural-ui-core-popover.mjs +207 -0
  92. package/fesm2022/neural-ui-core-popover.mjs.map +1 -0
  93. package/fesm2022/neural-ui-core-progress-bar.mjs +105 -0
  94. package/fesm2022/neural-ui-core-progress-bar.mjs.map +1 -0
  95. package/fesm2022/neural-ui-core-radio.mjs +171 -0
  96. package/fesm2022/neural-ui-core-radio.mjs.map +1 -0
  97. package/fesm2022/neural-ui-core-rating.mjs +151 -0
  98. package/fesm2022/neural-ui-core-rating.mjs.map +1 -0
  99. package/fesm2022/neural-ui-core-select.mjs +638 -0
  100. package/fesm2022/neural-ui-core-select.mjs.map +1 -0
  101. package/fesm2022/neural-ui-core-sidebar.mjs +214 -0
  102. package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -0
  103. package/fesm2022/neural-ui-core-skeleton.mjs +40 -0
  104. package/fesm2022/neural-ui-core-skeleton.mjs.map +1 -0
  105. package/fesm2022/neural-ui-core-slider.mjs +146 -0
  106. package/fesm2022/neural-ui-core-slider.mjs.map +1 -0
  107. package/fesm2022/neural-ui-core-spinner.mjs +113 -0
  108. package/fesm2022/neural-ui-core-spinner.mjs.map +1 -0
  109. package/fesm2022/neural-ui-core-split-button.mjs +252 -0
  110. package/fesm2022/neural-ui-core-split-button.mjs.map +1 -0
  111. package/fesm2022/neural-ui-core-splitter.mjs +174 -0
  112. package/fesm2022/neural-ui-core-splitter.mjs.map +1 -0
  113. package/fesm2022/neural-ui-core-stats-card.mjs +163 -0
  114. package/fesm2022/neural-ui-core-stats-card.mjs.map +1 -0
  115. package/fesm2022/neural-ui-core-stepper.mjs +204 -0
  116. package/fesm2022/neural-ui-core-stepper.mjs.map +1 -0
  117. package/fesm2022/neural-ui-core-switch.mjs +111 -0
  118. package/fesm2022/neural-ui-core-switch.mjs.map +1 -0
  119. package/fesm2022/neural-ui-core-table.mjs +1860 -0
  120. package/fesm2022/neural-ui-core-table.mjs.map +1 -0
  121. package/fesm2022/neural-ui-core-tabs.mjs +246 -0
  122. package/fesm2022/neural-ui-core-tabs.mjs.map +1 -0
  123. package/fesm2022/neural-ui-core-textarea.mjs +188 -0
  124. package/fesm2022/neural-ui-core-textarea.mjs.map +1 -0
  125. package/fesm2022/neural-ui-core-timeline.mjs +117 -0
  126. package/fesm2022/neural-ui-core-timeline.mjs.map +1 -0
  127. package/fesm2022/neural-ui-core-toast.mjs +171 -0
  128. package/fesm2022/neural-ui-core-toast.mjs.map +1 -0
  129. package/fesm2022/neural-ui-core-toggle-button-group.mjs +162 -0
  130. package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -0
  131. package/fesm2022/neural-ui-core-toolbar.mjs +67 -0
  132. package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -0
  133. package/fesm2022/neural-ui-core-tooltip.mjs +151 -0
  134. package/fesm2022/neural-ui-core-tooltip.mjs.map +1 -0
  135. package/fesm2022/neural-ui-core-url-state.mjs +96 -0
  136. package/fesm2022/neural-ui-core-url-state.mjs.map +1 -0
  137. package/fesm2022/neural-ui-core-virtual-list.mjs +126 -0
  138. package/fesm2022/neural-ui-core-virtual-list.mjs.map +1 -0
  139. package/fesm2022/neural-ui-core.mjs +11 -8544
  140. package/fesm2022/neural-ui-core.mjs.map +1 -1
  141. package/filter-bar/package.json +4 -0
  142. package/icon/package.json +4 -0
  143. package/image-viewer/package.json +4 -0
  144. package/input/package.json +4 -0
  145. package/input-otp/package.json +4 -0
  146. package/knob/package.json +4 -0
  147. package/meter-group/package.json +4 -0
  148. package/modal/package.json +4 -0
  149. package/multiselect/package.json +4 -0
  150. package/nav/package.json +4 -0
  151. package/notification-center/package.json +4 -0
  152. package/number-input/package.json +4 -0
  153. package/package.json +252 -5
  154. package/pagination/package.json +4 -0
  155. package/popover/package.json +4 -0
  156. package/progress-bar/package.json +4 -0
  157. package/radio/package.json +4 -0
  158. package/rating/package.json +4 -0
  159. package/select/package.json +4 -0
  160. package/sidebar/package.json +4 -0
  161. package/skeleton/package.json +4 -0
  162. package/slider/package.json +4 -0
  163. package/spinner/package.json +4 -0
  164. package/split-button/package.json +4 -0
  165. package/splitter/package.json +4 -0
  166. package/stats-card/package.json +4 -0
  167. package/stepper/package.json +4 -0
  168. package/styles/_tokens.scss +209 -7
  169. package/styles.scss +1 -0
  170. package/switch/package.json +4 -0
  171. package/table/package.json +4 -0
  172. package/tabs/package.json +4 -0
  173. package/textarea/package.json +4 -0
  174. package/timeline/package.json +4 -0
  175. package/toast/package.json +4 -0
  176. package/toggle-button-group/package.json +4 -0
  177. package/toolbar/package.json +4 -0
  178. package/tooltip/package.json +4 -0
  179. package/types/neural-ui-core-accordion.d.ts +55 -0
  180. package/types/neural-ui-core-alert.d.ts +47 -0
  181. package/types/neural-ui-core-autocomplete.d.ts +69 -0
  182. package/types/neural-ui-core-avatar.d.ts +39 -0
  183. package/types/neural-ui-core-badge.d.ts +36 -0
  184. package/types/neural-ui-core-block-ui.d.ts +46 -0
  185. package/types/neural-ui-core-breadcrumb.d.ts +38 -0
  186. package/types/neural-ui-core-button.d.ts +55 -0
  187. package/types/neural-ui-core-card.d.ts +37 -0
  188. package/types/neural-ui-core-chart.d.ts +236 -0
  189. package/types/neural-ui-core-checkbox.d.ts +33 -0
  190. package/types/neural-ui-core-chip.d.ts +53 -0
  191. package/types/neural-ui-core-code-block.d.ts +55 -0
  192. package/types/neural-ui-core-color-picker.d.ts +55 -0
  193. package/types/neural-ui-core-command-palette.d.ts +56 -0
  194. package/types/neural-ui-core-confirm-dialog.d.ts +50 -0
  195. package/types/neural-ui-core-context-menu.d.ts +66 -0
  196. package/types/neural-ui-core-dashboard-grid.d.ts +41 -0
  197. package/types/neural-ui-core-date-input.d.ts +178 -0
  198. package/types/neural-ui-core-divider.d.ts +20 -0
  199. package/types/neural-ui-core-empty-state.d.ts +32 -0
  200. package/types/neural-ui-core-filter-bar.d.ts +49 -0
  201. package/types/neural-ui-core-icon.d.ts +33 -0
  202. package/types/neural-ui-core-image-viewer.d.ts +67 -0
  203. package/types/neural-ui-core-input-otp.d.ts +49 -0
  204. package/types/neural-ui-core-input.d.ts +86 -0
  205. package/types/neural-ui-core-knob.d.ts +68 -0
  206. package/types/neural-ui-core-meter-group.d.ts +52 -0
  207. package/types/neural-ui-core-modal.d.ts +54 -0
  208. package/types/neural-ui-core-multiselect.d.ts +129 -0
  209. package/types/neural-ui-core-nav.d.ts +69 -0
  210. package/types/neural-ui-core-notification-center.d.ts +60 -0
  211. package/types/neural-ui-core-number-input.d.ts +63 -0
  212. package/types/neural-ui-core-pagination.d.ts +30 -0
  213. package/types/neural-ui-core-popover.d.ts +73 -0
  214. package/types/neural-ui-core-progress-bar.d.ts +35 -0
  215. package/types/neural-ui-core-radio.d.ts +51 -0
  216. package/types/neural-ui-core-rating.d.ts +34 -0
  217. package/types/neural-ui-core-select.d.ts +161 -0
  218. package/types/neural-ui-core-sidebar.d.ts +57 -0
  219. package/types/neural-ui-core-skeleton.d.ts +22 -0
  220. package/types/neural-ui-core-slider.d.ts +42 -0
  221. package/types/neural-ui-core-spinner.d.ts +38 -0
  222. package/types/neural-ui-core-split-button.d.ts +65 -0
  223. package/types/neural-ui-core-splitter.d.ts +28 -0
  224. package/types/neural-ui-core-stats-card.d.ts +39 -0
  225. package/types/neural-ui-core-stepper.d.ts +51 -0
  226. package/types/neural-ui-core-switch.d.ts +34 -0
  227. package/types/neural-ui-core-table.d.ts +282 -0
  228. package/types/neural-ui-core-tabs.d.ts +76 -0
  229. package/types/neural-ui-core-textarea.d.ts +52 -0
  230. package/types/neural-ui-core-timeline.d.ts +33 -0
  231. package/types/neural-ui-core-toast.d.ts +70 -0
  232. package/types/neural-ui-core-toggle-button-group.d.ts +63 -0
  233. package/types/neural-ui-core-toolbar.d.ts +36 -0
  234. package/types/neural-ui-core-tooltip.d.ts +48 -0
  235. package/types/neural-ui-core-url-state.d.ts +58 -0
  236. package/types/neural-ui-core-virtual-list.d.ts +60 -0
  237. package/types/neural-ui-core.d.ts +5 -2107
  238. package/url-state/package.json +4 -0
  239. package/virtual-list/package.json +4 -0
@@ -0,0 +1,163 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { NeuIconComponent } from '@neural-ui/core/icon';
4
+
5
+ /**
6
+ * NeuStatsCard — Card de métrica con título, valor, tendencia y sparkline.
7
+ *
8
+ * Uso:
9
+ * <neu-stats-card
10
+ * title="Ingresos"
11
+ * value="$12,450"
12
+ * change="+12.5%"
13
+ * trend="up"
14
+ * icon="lucideDollarSign"
15
+ * [sparkData]="[30,45,38,52,60,55,70]"
16
+ * />
17
+ */
18
+ class NeuStatsCardComponent {
19
+ /** Título o etiqueta de la métrica. / Metric title or label. */
20
+ title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
21
+ /** Valor principal formateado (p.ej. "$12,450" o "98.2%"). / Main formatted value (e.g. "$12,450" or "98.2%"). */
22
+ value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
23
+ /** Cambio porcentual o absoluto (p.ej. "+12.5%" o "-3"). / Percentage or absolute change (e.g. "+12.5%" or "-3"). */
24
+ change = input('', ...(ngDevMode ? [{ debugName: "change" }] : /* istanbul ignore next */ []));
25
+ /** Dirección del cambio. Afecta el color del change. / Change direction. Affects the change color. */
26
+ trend = input('neutral', ...(ngDevMode ? [{ debugName: "trend" }] : /* istanbul ignore next */ []));
27
+ /** Texto auxiliar bajo el cambio (p.ej. "vs. mes anterior"). / Auxiliary text below the change (e.g. "vs. previous month"). */
28
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
29
+ /** Nombre del icono Lucide para el encabezado. / Lucide icon name for the header. */
30
+ icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
31
+ /** Array de valores numéricos para la sparkline. Mín. 2 puntos. / Array of numeric values for the sparkline. Min. 2 points. */
32
+ sparkData = input([], ...(ngDevMode ? [{ debugName: "sparkData" }] : /* istanbul ignore next */ []));
33
+ /** @internal Genera los puntos SVG de la sparkline / Generates the SVG sparkline points */
34
+ sparkPoints = computed(() => {
35
+ const data = this.sparkData();
36
+ if (data.length < 2)
37
+ return '';
38
+ const min = Math.min(...data);
39
+ const max = Math.max(...data);
40
+ const range = max - min || 1;
41
+ const step = 100 / (data.length - 1);
42
+ return data
43
+ .map((v, i) => `${(i * step).toFixed(1)},${(30 - ((v - min) / range) * 25 + 2.5).toFixed(1)}`)
44
+ .join(' ');
45
+ }, ...(ngDevMode ? [{ debugName: "sparkPoints" }] : /* istanbul ignore next */ []));
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuStatsCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
47
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuStatsCardComponent, isStandalone: true, selector: "neu-stats-card", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, change: { classPropertyName: "change", publicName: "change", isSignal: true, isRequired: false, transformFunction: null }, trend: { classPropertyName: "trend", publicName: "trend", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, sparkData: { classPropertyName: "sparkData", publicName: "sparkData", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "neu-stats-card" }, ngImport: i0, template: `
48
+ <div class="neu-stats-card__inner">
49
+ <!-- Header: icono + título -->
50
+ <div class="neu-stats-card__header">
51
+ @if (icon()) {
52
+ <span class="neu-stats-card__icon">
53
+ <neu-icon [name]="icon()" size="1.125rem" />
54
+ </span>
55
+ }
56
+ <span class="neu-stats-card__title">{{ title() }}</span>
57
+ </div>
58
+
59
+ <!-- Valor principal -->
60
+ <div class="neu-stats-card__value">{{ value() }}</div>
61
+
62
+ <!-- Footer: cambio + sparkline -->
63
+ <div class="neu-stats-card__footer">
64
+ @if (change()) {
65
+ <span class="neu-stats-card__change neu-stats-card__change--{{ trend() }}">
66
+ @if (trend() === 'up') {
67
+ <neu-icon name="lucideTrendingUp" size="0.875rem" />
68
+ } @else if (trend() === 'down') {
69
+ <neu-icon name="lucideTrendingDown" size="0.875rem" />
70
+ } @else {
71
+ <neu-icon name="lucideMinus" size="0.875rem" />
72
+ }
73
+ {{ change() }}
74
+ </span>
75
+ }
76
+ @if (label()) {
77
+ <span class="neu-stats-card__label">{{ label() }}</span>
78
+ }
79
+
80
+ @if (sparkData().length > 1) {
81
+ <svg
82
+ class="neu-stats-card__sparkline"
83
+ viewBox="0 0 100 30"
84
+ preserveAspectRatio="none"
85
+ aria-hidden="true"
86
+ >
87
+ <polyline
88
+ class="neu-stats-card__spark-line"
89
+ [attr.points]="sparkPoints()"
90
+ fill="none"
91
+ stroke-width="1.5"
92
+ stroke-linecap="round"
93
+ stroke-linejoin="round"
94
+ />
95
+ </svg>
96
+ }
97
+ </div>
98
+ </div>
99
+ `, isInline: true, styles: [".neu-stats-card{display:block}.neu-stats-card__inner{background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:var(--neu-radius-lg, 16px);padding:var(--neu-space-5, 1.25rem);display:flex;flex-direction:column;gap:var(--neu-space-3, .75rem);transition:box-shadow var(--neu-transition)}.neu-stats-card__inner:hover{box-shadow:var(--neu-shadow-sm)}.neu-stats-card__header{display:flex;align-items:center;gap:var(--neu-space-2, .5rem)}.neu-stats-card__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:var(--neu-radius, 8px);background:var(--neu-primary-50, #eff6ff);color:var(--neu-primary);flex-shrink:0}.neu-stats-card__title{font-size:var(--neu-text-sm, .875rem);font-weight:500;color:var(--neu-text-muted);line-height:1.3}.neu-stats-card__value{font-size:var(--neu-text-2xl, 1.5rem);font-weight:700;color:var(--neu-text);letter-spacing:-.03em;line-height:1.1;font-family:var(--neu-font-sans)}.neu-stats-card__footer{display:flex;align-items:center;gap:var(--neu-space-2, .5rem);margin-top:auto}.neu-stats-card__change{display:inline-flex;align-items:center;gap:3px;font-size:var(--neu-text-xs, .75rem);font-weight:600;padding:2px 6px;border-radius:var(--neu-radius-full, 999px)}.neu-stats-card__change--up{background:#dcfce7;color:#15803d}.neu-stats-card__change--down{background:#fee2e2;color:#b91c1c}.neu-stats-card__change--neutral{background:var(--neu-surface-2, #f8fafc);color:var(--neu-text-muted)}.neu-stats-card__label{font-size:var(--neu-text-xs, .75rem);color:var(--neu-text-muted)}.neu-stats-card__sparkline{margin-left:auto;width:80px;height:30px;flex-shrink:0}.neu-stats-card__spark-line{stroke:var(--neu-primary);opacity:.8}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
100
+ }
101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuStatsCardComponent, decorators: [{
102
+ type: Component,
103
+ args: [{ selector: 'neu-stats-card', imports: [NeuIconComponent], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-stats-card' }, template: `
104
+ <div class="neu-stats-card__inner">
105
+ <!-- Header: icono + título -->
106
+ <div class="neu-stats-card__header">
107
+ @if (icon()) {
108
+ <span class="neu-stats-card__icon">
109
+ <neu-icon [name]="icon()" size="1.125rem" />
110
+ </span>
111
+ }
112
+ <span class="neu-stats-card__title">{{ title() }}</span>
113
+ </div>
114
+
115
+ <!-- Valor principal -->
116
+ <div class="neu-stats-card__value">{{ value() }}</div>
117
+
118
+ <!-- Footer: cambio + sparkline -->
119
+ <div class="neu-stats-card__footer">
120
+ @if (change()) {
121
+ <span class="neu-stats-card__change neu-stats-card__change--{{ trend() }}">
122
+ @if (trend() === 'up') {
123
+ <neu-icon name="lucideTrendingUp" size="0.875rem" />
124
+ } @else if (trend() === 'down') {
125
+ <neu-icon name="lucideTrendingDown" size="0.875rem" />
126
+ } @else {
127
+ <neu-icon name="lucideMinus" size="0.875rem" />
128
+ }
129
+ {{ change() }}
130
+ </span>
131
+ }
132
+ @if (label()) {
133
+ <span class="neu-stats-card__label">{{ label() }}</span>
134
+ }
135
+
136
+ @if (sparkData().length > 1) {
137
+ <svg
138
+ class="neu-stats-card__sparkline"
139
+ viewBox="0 0 100 30"
140
+ preserveAspectRatio="none"
141
+ aria-hidden="true"
142
+ >
143
+ <polyline
144
+ class="neu-stats-card__spark-line"
145
+ [attr.points]="sparkPoints()"
146
+ fill="none"
147
+ stroke-width="1.5"
148
+ stroke-linecap="round"
149
+ stroke-linejoin="round"
150
+ />
151
+ </svg>
152
+ }
153
+ </div>
154
+ </div>
155
+ `, styles: [".neu-stats-card{display:block}.neu-stats-card__inner{background:var(--neu-surface);border:1px solid var(--neu-border);border-radius:var(--neu-radius-lg, 16px);padding:var(--neu-space-5, 1.25rem);display:flex;flex-direction:column;gap:var(--neu-space-3, .75rem);transition:box-shadow var(--neu-transition)}.neu-stats-card__inner:hover{box-shadow:var(--neu-shadow-sm)}.neu-stats-card__header{display:flex;align-items:center;gap:var(--neu-space-2, .5rem)}.neu-stats-card__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:var(--neu-radius, 8px);background:var(--neu-primary-50, #eff6ff);color:var(--neu-primary);flex-shrink:0}.neu-stats-card__title{font-size:var(--neu-text-sm, .875rem);font-weight:500;color:var(--neu-text-muted);line-height:1.3}.neu-stats-card__value{font-size:var(--neu-text-2xl, 1.5rem);font-weight:700;color:var(--neu-text);letter-spacing:-.03em;line-height:1.1;font-family:var(--neu-font-sans)}.neu-stats-card__footer{display:flex;align-items:center;gap:var(--neu-space-2, .5rem);margin-top:auto}.neu-stats-card__change{display:inline-flex;align-items:center;gap:3px;font-size:var(--neu-text-xs, .75rem);font-weight:600;padding:2px 6px;border-radius:var(--neu-radius-full, 999px)}.neu-stats-card__change--up{background:#dcfce7;color:#15803d}.neu-stats-card__change--down{background:#fee2e2;color:#b91c1c}.neu-stats-card__change--neutral{background:var(--neu-surface-2, #f8fafc);color:var(--neu-text-muted)}.neu-stats-card__label{font-size:var(--neu-text-xs, .75rem);color:var(--neu-text-muted)}.neu-stats-card__sparkline{margin-left:auto;width:80px;height:30px;flex-shrink:0}.neu-stats-card__spark-line{stroke:var(--neu-primary);opacity:.8}\n"] }]
156
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], change: [{ type: i0.Input, args: [{ isSignal: true, alias: "change", required: false }] }], trend: [{ type: i0.Input, args: [{ isSignal: true, alias: "trend", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], sparkData: [{ type: i0.Input, args: [{ isSignal: true, alias: "sparkData", required: false }] }] } });
157
+
158
+ /**
159
+ * Generated bundle index. Do not edit.
160
+ */
161
+
162
+ export { NeuStatsCardComponent };
163
+ //# sourceMappingURL=neural-ui-core-stats-card.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-stats-card.mjs","sources":["../../../../projects/ui-core/stats-card/neu-stats-card.component.ts","../../../../projects/ui-core/stats-card/neural-ui-core-stats-card.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n} from '@angular/core';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nexport type NeuStatsTrend = 'up' | 'down' | 'neutral';\n\n/**\n * NeuStatsCard — Card de métrica con título, valor, tendencia y sparkline.\n *\n * Uso:\n * <neu-stats-card\n * title=\"Ingresos\"\n * value=\"$12,450\"\n * change=\"+12.5%\"\n * trend=\"up\"\n * icon=\"lucideDollarSign\"\n * [sparkData]=\"[30,45,38,52,60,55,70]\"\n * />\n */\n@Component({\n selector: 'neu-stats-card',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-stats-card' },\n template: `\n <div class=\"neu-stats-card__inner\">\n <!-- Header: icono + título -->\n <div class=\"neu-stats-card__header\">\n @if (icon()) {\n <span class=\"neu-stats-card__icon\">\n <neu-icon [name]=\"icon()\" size=\"1.125rem\" />\n </span>\n }\n <span class=\"neu-stats-card__title\">{{ title() }}</span>\n </div>\n\n <!-- Valor principal -->\n <div class=\"neu-stats-card__value\">{{ value() }}</div>\n\n <!-- Footer: cambio + sparkline -->\n <div class=\"neu-stats-card__footer\">\n @if (change()) {\n <span class=\"neu-stats-card__change neu-stats-card__change--{{ trend() }}\">\n @if (trend() === 'up') {\n <neu-icon name=\"lucideTrendingUp\" size=\"0.875rem\" />\n } @else if (trend() === 'down') {\n <neu-icon name=\"lucideTrendingDown\" size=\"0.875rem\" />\n } @else {\n <neu-icon name=\"lucideMinus\" size=\"0.875rem\" />\n }\n {{ change() }}\n </span>\n }\n @if (label()) {\n <span class=\"neu-stats-card__label\">{{ label() }}</span>\n }\n\n @if (sparkData().length > 1) {\n <svg\n class=\"neu-stats-card__sparkline\"\n viewBox=\"0 0 100 30\"\n preserveAspectRatio=\"none\"\n aria-hidden=\"true\"\n >\n <polyline\n class=\"neu-stats-card__spark-line\"\n [attr.points]=\"sparkPoints()\"\n fill=\"none\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n }\n </div>\n </div>\n `,\n styleUrl: './neu-stats-card.component.scss',\n})\nexport class NeuStatsCardComponent {\n /** Título o etiqueta de la métrica. / Metric title or label. */\n title = input<string>('');\n /** Valor principal formateado (p.ej. \"$12,450\" o \"98.2%\"). / Main formatted value (e.g. \"$12,450\" or \"98.2%\"). */\n value = input<string>('');\n /** Cambio porcentual o absoluto (p.ej. \"+12.5%\" o \"-3\"). / Percentage or absolute change (e.g. \"+12.5%\" or \"-3\"). */\n change = input<string>('');\n /** Dirección del cambio. Afecta el color del change. / Change direction. Affects the change color. */\n trend = input<NeuStatsTrend>('neutral');\n /** Texto auxiliar bajo el cambio (p.ej. \"vs. mes anterior\"). / Auxiliary text below the change (e.g. \"vs. previous month\"). */\n label = input<string>('');\n /** Nombre del icono Lucide para el encabezado. / Lucide icon name for the header. */\n icon = input<string>('');\n /** Array de valores numéricos para la sparkline. Mín. 2 puntos. / Array of numeric values for the sparkline. Min. 2 points. */\n sparkData = input<number[]>([]);\n\n /** @internal Genera los puntos SVG de la sparkline / Generates the SVG sparkline points */\n protected readonly sparkPoints = computed(() => {\n const data = this.sparkData();\n if (data.length < 2) return '';\n const min = Math.min(...data);\n const max = Math.max(...data);\n const range = max - min || 1;\n const step = 100 / (data.length - 1);\n return data\n .map((v, i) => `${(i * step).toFixed(1)},${(30 - ((v - min) / range) * 25 + 2.5).toFixed(1)}`)\n .join(' ');\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,204 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, DestroyRef, input, output, signal, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { NeuTooltipDirective } from '@neural-ui/core/tooltip';
4
+
5
+ /**
6
+ * NeuralUI Stepper Component
7
+ *
8
+ * Wizard paso a paso con estado de completado, lineal u opcional.
9
+ * Expone métodos next() / prev() y emite stepChange.
10
+ *
11
+ * Uso:
12
+ * <neu-stepper [steps]="steps" [activeStep]="step" (stepChange)="step = $event">
13
+ * <ng-template neuStepContent>Contenido paso 1</ng-template>
14
+ * <ng-template neuStepContent>Contenido paso 2</ng-template>
15
+ * </neu-stepper>
16
+ */
17
+ class NeuStepperComponent {
18
+ _destroyRef = inject(DestroyRef);
19
+ /** Pasos del wizard / Wizard steps */
20
+ steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
21
+ /** Índice del paso activo (0-based) / Active step index (0-based) */
22
+ activeStep = input(0, ...(ngDevMode ? [{ debugName: "activeStep" }] : /* istanbul ignore next */ []));
23
+ /** Si true, solo permite ir hacia adelante secuencialmente / If true, only allows moving forward sequentially */
24
+ linear = input(false, ...(ngDevMode ? [{ debugName: "linear" }] : /* istanbul ignore next */ []));
25
+ /** Emite el nuevo índice al cambiar / Emits the new index on change */
26
+ stepChange = output();
27
+ /** Set de pasos completados / Set of completed steps */
28
+ _completed = signal(new Set(), ...(ngDevMode ? [{ debugName: "_completed" }] : /* istanbul ignore next */ []));
29
+ isCompact = signal(typeof window !== 'undefined' ? window.innerWidth <= 767 : false, ...(ngDevMode ? [{ debugName: "isCompact" }] : /* istanbul ignore next */ []));
30
+ isCompleted = (i) => this._completed().has(i) || (this.steps()[i]?.completed ?? false) || i < this.activeStep();
31
+ stepTooltip = (step) => step.description ? `${step.label} - ${step.description}` : step.label;
32
+ stepAriaLabel = (step) => this.stepTooltip(step);
33
+ constructor() {
34
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
35
+ return;
36
+ }
37
+ const mediaQuery = window.matchMedia('(max-width: 767px)');
38
+ const updateCompact = (event) => {
39
+ this.isCompact.set(event?.matches ?? mediaQuery.matches);
40
+ };
41
+ updateCompact();
42
+ mediaQuery.addEventListener('change', updateCompact);
43
+ this._destroyRef.onDestroy(() => mediaQuery.removeEventListener('change', updateCompact));
44
+ }
45
+ goTo(i) {
46
+ const step = this.steps()[i];
47
+ if (step?.disabled)
48
+ return;
49
+ if (this.linear() && i > this.activeStep() + 1 && !this.isCompleted(this.activeStep()))
50
+ return;
51
+ this.stepChange.emit(i);
52
+ }
53
+ /** Marca el paso actual como completado y avanza al siguiente / Marks the current step as completed and advances to the next */
54
+ next() {
55
+ const current = this.activeStep();
56
+ const updated = new Set(this._completed());
57
+ updated.add(current);
58
+ this._completed.set(updated);
59
+ if (current < this.steps().length - 1) {
60
+ this.stepChange.emit(current + 1);
61
+ }
62
+ }
63
+ prev() {
64
+ const current = this.activeStep();
65
+ if (current > 0) {
66
+ this.stepChange.emit(current - 1);
67
+ }
68
+ }
69
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
70
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuStepperComponent, isStandalone: true, selector: "neu-stepper", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, activeStep: { classPropertyName: "activeStep", publicName: "activeStep", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { stepChange: "stepChange" }, ngImport: i0, template: `
71
+ <!-- Cabecera de pasos -->
72
+ <div class="neu-stepper">
73
+ <div class="neu-stepper__header">
74
+ @for (step of steps(); track step.label; let i = $index; let last = $last) {
75
+ <div
76
+ class="neu-stepper__step"
77
+ [class.neu-stepper__step--active]="i === activeStep()"
78
+ [class.neu-stepper__step--completed]="isCompleted(i)"
79
+ [class.neu-stepper__step--disabled]="step.disabled"
80
+ >
81
+ @if (!last) {
82
+ <div
83
+ class="neu-stepper__connector"
84
+ [class.neu-stepper__connector--done]="isCompleted(i) || i < activeStep()"
85
+ ></div>
86
+ }
87
+ <button
88
+ class="neu-stepper__step-btn"
89
+ type="button"
90
+ [disabled]="step.disabled"
91
+ [attr.aria-label]="stepAriaLabel(step)"
92
+ [neuTooltip]="stepTooltip(step)"
93
+ [neuTooltipDisabled]="!isCompact()"
94
+ neuTooltipPosition="bottom"
95
+ (click)="goTo(i)"
96
+ >
97
+ <span class="neu-stepper__indicator">
98
+ @if (isCompleted(i)) {
99
+ <svg
100
+ width="14"
101
+ height="14"
102
+ viewBox="0 0 24 24"
103
+ fill="none"
104
+ stroke="currentColor"
105
+ stroke-width="3"
106
+ stroke-linecap="round"
107
+ aria-hidden="true"
108
+ >
109
+ <polyline points="20 6 9 17 4 12" />
110
+ </svg>
111
+ } @else {
112
+ {{ i + 1 }}
113
+ }
114
+ </span>
115
+ <span class="neu-stepper__step-info">
116
+ <span class="neu-stepper__step-label">{{ step.label }}</span>
117
+ @if (step.description) {
118
+ <span class="neu-stepper__step-desc">{{ step.description }}</span>
119
+ }
120
+ </span>
121
+ </button>
122
+ </div>
123
+ }
124
+ </div>
125
+
126
+ <!-- Panel de contenido -->
127
+ <div class="neu-stepper__content">
128
+ <ng-content />
129
+ </div>
130
+ </div>
131
+ `, isInline: true, styles: [".neu-stepper{--neu-stepper-indicator-size: 32px;--neu-stepper-indicator-radius: calc(var(--neu-stepper-indicator-size) / 2);--neu-stepper-connector-gap: 8px;display:flex;flex-direction:column;gap:var(--neu-space-6);font-family:var(--neu-font-sans)}.neu-stepper__header{display:flex;align-items:flex-start;gap:0;overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--neu-space-2)}.neu-stepper__step{position:relative;display:flex;flex-direction:column;align-items:center;flex:1 0 8.5rem;min-width:8.5rem}.neu-stepper__step-btn{display:flex;flex-direction:column;align-items:center;width:100%;gap:var(--neu-space-3);background:none;border:none;padding:0 var(--neu-space-2);cursor:pointer;min-width:0;outline:none;position:relative;z-index:1}.neu-stepper__step-btn:focus-visible .neu-stepper__indicator{box-shadow:0 0 0 3px var(--neu-primary-100)}.neu-stepper__step-btn:disabled{cursor:not-allowed}.neu-stepper__indicator{width:var(--neu-stepper-indicator-size);height:var(--neu-stepper-indicator-size);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.8125rem;font-weight:700;background:var(--neu-surface-2);border:2px solid var(--neu-border);color:var(--neu-text-disabled);transition:background var(--neu-transition),border-color var(--neu-transition),color var(--neu-transition)}.neu-stepper__step--active .neu-stepper__indicator{background:var(--neu-primary);border-color:var(--neu-primary);color:var(--neu-primary-fg)}.neu-stepper__step--completed .neu-stepper__indicator{background:var(--neu-success);border-color:var(--neu-success);color:var(--neu-primary-fg)}.neu-stepper__step-info{display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0;width:100%;gap:2px}.neu-stepper__step-label{display:block;font-size:var(--neu-text-sm);font-weight:600;color:var(--neu-text-muted);transition:color var(--neu-transition);line-height:1.25;overflow-wrap:anywhere}.neu-stepper__step--active .neu-stepper__step-label{color:var(--neu-text)}.neu-stepper__step--completed .neu-stepper__step-label{color:var(--neu-text-muted)}.neu-stepper__step-desc{display:block;max-width:100%;font-size:var(--neu-text-xs);color:var(--neu-text-disabled);margin-top:1px;line-height:1.35;overflow-wrap:anywhere}.neu-stepper__connector{position:absolute;top:calc(var(--neu-stepper-indicator-radius) - 1px);left:calc(50% + var(--neu-stepper-indicator-radius) + var(--neu-stepper-connector-gap));width:calc(100% - var(--neu-stepper-indicator-size) - var(--neu-stepper-connector-gap) * 2);height:2px;background:var(--neu-border);transition:background var(--neu-transition);z-index:0}.neu-stepper__connector--done{background:var(--neu-success)}.neu-stepper__content{min-height:80px}@media(max-width:767px){.neu-stepper__header{align-items:flex-start;gap:var(--neu-space-2);scroll-snap-type:x proximity}.neu-stepper__step{flex:0 0 auto;min-width:3.5rem}.neu-stepper__step-btn{padding-inline:0}.neu-stepper__connector{left:calc(50% + var(--neu-stepper-indicator-radius) + var(--neu-stepper-connector-gap));width:calc(100% - var(--neu-stepper-indicator-size) - var(--neu-stepper-connector-gap) * 2)}.neu-stepper__step-info{display:none}}\n"], dependencies: [{ kind: "directive", type: NeuTooltipDirective, selector: "[neuTooltip]", inputs: ["neuTooltip", "neuTooltipPosition", "neuTooltipDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
132
+ }
133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuStepperComponent, decorators: [{
134
+ type: Component,
135
+ args: [{ selector: 'neu-stepper', imports: [NeuTooltipDirective], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
136
+ <!-- Cabecera de pasos -->
137
+ <div class="neu-stepper">
138
+ <div class="neu-stepper__header">
139
+ @for (step of steps(); track step.label; let i = $index; let last = $last) {
140
+ <div
141
+ class="neu-stepper__step"
142
+ [class.neu-stepper__step--active]="i === activeStep()"
143
+ [class.neu-stepper__step--completed]="isCompleted(i)"
144
+ [class.neu-stepper__step--disabled]="step.disabled"
145
+ >
146
+ @if (!last) {
147
+ <div
148
+ class="neu-stepper__connector"
149
+ [class.neu-stepper__connector--done]="isCompleted(i) || i < activeStep()"
150
+ ></div>
151
+ }
152
+ <button
153
+ class="neu-stepper__step-btn"
154
+ type="button"
155
+ [disabled]="step.disabled"
156
+ [attr.aria-label]="stepAriaLabel(step)"
157
+ [neuTooltip]="stepTooltip(step)"
158
+ [neuTooltipDisabled]="!isCompact()"
159
+ neuTooltipPosition="bottom"
160
+ (click)="goTo(i)"
161
+ >
162
+ <span class="neu-stepper__indicator">
163
+ @if (isCompleted(i)) {
164
+ <svg
165
+ width="14"
166
+ height="14"
167
+ viewBox="0 0 24 24"
168
+ fill="none"
169
+ stroke="currentColor"
170
+ stroke-width="3"
171
+ stroke-linecap="round"
172
+ aria-hidden="true"
173
+ >
174
+ <polyline points="20 6 9 17 4 12" />
175
+ </svg>
176
+ } @else {
177
+ {{ i + 1 }}
178
+ }
179
+ </span>
180
+ <span class="neu-stepper__step-info">
181
+ <span class="neu-stepper__step-label">{{ step.label }}</span>
182
+ @if (step.description) {
183
+ <span class="neu-stepper__step-desc">{{ step.description }}</span>
184
+ }
185
+ </span>
186
+ </button>
187
+ </div>
188
+ }
189
+ </div>
190
+
191
+ <!-- Panel de contenido -->
192
+ <div class="neu-stepper__content">
193
+ <ng-content />
194
+ </div>
195
+ </div>
196
+ `, styles: [".neu-stepper{--neu-stepper-indicator-size: 32px;--neu-stepper-indicator-radius: calc(var(--neu-stepper-indicator-size) / 2);--neu-stepper-connector-gap: 8px;display:flex;flex-direction:column;gap:var(--neu-space-6);font-family:var(--neu-font-sans)}.neu-stepper__header{display:flex;align-items:flex-start;gap:0;overflow-x:auto;scrollbar-width:thin;padding-bottom:var(--neu-space-2)}.neu-stepper__step{position:relative;display:flex;flex-direction:column;align-items:center;flex:1 0 8.5rem;min-width:8.5rem}.neu-stepper__step-btn{display:flex;flex-direction:column;align-items:center;width:100%;gap:var(--neu-space-3);background:none;border:none;padding:0 var(--neu-space-2);cursor:pointer;min-width:0;outline:none;position:relative;z-index:1}.neu-stepper__step-btn:focus-visible .neu-stepper__indicator{box-shadow:0 0 0 3px var(--neu-primary-100)}.neu-stepper__step-btn:disabled{cursor:not-allowed}.neu-stepper__indicator{width:var(--neu-stepper-indicator-size);height:var(--neu-stepper-indicator-size);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.8125rem;font-weight:700;background:var(--neu-surface-2);border:2px solid var(--neu-border);color:var(--neu-text-disabled);transition:background var(--neu-transition),border-color var(--neu-transition),color var(--neu-transition)}.neu-stepper__step--active .neu-stepper__indicator{background:var(--neu-primary);border-color:var(--neu-primary);color:var(--neu-primary-fg)}.neu-stepper__step--completed .neu-stepper__indicator{background:var(--neu-success);border-color:var(--neu-success);color:var(--neu-primary-fg)}.neu-stepper__step-info{display:flex;flex-direction:column;align-items:center;text-align:center;min-width:0;width:100%;gap:2px}.neu-stepper__step-label{display:block;font-size:var(--neu-text-sm);font-weight:600;color:var(--neu-text-muted);transition:color var(--neu-transition);line-height:1.25;overflow-wrap:anywhere}.neu-stepper__step--active .neu-stepper__step-label{color:var(--neu-text)}.neu-stepper__step--completed .neu-stepper__step-label{color:var(--neu-text-muted)}.neu-stepper__step-desc{display:block;max-width:100%;font-size:var(--neu-text-xs);color:var(--neu-text-disabled);margin-top:1px;line-height:1.35;overflow-wrap:anywhere}.neu-stepper__connector{position:absolute;top:calc(var(--neu-stepper-indicator-radius) - 1px);left:calc(50% + var(--neu-stepper-indicator-radius) + var(--neu-stepper-connector-gap));width:calc(100% - var(--neu-stepper-indicator-size) - var(--neu-stepper-connector-gap) * 2);height:2px;background:var(--neu-border);transition:background var(--neu-transition);z-index:0}.neu-stepper__connector--done{background:var(--neu-success)}.neu-stepper__content{min-height:80px}@media(max-width:767px){.neu-stepper__header{align-items:flex-start;gap:var(--neu-space-2);scroll-snap-type:x proximity}.neu-stepper__step{flex:0 0 auto;min-width:3.5rem}.neu-stepper__step-btn{padding-inline:0}.neu-stepper__connector{left:calc(50% + var(--neu-stepper-indicator-radius) + var(--neu-stepper-connector-gap));width:calc(100% - var(--neu-stepper-indicator-size) - var(--neu-stepper-connector-gap) * 2)}.neu-stepper__step-info{display:none}}\n"] }]
197
+ }], ctorParameters: () => [], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }], activeStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeStep", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], stepChange: [{ type: i0.Output, args: ["stepChange"] }] } });
198
+
199
+ /**
200
+ * Generated bundle index. Do not edit.
201
+ */
202
+
203
+ export { NeuStepperComponent };
204
+ //# sourceMappingURL=neural-ui-core-stepper.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-stepper.mjs","sources":["../../../../projects/ui-core/stepper/neu-stepper.component.ts","../../../../projects/ui-core/stepper/neural-ui-core-stepper.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ViewEncapsulation,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { NeuTooltipDirective } from '@neural-ui/core/tooltip';\n\nexport interface NeuStepperStep {\n /** Etiqueta del paso / Step label */\n label: string;\n /** Descripción corta opcional / Optional short description */\n description?: string;\n /** Marca el paso como completado externamente / Marks the step as completed externally */\n completed?: boolean;\n /** Desactiva el paso / Disables the step */\n disabled?: boolean;\n}\n\n/**\n * NeuralUI Stepper Component\n *\n * Wizard paso a paso con estado de completado, lineal u opcional.\n * Expone métodos next() / prev() y emite stepChange.\n *\n * Uso:\n * <neu-stepper [steps]=\"steps\" [activeStep]=\"step\" (stepChange)=\"step = $event\">\n * <ng-template neuStepContent>Contenido paso 1</ng-template>\n * <ng-template neuStepContent>Contenido paso 2</ng-template>\n * </neu-stepper>\n */\n@Component({\n selector: 'neu-stepper',\n imports: [NeuTooltipDirective],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Cabecera de pasos -->\n <div class=\"neu-stepper\">\n <div class=\"neu-stepper__header\">\n @for (step of steps(); track step.label; let i = $index; let last = $last) {\n <div\n class=\"neu-stepper__step\"\n [class.neu-stepper__step--active]=\"i === activeStep()\"\n [class.neu-stepper__step--completed]=\"isCompleted(i)\"\n [class.neu-stepper__step--disabled]=\"step.disabled\"\n >\n @if (!last) {\n <div\n class=\"neu-stepper__connector\"\n [class.neu-stepper__connector--done]=\"isCompleted(i) || i < activeStep()\"\n ></div>\n }\n <button\n class=\"neu-stepper__step-btn\"\n type=\"button\"\n [disabled]=\"step.disabled\"\n [attr.aria-label]=\"stepAriaLabel(step)\"\n [neuTooltip]=\"stepTooltip(step)\"\n [neuTooltipDisabled]=\"!isCompact()\"\n neuTooltipPosition=\"bottom\"\n (click)=\"goTo(i)\"\n >\n <span class=\"neu-stepper__indicator\">\n @if (isCompleted(i)) {\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n } @else {\n {{ i + 1 }}\n }\n </span>\n <span class=\"neu-stepper__step-info\">\n <span class=\"neu-stepper__step-label\">{{ step.label }}</span>\n @if (step.description) {\n <span class=\"neu-stepper__step-desc\">{{ step.description }}</span>\n }\n </span>\n </button>\n </div>\n }\n </div>\n\n <!-- Panel de contenido -->\n <div class=\"neu-stepper__content\">\n <ng-content />\n </div>\n </div>\n `,\n styleUrl: './neu-stepper.component.scss',\n})\nexport class NeuStepperComponent {\n private readonly _destroyRef = inject(DestroyRef);\n\n /** Pasos del wizard / Wizard steps */\n steps = input<NeuStepperStep[]>([]);\n\n /** Índice del paso activo (0-based) / Active step index (0-based) */\n activeStep = input<number>(0);\n\n /** Si true, solo permite ir hacia adelante secuencialmente / If true, only allows moving forward sequentially */\n linear = input<boolean>(false);\n\n /** Emite el nuevo índice al cambiar / Emits the new index on change */\n stepChange = output<number>();\n\n /** Set de pasos completados / Set of completed steps */\n private readonly _completed = signal<Set<number>>(new Set());\n readonly isCompact = signal(typeof window !== 'undefined' ? window.innerWidth <= 767 : false);\n\n readonly isCompleted = (i: number) =>\n this._completed().has(i) || (this.steps()[i]?.completed ?? false) || i < this.activeStep();\n\n readonly stepTooltip = (step: NeuStepperStep) =>\n step.description ? `${step.label} - ${step.description}` : step.label;\n\n readonly stepAriaLabel = (step: NeuStepperStep) => this.stepTooltip(step);\n\n constructor() {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return;\n }\n\n const mediaQuery = window.matchMedia('(max-width: 767px)');\n const updateCompact = (event?: MediaQueryListEvent) => {\n this.isCompact.set(event?.matches ?? mediaQuery.matches);\n };\n\n updateCompact();\n mediaQuery.addEventListener('change', updateCompact);\n this._destroyRef.onDestroy(() => mediaQuery.removeEventListener('change', updateCompact));\n }\n\n goTo(i: number): void {\n const step = this.steps()[i];\n if (step?.disabled) return;\n if (this.linear() && i > this.activeStep() + 1 && !this.isCompleted(this.activeStep())) return;\n this.stepChange.emit(i);\n }\n\n /** Marca el paso actual como completado y avanza al siguiente / Marks the current step as completed and advances to the next */\n next(): void {\n const current = this.activeStep();\n const updated = new Set(this._completed());\n updated.add(current);\n this._completed.set(updated);\n if (current < this.steps().length - 1) {\n this.stepChange.emit(current + 1);\n }\n }\n\n prev(): void {\n const current = this.activeStep();\n if (current > 0) {\n this.stepChange.emit(current - 1);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, signal, computed, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
+
5
+ let _neuSwitchIdSeq = 0;
6
+ /**
7
+ * NeuralUI Switch Component
8
+ *
9
+ * Toggle animado para formularios de configuración en dashboards.
10
+ * Usa el Electric-Blue (--neu-primary) cuando está activo.
11
+ *
12
+ * Uso:
13
+ * <neu-switch label="Notificaciones" [formControl]="notifsCtrl" />
14
+ */
15
+ class NeuSwitchComponent {
16
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
17
+ name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
18
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
19
+ _id = `neu-switch-${_neuSwitchIdSeq++}`;
20
+ _checked = signal(false, ...(ngDevMode ? [{ debugName: "_checked" }] : /* istanbul ignore next */ []));
21
+ /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState / Internal disabled state — combines the `disabled` input with CVA setDisabledState */
22
+ _cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
23
+ _isDisabled = computed(() => this.disabled() || this._cvaDisabled(), ...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
24
+ _onChange = () => { };
25
+ _onTouched = () => { };
26
+ onChange(event) {
27
+ const checked = event.target.checked;
28
+ this._checked.set(checked);
29
+ this._onChange(checked);
30
+ }
31
+ onBlur() {
32
+ this._onTouched();
33
+ }
34
+ writeValue(val) {
35
+ this._checked.set(!!val);
36
+ }
37
+ registerOnChange(fn) {
38
+ this._onChange = fn;
39
+ }
40
+ registerOnTouched(fn) {
41
+ this._onTouched = fn;
42
+ }
43
+ setDisabledState(isDisabled) {
44
+ this._cvaDisabled.set(isDisabled);
45
+ }
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSwitchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
47
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuSwitchComponent, isStandalone: true, selector: "neu-switch", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "neu-switch-host" }, providers: [
48
+ {
49
+ provide: NG_VALUE_ACCESSOR,
50
+ useExisting: forwardRef(() => NeuSwitchComponent),
51
+ multi: true,
52
+ },
53
+ ], ngImport: i0, template: `
54
+ <label class="neu-switch" [class.neu-switch--disabled]="_isDisabled()" [for]="_id">
55
+ <input
56
+ type="checkbox"
57
+ role="switch"
58
+ class="neu-switch__input"
59
+ [id]="_id"
60
+ [attr.name]="name() || null"
61
+ [checked]="_checked()"
62
+ [disabled]="_isDisabled()"
63
+ (change)="onChange($event)"
64
+ (blur)="onBlur()"
65
+ />
66
+ <span class="neu-switch__track" [class.neu-switch__track--on]="_checked()">
67
+ <span class="neu-switch__thumb" [class.neu-switch__thumb--on]="_checked()"></span>
68
+ </span>
69
+ @if (label()) {
70
+ <span class="neu-switch__label">{{ label() }}</span>
71
+ }
72
+ </label>
73
+ `, isInline: true, styles: [".neu-switch-host{display:inline-block}.neu-switch{display:inline-flex;align-items:center;gap:var(--neu-space-3);cursor:pointer;-webkit-user-select:none;user-select:none}.neu-switch--disabled{opacity:.5;pointer-events:none}.neu-switch__input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.neu-switch__input:focus-visible+.neu-switch__track{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-switch__track{position:relative;display:inline-block;width:44px;height:24px;background:var(--neu-surface-3);border-radius:var(--neu-radius-full);transition:background-color var(--neu-transition),box-shadow var(--neu-transition);flex-shrink:0}.neu-switch__track--on{background:var(--neu-primary);box-shadow:0 0 12px #007aff59}.neu-switch__thumb{position:absolute;top:3px;left:3px;width:18px;height:18px;background:#fff;border-radius:var(--neu-radius-full);box-shadow:var(--neu-shadow-xs);transition:transform var(--neu-transition-bounce)}.neu-switch__thumb--on{transform:translate(20px)}.neu-switch__label{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);font-weight:500;line-height:1}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSwitchComponent, decorators: [{
76
+ type: Component,
77
+ args: [{ selector: 'neu-switch', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-switch-host' }, providers: [
78
+ {
79
+ provide: NG_VALUE_ACCESSOR,
80
+ useExisting: forwardRef(() => NeuSwitchComponent),
81
+ multi: true,
82
+ },
83
+ ], template: `
84
+ <label class="neu-switch" [class.neu-switch--disabled]="_isDisabled()" [for]="_id">
85
+ <input
86
+ type="checkbox"
87
+ role="switch"
88
+ class="neu-switch__input"
89
+ [id]="_id"
90
+ [attr.name]="name() || null"
91
+ [checked]="_checked()"
92
+ [disabled]="_isDisabled()"
93
+ (change)="onChange($event)"
94
+ (blur)="onBlur()"
95
+ />
96
+ <span class="neu-switch__track" [class.neu-switch__track--on]="_checked()">
97
+ <span class="neu-switch__thumb" [class.neu-switch__thumb--on]="_checked()"></span>
98
+ </span>
99
+ @if (label()) {
100
+ <span class="neu-switch__label">{{ label() }}</span>
101
+ }
102
+ </label>
103
+ `, styles: [".neu-switch-host{display:inline-block}.neu-switch{display:inline-flex;align-items:center;gap:var(--neu-space-3);cursor:pointer;-webkit-user-select:none;user-select:none}.neu-switch--disabled{opacity:.5;pointer-events:none}.neu-switch__input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.neu-switch__input:focus-visible+.neu-switch__track{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-switch__track{position:relative;display:inline-block;width:44px;height:24px;background:var(--neu-surface-3);border-radius:var(--neu-radius-full);transition:background-color var(--neu-transition),box-shadow var(--neu-transition);flex-shrink:0}.neu-switch__track--on{background:var(--neu-primary);box-shadow:0 0 12px #007aff59}.neu-switch__thumb{position:absolute;top:3px;left:3px;width:18px;height:18px;background:#fff;border-radius:var(--neu-radius-full);box-shadow:var(--neu-shadow-xs);transition:transform var(--neu-transition-bounce)}.neu-switch__thumb--on{transform:translate(20px)}.neu-switch__label{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);font-weight:500;line-height:1}\n"] }]
104
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
105
+
106
+ /**
107
+ * Generated bundle index. Do not edit.
108
+ */
109
+
110
+ export { NeuSwitchComponent };
111
+ //# sourceMappingURL=neural-ui-core-switch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-switch.mjs","sources":["../../../../projects/ui-core/switch/neu-switch.component.ts","../../../../projects/ui-core/switch/neural-ui-core-switch.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n forwardRef,\n input,\n signal,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nlet _neuSwitchIdSeq = 0;\n\n/**\n * NeuralUI Switch Component\n *\n * Toggle animado para formularios de configuración en dashboards.\n * Usa el Electric-Blue (--neu-primary) cuando está activo.\n *\n * Uso:\n * <neu-switch label=\"Notificaciones\" [formControl]=\"notifsCtrl\" />\n */\n@Component({\n selector: 'neu-switch',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-switch-host' },\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NeuSwitchComponent),\n multi: true,\n },\n ],\n template: `\n <label class=\"neu-switch\" [class.neu-switch--disabled]=\"_isDisabled()\" [for]=\"_id\">\n <input\n type=\"checkbox\"\n role=\"switch\"\n class=\"neu-switch__input\"\n [id]=\"_id\"\n [attr.name]=\"name() || null\"\n [checked]=\"_checked()\"\n [disabled]=\"_isDisabled()\"\n (change)=\"onChange($event)\"\n (blur)=\"onBlur()\"\n />\n <span class=\"neu-switch__track\" [class.neu-switch__track--on]=\"_checked()\">\n <span class=\"neu-switch__thumb\" [class.neu-switch__thumb--on]=\"_checked()\"></span>\n </span>\n @if (label()) {\n <span class=\"neu-switch__label\">{{ label() }}</span>\n }\n </label>\n `,\n styleUrl: './neu-switch.component.scss',\n})\nexport class NeuSwitchComponent implements ControlValueAccessor {\n readonly label = input<string>('');\n readonly name = input<string>('');\n readonly disabled = input<boolean>(false);\n\n readonly _id = `neu-switch-${_neuSwitchIdSeq++}`;\n\n protected readonly _checked = signal(false);\n /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState / Internal disabled state — combines the `disabled` input with CVA setDisabledState */\n private readonly _cvaDisabled = signal(false);\n protected readonly _isDisabled = computed(() => this.disabled() || this._cvaDisabled());\n\n private _onChange: (v: boolean) => void = () => {};\n private _onTouched: () => void = () => {};\n\n onChange(event: Event): void {\n const checked = (event.target as HTMLInputElement).checked;\n this._checked.set(checked);\n this._onChange(checked);\n }\n\n onBlur(): void {\n this._onTouched();\n }\n\n writeValue(val: unknown): void {\n this._checked.set(!!val);\n }\n\n registerOnChange(fn: (v: boolean) => void): void {\n this._onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._cvaDisabled.set(isDisabled);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}