@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 @@
1
+ {"version":3,"file":"neural-ui-core-select.mjs","sources":["../../../../projects/ui-core/select/neu-select.directives.ts","../../../../projects/ui-core/select/neu-select.component.ts","../../../../projects/ui-core/select/neural-ui-core-select.ts"],"sourcesContent":["import { Directive, TemplateRef, inject } from '@angular/core';\nimport { NeuSelectOption } from './neu-select.types';\n\n/**\n * Directiva para personalizar el template de cada ítem del dropdown.\n *\n * Uso:\n * ```html\n * <neu-select [options]=\"opts\" [formControl]=\"valueCtrl\">\n * <ng-template neuSelectItem let-item>\n * <span class=\"flag flag-{{ item.value }}\"></span>\n * {{ item.label }}\n * </ng-template>\n * </neu-select>\n * ```\n */\n@Directive({ selector: '[neuSelectItem]', standalone: true })\nexport class NeuSelectItemDirective {\n readonly templateRef = inject<TemplateRef<{ $implicit: NeuSelectOption }>>(TemplateRef);\n}\n\n/**\n * Directiva para personalizar el template del ítem seleccionado (trigger).\n *\n * Uso:\n * ```html\n * <neu-select [options]=\"opts\" [formControl]=\"valueCtrl\">\n * <ng-template neuSelectSelected let-item>\n * <strong>{{ item?.label }}</strong>\n * </ng-template>\n * </neu-select>\n * ```\n */\n@Directive({ selector: '[neuSelectSelected]', standalone: true })\nexport class NeuSelectSelectedDirective {\n readonly templateRef = inject<TemplateRef<{ $implicit: NeuSelectOption | null }>>(TemplateRef);\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n contentChild,\n effect,\n forwardRef,\n inject,\n input,\n output,\n signal,\n untracked,\n} from '@angular/core';\nimport { NeuUrlStateService } from '@neural-ui/core/url-state';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { NeuSelectOption } from './neu-select.types';\nimport { NeuSelectItemDirective, NeuSelectSelectedDirective } from './neu-select.directives';\n\nexport type { NeuSelectOption } from './neu-select.types';\n\nlet _neuSelectIdSeq = 0;\n\n/**\n * NeuralUI Select Component\n *\n * Dropdown personalizado con soporte para ControlValueAccessor y Reactive Forms.\n * Puede usarse dentro de un FormGroup o con un FormControl standalone.\n * Cierra automáticamente al hacer clic fuera del componente.\n *\n * Uso:\n * readonly countryCtrl = new FormControl<string | null>(null);\n * <neu-select label=\"País\" [options]=\"paises\" [formControl]=\"countryCtrl\" />\n *\n * Uso standalone fuera de un formulario completo:\n * readonly sortCtrl = new FormControl<string | null>('name');\n * <neu-select label=\"Orden\" [options]=\"sortOptions\" [formControl]=\"sortCtrl\" />\n */\n@Component({\n selector: 'neu-select',\n imports: [NgTemplateOutlet],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NeuSelectComponent),\n multi: true,\n },\n ],\n host: {\n '(document:click)': 'onDocumentClick($event)',\n '(keydown.escape)': 'close()',\n '(window:resize)': 'onWindowResize()',\n '(window:scroll)': 'onWindowScroll()',\n },\n template: `\n @if (!floatingLabel() && label()) {\n <label class=\"neu-select__static-label\" [for]=\"_triggerId\">{{ label() }}</label>\n }\n <div\n class=\"neu-select\"\n [class.neu-select--open]=\"isOpen()\"\n [class.neu-select--disabled]=\"isDisabledFinal()\"\n [class.neu-select--error]=\"hasError()\"\n [class.neu-select--has-value]=\"!!_value()\"\n [class.neu-select--has-placeholder]=\"!!placeholder() && !_value()\"\n [class.neu-select--no-float]=\"!floatingLabel()\"\n [class.neu-select--sm]=\"size() === 'sm'\"\n [class.neu-select--lg]=\"size() === 'lg'\"\n >\n <!-- Trigger ------>\n <button\n class=\"neu-select__trigger\"\n type=\"button\"\n [id]=\"_triggerId\"\n [disabled]=\"isDisabledFinal()\"\n [attr.role]=\"'combobox'\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-invalid]=\"hasError() ? 'true' : null\"\n [attr.aria-activedescendant]=\"isOpen() && _value() ? 'neu-select-opt-' + _value() : null\"\n [attr.aria-label]=\"label() || placeholder() || null\"\n (click)=\"toggle()\"\n (keydown.arrowDown)=\"onTriggerKey($any($event))\"\n (keydown.arrowUp)=\"onTriggerKey($any($event))\"\n >\n <!-- Floating label -->\n @if (floatingLabel() && label()) {\n <span class=\"neu-select__label\">{{ label() }}</span>\n }\n\n <span class=\"neu-select__value\">\n @if (selectedLabel()) {\n @if (selectedItemTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"selectedItemTpl()!.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: _selectedOption() }\"\n />\n } @else {\n {{ selectedLabel() }}\n }\n } @else {\n <span class=\"neu-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n\n <!-- Clear button -->\n @if (clearable() && !!_value() && !isDisabledFinal()) {\n <button\n class=\"neu-select__clear\"\n type=\"button\"\n aria-label=\"Limpiar selección\"\n [attr.aria-label]=\"clearAriaLabel()\"\n (click)=\"clearValue($event)\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n }\n\n <!-- Chevron -->\n <svg\n class=\"neu-select__chevron\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n </button>\n\n <!-- Panel ------>\n @if (isOpen()) {\n <div\n class=\"neu-select__panel\"\n role=\"listbox\"\n [attr.aria-label]=\"label()\"\n [style.position]=\"panelPosition().position\"\n [style.top]=\"panelPosition().top\"\n [style.left]=\"panelPosition().left\"\n [style.width]=\"panelPosition().width\"\n [style.max-height]=\"panelPosition().maxHeight\"\n >\n @if (searchable()) {\n <div class=\"neu-select__search\">\n <input\n class=\"neu-select__search-input\"\n type=\"text\"\n [attr.aria-label]=\"'Search ' + label()\"\n [placeholder]=\"searchPlaceholder()\"\n [value]=\"searchQuery()\"\n (input)=\"searchQuery.set($any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n @for (option of filteredOptions(); track option.value) {\n <div\n class=\"neu-select__option\"\n [class.neu-select__option--selected]=\"option.value === _value()\"\n [class.neu-select__option--disabled]=\"option.disabled\"\n role=\"option\"\n [id]=\"'neu-select-opt-' + option.value\"\n [attr.aria-selected]=\"option.value === _value()\"\n [attr.aria-disabled]=\"option.disabled\"\n [attr.tabindex]=\"option.disabled ? null : '-1'\"\n (click)=\"selectOption(option)\"\n (keydown.enter)=\"selectOption(option)\"\n (keydown.space)=\"selectOption(option)\"\n (keydown.arrowDown)=\"focusOptionByIndex($any($event), option, 1)\"\n (keydown.arrowUp)=\"focusOptionByIndex($any($event), option, -1)\"\n >\n <!-- Checkmark en la seleccionada (siempre reserva el espacio) -->\n <svg\n class=\"neu-select__check\"\n [style.visibility]=\"option.value === _value() ? 'visible' : 'hidden'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"20 6 9 17 4 12\" />\n </svg>\n @if (itemTpl()) {\n <ng-container\n [ngTemplateOutlet]=\"itemTpl()!.templateRef\"\n [ngTemplateOutletContext]=\"{ $implicit: option }\"\n />\n } @else {\n {{ option.label }}\n }\n </div>\n }\n @if (filteredOptions().length === 0) {\n <div class=\"neu-select__empty\">{{ noResultsMessage() }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Error / hint -->\n @if (hasError()) {\n <p class=\"neu-select__error\" role=\"alert\">{{ errorMessage() }}</p>\n }\n `,\n styleUrl: './neu-select.component.scss',\n})\nexport class NeuSelectComponent implements ControlValueAccessor {\n private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly _urlState = inject(NeuUrlStateService);\n private readonly _mobileViewportMax = 768;\n private readonly _viewportMargin = 16;\n\n constructor() {\n effect(() => {\n const param = this.urlParam();\n if (!param) return;\n const urlVal = this._urlState.getParam(param)();\n if (urlVal !== untracked(() => this._value())) {\n this._value.set(urlVal);\n this._onChange(urlVal);\n }\n });\n }\n /** @internal — ID \\u00fanico para asociar label con trigger */\n readonly _triggerId = `neu-select-trigger-${_neuSelectIdSeq++}`;\n /** Template personalizado para cada opción del dropdown / Custom template for each dropdown option */\n readonly itemTpl = contentChild(NeuSelectItemDirective);\n\n /** Template personalizado para el valor seleccionado en el trigger / Custom template for the selected value in the trigger */\n readonly selectedItemTpl = contentChild(NeuSelectSelectedDirective);\n /** Opciones del dropdown / Dropdown options */\n options = input<NeuSelectOption[]>([]);\n\n /** Texto del floating label / Floating label text */\n label = input<string>('');\n\n /** Placeholder cuando no hay selección / Placeholder when there is no selection */\n placeholder = input<string>('Seleccionar...');\n\n /** Mensaje de error / Error message */\n errorMessage = input<string>('');\n\n /** Deshabilita el select / Disables the select */\n disabled = input<boolean>(false);\n\n /** Muestra el label como flotante (true) o como label estático encima (false, por defecto) / Shows the label as floating (true) or static above (false, default) */\n floatingLabel = input<boolean>(false);\n /** Tamaño del campo: 'sm' = 36px | 'md' = 48px | 'lg' = 56px / Field size */\n size = input<'sm' | 'md' | 'lg'>('md');\n /** Activa input de búsqueda/filtro en el panel / Activates the search/filter input in the panel */\n searchable = input<boolean>(false);\n\n /** Placeholder del input de búsqueda / Search input placeholder */\n searchPlaceholder = input<string>('Buscar...');\n\n /** Muestra un botón para limpiar la selección / Shows a button to clear the selection */\n clearable = input<boolean>(false);\n\n /** Texto cuando no hay opciones tras filtrar / Text when no options remain after filtering */\n noResultsMessage = input<string>('Sin resultados');\n\n /** Aria-label del botón de limpiar / Aria-label for the clear button */\n clearAriaLabel = input<string>('Limpiar selección');\n\n /**\n * Sincroniza el valor seleccionado con este query param de la URL.\n * Al seleccionar una opción se añade `?{urlParam}=value` a la URL.\n * Pasar `null` (default) deshabilita la sincronización.\n */\n urlParam = input<string | null>(null);\n\n /**\n * Emite el objeto NeuSelectOption completo (incluyendo data) al seleccionar una opción.\n * Emite null al limpiar la selección.\n * El valor del formControl sigue siendo string.\n */\n readonly selectionChange = output<NeuSelectOption | null>();\n\n // Estado interno\n protected readonly _value = signal<string | null>(null);\n readonly isOpen = signal(false);\n readonly searchQuery = signal('');\n readonly panelPosition = signal<{\n position: string | null;\n top: string | null;\n left: string | null;\n width: string | null;\n maxHeight: string | null;\n }>({\n position: null,\n top: null,\n left: null,\n width: null,\n maxHeight: null,\n });\n\n readonly hasError = computed(() => !!this.errorMessage());\n\n readonly filteredOptions = computed(() => {\n const q = this.searchQuery().toLowerCase().trim();\n if (!q) return this.options();\n return this.options().filter((o) => o.label.toLowerCase().includes(q));\n });\n\n readonly selectedLabel = computed(\n () => this.options().find((o) => o.value === this._value())?.label ?? null,\n );\n\n readonly _selectedOption = computed(\n () => this.options().find((o) => o.value === this._value()) ?? null,\n );\n\n // CVA\n private _onChange: (v: string | null) => void = () => {};\n private _onTouched: () => void = () => {};\n\n writeValue(val: string | null): void {\n this._value.set(val ?? null);\n }\n\n registerOnChange(fn: (v: string | null) => void): void {\n this._onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n private readonly _cvaDisabled = signal(false);\n setDisabledState(isDisabled: boolean): void {\n this._cvaDisabled.set(isDisabled);\n }\n\n readonly isDisabledFinal = computed(() => this.disabled() || this._cvaDisabled());\n\n toggle(): void {\n if (!this.isDisabledFinal()) this.isOpen.update((v) => !v);\n if (this.isOpen()) {\n this.syncPanelPosition();\n // Foco al primer item cuando abre con teclado\n requestAnimationFrame(() => {\n const first = this.elementRef.nativeElement.querySelector<HTMLElement>(\n '.neu-select__option:not([aria-disabled=\"true\"])',\n );\n first?.focus();\n });\n } else {\n this.resetPanelPosition();\n }\n }\n\n close(): void {\n this.isOpen.set(false);\n this.searchQuery.set('');\n this.resetPanelPosition();\n this._onTouched();\n }\n\n /** Abre el panel y navega con flechas desde el trigger / Opens the panel and navigates with arrows from the trigger */\n onTriggerKey(event: Event): void {\n event.preventDefault();\n if (!this.isOpen()) {\n this.isOpen.set(true);\n this.syncPanelPosition();\n requestAnimationFrame(() => {\n const first = this.elementRef.nativeElement.querySelector<HTMLElement>(\n '.neu-select__option:not([aria-disabled=\"true\"])',\n );\n first?.focus();\n });\n }\n }\n\n /** Navega entre opciones con flechas / Navigates between options with arrows */\n focusOptionByIndex(event: Event, current: NeuSelectOption, dir: 1 | -1): void {\n event.preventDefault();\n const opts = this.filteredOptions().filter((o) => !o.disabled);\n const idx = opts.findIndex((o) => o.value === current.value);\n const next = opts[(idx + dir + opts.length) % opts.length];\n if (next) {\n const el = this.elementRef.nativeElement.querySelector<HTMLElement>(\n `#neu-select-opt-${next.value}`,\n );\n el?.focus();\n }\n }\n\n clearValue(event: MouseEvent): void {\n event.stopPropagation();\n this._value.set(null);\n this._onChange(null);\n const param = this.urlParam();\n if (param) this._urlState.setParam(param, null);\n this._onTouched();\n this.selectionChange.emit(null);\n this.close();\n }\n\n selectOption(option: NeuSelectOption): void {\n if (option.disabled) return;\n this._value.set(option.value);\n this._onChange(option.value);\n const param = this.urlParam();\n if (param) this._urlState.setParam(param, option.value);\n this.selectionChange.emit(option);\n this.close();\n }\n\n onDocumentClick(event: MouseEvent): void {\n if (!this.elementRef.nativeElement.contains(event.target as Node)) {\n this.close();\n }\n }\n\n onWindowResize(): void {\n if (this.isOpen()) {\n this.syncPanelPosition();\n }\n }\n\n onWindowScroll(): void {\n if (this.isOpen()) {\n this.syncPanelPosition();\n }\n }\n\n private syncPanelPosition(): void {\n requestAnimationFrame(() => {\n const trigger =\n this.elementRef.nativeElement.querySelector<HTMLElement>('.neu-select__trigger');\n if (!trigger) return;\n if (window.innerWidth > this._mobileViewportMax) {\n this.resetPanelPosition();\n return;\n }\n\n const triggerRect = trigger.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const width = Math.min(triggerRect.width, viewportWidth - this._viewportMargin * 2);\n const left = Math.min(\n Math.max(triggerRect.left, this._viewportMargin),\n viewportWidth - this._viewportMargin - width,\n );\n const top = triggerRect.bottom + 6;\n const maxHeight = Math.max(140, viewportHeight - top - this._viewportMargin);\n\n this.panelPosition.set({\n position: 'fixed',\n top: `${top}px`,\n left: `${left}px`,\n width: `${width}px`,\n maxHeight: `${maxHeight}px`,\n });\n });\n }\n\n private resetPanelPosition(): void {\n this.panelPosition.set({\n position: null,\n top: null,\n left: null,\n width: null,\n maxHeight: null,\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,214 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, input, output, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { DOCUMENT } from '@angular/common';
4
+ import { NeuUrlStateService } from '@neural-ui/core/url-state';
5
+ import { NeuIconComponent } from '@neural-ui/core/icon';
6
+
7
+ let overlayScrollLockCount = 0;
8
+ let previousHtmlOverflow = '';
9
+ let previousBodyOverflow = '';
10
+ function lockDocumentScroll(document) {
11
+ if (overlayScrollLockCount === 0) {
12
+ previousHtmlOverflow = document.documentElement.style.overflow;
13
+ previousBodyOverflow = document.body.style.overflow;
14
+ document.documentElement.style.overflow = 'hidden';
15
+ document.body.style.overflow = 'hidden';
16
+ }
17
+ overlayScrollLockCount += 1;
18
+ }
19
+ function unlockDocumentScroll(document) {
20
+ if (overlayScrollLockCount === 0) {
21
+ return;
22
+ }
23
+ overlayScrollLockCount -= 1;
24
+ if (overlayScrollLockCount === 0) {
25
+ document.documentElement.style.overflow = previousHtmlOverflow;
26
+ document.body.style.overflow = previousBodyOverflow;
27
+ }
28
+ }
29
+ /**
30
+ * NeuralUI Sidebar Component
31
+ *
32
+ * El estado abierto/cerrado se gestiona automáticamente desde la URL / The open/closed state is automatically managed from the URL
33
+ * via NeuUrlStateService (?menu=open por defecto). / via NeuUrlStateService (?menu=open by default).
34
+ *
35
+ * Modos:
36
+ * - overlay (default): panel flotante sobre el contenido con backdrop / floating panel above content with backdrop
37
+ * - persistent: sidebar fijo integrado en el layout (desktop) / fixed sidebar integrated in the layout (desktop)
38
+ *
39
+ * Uso:
40
+ * <neu-sidebar urlParam="menu" [persistent]="isDesktop()">
41
+ * <span neu-sidebar-header>Mi App</span>
42
+ * <nav>...</nav>
43
+ * <div neu-sidebar-footer>...</div>
44
+ * </neu-sidebar>
45
+ *
46
+ * Abrir desde cualquier parte: / Open from anywhere:
47
+ * inject(NeuUrlStateService).setParam('menu', 'open', false);
48
+ */
49
+ class NeuSidebarComponent {
50
+ document = inject(DOCUMENT);
51
+ urlState = inject(NeuUrlStateService);
52
+ /** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */
53
+ side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
54
+ /** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */
55
+ urlParam = input('menu', ...(ngDevMode ? [{ debugName: "urlParam" }] : /* istanbul ignore next */ []));
56
+ /**
57
+ * Modo persistente: el sidebar está siempre visible como parte del layout.
58
+ * Usar en desktop (≥768px). El overlay y el toggle por URL no aplican.
59
+ */
60
+ persistent = input(false, ...(ngDevMode ? [{ debugName: "persistent" }] : /* istanbul ignore next */ []));
61
+ /**
62
+ * Ocultar la cabecera del sidebar. Útil cuando el header ya está en el layout
63
+ * principal y el sidebar persistente no necesita su propio header.
64
+ */
65
+ hideHeader = input(false, ...(ngDevMode ? [{ debugName: "hideHeader" }] : /* istanbul ignore next */ []));
66
+ /** Etiqueta accesible para el <aside> / Accessible label for the <aside> */
67
+ ariaLabel = input('Menú de navegación', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
68
+ /** Etiqueta accesible para el botón cerrar / Accessible label for the close button */
69
+ closeLabel = input('Cerrar menú de navegación', ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
70
+ /** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */
71
+ closeRequested = output();
72
+ /** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */
73
+ isOpen = computed(() => {
74
+ if (this.persistent())
75
+ return true;
76
+ return this.urlState.getParam(this.urlParam())() === 'open';
77
+ }, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
78
+ constructor() {
79
+ effect((onCleanup) => {
80
+ const shouldLockScroll = !this.persistent() && this.isOpen();
81
+ if (!shouldLockScroll) {
82
+ return;
83
+ }
84
+ lockDocumentScroll(this.document);
85
+ onCleanup(() => {
86
+ unlockDocumentScroll(this.document);
87
+ });
88
+ });
89
+ }
90
+ /** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */
91
+ open(replaceUrl = false) {
92
+ this.urlState.setParam(this.urlParam(), 'open', replaceUrl);
93
+ }
94
+ /** Cierra el sidebar — elimina el parámetro de la URL / Closes the sidebar — removes the URL parameter */
95
+ close() {
96
+ this.urlState.setParam(this.urlParam(), null, true);
97
+ this.closeRequested.emit();
98
+ }
99
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
100
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuSidebarComponent, isStandalone: true, selector: "neu-sidebar", inputs: { side: { classPropertyName: "side", publicName: "side", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null }, persistent: { classPropertyName: "persistent", publicName: "persistent", isSignal: true, isRequired: false, transformFunction: null }, hideHeader: { classPropertyName: "hideHeader", publicName: "hideHeader", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested" }, ngImport: i0, template: `
101
+ <!-- Overlay de fondo — solo visible en modo overlay -->
102
+ @if (!persistent()) {
103
+ <div
104
+ class="neu-sidebar__overlay"
105
+ [class.neu-sidebar__overlay--visible]="isOpen()"
106
+ (click)="close()"
107
+ aria-hidden="true"
108
+ ></div>
109
+ }
110
+
111
+ <!-- Panel lateral -->
112
+ <aside
113
+ class="neu-sidebar"
114
+ [class.neu-sidebar--open]="isOpen()"
115
+ [class.neu-sidebar--persistent]="persistent()"
116
+ [class.neu-sidebar--right]="side() === 'right'"
117
+ role="navigation"
118
+ [attr.aria-label]="ariaLabel()"
119
+ [attr.aria-hidden]="!isOpen() && !persistent()"
120
+ [attr.inert]="!isOpen() && !persistent() ? '' : null"
121
+ >
122
+ <!-- Cabecera -->
123
+ @if (!hideHeader()) {
124
+ <div class="neu-sidebar__header">
125
+ <div class="neu-sidebar__title">
126
+ <ng-content select="[neu-sidebar-header]" />
127
+ </div>
128
+ @if (!persistent()) {
129
+ <button
130
+ class="neu-sidebar__close"
131
+ (click)="close()"
132
+ [attr.aria-label]="closeLabel()"
133
+ type="button"
134
+ >
135
+ <neu-icon name="lucideX" size="18px" aria-hidden="true" />
136
+ </button>
137
+ }
138
+ </div>
139
+ }
140
+
141
+ <!-- Contenido -->
142
+ <div class="neu-sidebar__content">
143
+ <ng-content />
144
+ </div>
145
+
146
+ <!-- Footer -->
147
+ <div class="neu-sidebar__footer">
148
+ <ng-content select="[neu-sidebar-footer]" />
149
+ </div>
150
+ </aside>
151
+ `, isInline: true, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}\n"], dependencies: [{ kind: "component", type: NeuIconComponent, selector: "neu-icon", inputs: ["name", "strokeWidth", "size"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
152
+ }
153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSidebarComponent, decorators: [{
154
+ type: Component,
155
+ args: [{ selector: 'neu-sidebar', imports: [NeuIconComponent], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
156
+ <!-- Overlay de fondo — solo visible en modo overlay -->
157
+ @if (!persistent()) {
158
+ <div
159
+ class="neu-sidebar__overlay"
160
+ [class.neu-sidebar__overlay--visible]="isOpen()"
161
+ (click)="close()"
162
+ aria-hidden="true"
163
+ ></div>
164
+ }
165
+
166
+ <!-- Panel lateral -->
167
+ <aside
168
+ class="neu-sidebar"
169
+ [class.neu-sidebar--open]="isOpen()"
170
+ [class.neu-sidebar--persistent]="persistent()"
171
+ [class.neu-sidebar--right]="side() === 'right'"
172
+ role="navigation"
173
+ [attr.aria-label]="ariaLabel()"
174
+ [attr.aria-hidden]="!isOpen() && !persistent()"
175
+ [attr.inert]="!isOpen() && !persistent() ? '' : null"
176
+ >
177
+ <!-- Cabecera -->
178
+ @if (!hideHeader()) {
179
+ <div class="neu-sidebar__header">
180
+ <div class="neu-sidebar__title">
181
+ <ng-content select="[neu-sidebar-header]" />
182
+ </div>
183
+ @if (!persistent()) {
184
+ <button
185
+ class="neu-sidebar__close"
186
+ (click)="close()"
187
+ [attr.aria-label]="closeLabel()"
188
+ type="button"
189
+ >
190
+ <neu-icon name="lucideX" size="18px" aria-hidden="true" />
191
+ </button>
192
+ }
193
+ </div>
194
+ }
195
+
196
+ <!-- Contenido -->
197
+ <div class="neu-sidebar__content">
198
+ <ng-content />
199
+ </div>
200
+
201
+ <!-- Footer -->
202
+ <div class="neu-sidebar__footer">
203
+ <ng-content select="[neu-sidebar-footer]" />
204
+ </div>
205
+ </aside>
206
+ `, styles: [".neu-sidebar__overlay{position:fixed;inset:0;background:var(--neu-overlay-bg-soft);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);z-index:var(--neu-z-overlay);opacity:0;pointer-events:none;transition:opacity var(--neu-transition-slow)}.neu-sidebar__overlay--visible{opacity:1;pointer-events:all}.neu-sidebar{position:fixed;top:0;left:0;height:100dvh;width:100%;background:var(--neu-sidebar-bg, var(--neu-surface));border-right:1px solid var(--neu-border);z-index:var(--neu-z-sidebar);display:flex;flex-direction:column;transform:translate(-100%);transition:transform var(--neu-transition-slow),box-shadow var(--neu-transition-slow);overflow:hidden}@media(min-width:400px){.neu-sidebar{width:var(--neu-sidebar-width, 260px)}}.neu-sidebar--open:not(.neu-sidebar--persistent):not(.neu-sidebar--right){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--right{left:auto;right:0;border-right:none;border-left:1px solid var(--neu-border);transform:translate(100%)}.neu-sidebar--right.neu-sidebar--open:not(.neu-sidebar--persistent){transform:translate(0);box-shadow:var(--neu-shadow-lg)}.neu-sidebar--persistent{position:sticky;top:var(--neu-header-height);height:calc(100dvh - var(--neu-header-height));transform:none;box-shadow:none;border-right:1px solid var(--neu-border);flex-shrink:0;z-index:var(--neu-z-base)}.neu-sidebar__header{display:flex;align-items:center;justify-content:space-between;padding:0 var(--neu-space-5);min-height:var(--neu-header-height, 64px);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__title{font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);font-weight:700;letter-spacing:-.01em;color:var(--neu-text)}.neu-sidebar__close{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--neu-radius);color:var(--neu-text-muted);cursor:pointer;flex-shrink:0;transition:background-color var(--neu-transition),color var(--neu-transition),border-color var(--neu-transition)}.neu-sidebar__close:hover{background:var(--neu-surface-2);color:var(--neu-text);border-color:var(--neu-border)}.neu-sidebar__close:focus-visible{outline:none;box-shadow:var(--neu-focus-ring-strong)}.neu-sidebar__content{flex:1;overflow-y:auto;overflow-x:hidden;padding:var(--neu-space-3) 0;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent}.neu-sidebar__content::-webkit-scrollbar{width:4px}.neu-sidebar__content::-webkit-scrollbar-track{background:transparent}.neu-sidebar__content::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:var(--neu-radius-full)}.neu-sidebar__footer{padding:var(--neu-space-4) var(--neu-space-5);border-top:1px solid var(--neu-border);flex-shrink:0}.neu-sidebar__footer:empty{display:none}\n"] }]
207
+ }], ctorParameters: () => [], propDecorators: { side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], persistent: [{ type: i0.Input, args: [{ isSignal: true, alias: "persistent", required: false }] }], hideHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideHeader", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] } });
208
+
209
+ /**
210
+ * Generated bundle index. Do not edit.
211
+ */
212
+
213
+ export { NeuSidebarComponent };
214
+ //# sourceMappingURL=neural-ui-core-sidebar.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-sidebar.mjs","sources":["../../../../projects/ui-core/sidebar/neu-sidebar.component.ts","../../../../projects/ui-core/sidebar/neural-ui-core-sidebar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { NeuUrlStateService } from '@neural-ui/core/url-state';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\n\nlet overlayScrollLockCount = 0;\nlet previousHtmlOverflow = '';\nlet previousBodyOverflow = '';\n\nfunction lockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n previousHtmlOverflow = document.documentElement.style.overflow;\n previousBodyOverflow = document.body.style.overflow;\n document.documentElement.style.overflow = 'hidden';\n document.body.style.overflow = 'hidden';\n }\n\n overlayScrollLockCount += 1;\n}\n\nfunction unlockDocumentScroll(document: Document): void {\n if (overlayScrollLockCount === 0) {\n return;\n }\n\n overlayScrollLockCount -= 1;\n\n if (overlayScrollLockCount === 0) {\n document.documentElement.style.overflow = previousHtmlOverflow;\n document.body.style.overflow = previousBodyOverflow;\n }\n}\n\n/**\n * NeuralUI Sidebar Component\n *\n * El estado abierto/cerrado se gestiona automáticamente desde la URL / The open/closed state is automatically managed from the URL\n * via NeuUrlStateService (?menu=open por defecto). / via NeuUrlStateService (?menu=open by default).\n *\n * Modos:\n * - overlay (default): panel flotante sobre el contenido con backdrop / floating panel above content with backdrop\n * - persistent: sidebar fijo integrado en el layout (desktop) / fixed sidebar integrated in the layout (desktop)\n *\n * Uso:\n * <neu-sidebar urlParam=\"menu\" [persistent]=\"isDesktop()\">\n * <span neu-sidebar-header>Mi App</span>\n * <nav>...</nav>\n * <div neu-sidebar-footer>...</div>\n * </neu-sidebar>\n *\n * Abrir desde cualquier parte: / Open from anywhere:\n * inject(NeuUrlStateService).setParam('menu', 'open', false);\n */\n@Component({\n selector: 'neu-sidebar',\n imports: [NeuIconComponent],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <!-- Overlay de fondo — solo visible en modo overlay -->\n @if (!persistent()) {\n <div\n class=\"neu-sidebar__overlay\"\n [class.neu-sidebar__overlay--visible]=\"isOpen()\"\n (click)=\"close()\"\n aria-hidden=\"true\"\n ></div>\n }\n\n <!-- Panel lateral -->\n <aside\n class=\"neu-sidebar\"\n [class.neu-sidebar--open]=\"isOpen()\"\n [class.neu-sidebar--persistent]=\"persistent()\"\n [class.neu-sidebar--right]=\"side() === 'right'\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-hidden]=\"!isOpen() && !persistent()\"\n [attr.inert]=\"!isOpen() && !persistent() ? '' : null\"\n >\n <!-- Cabecera -->\n @if (!hideHeader()) {\n <div class=\"neu-sidebar__header\">\n <div class=\"neu-sidebar__title\">\n <ng-content select=\"[neu-sidebar-header]\" />\n </div>\n @if (!persistent()) {\n <button\n class=\"neu-sidebar__close\"\n (click)=\"close()\"\n [attr.aria-label]=\"closeLabel()\"\n type=\"button\"\n >\n <neu-icon name=\"lucideX\" size=\"18px\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n }\n\n <!-- Contenido -->\n <div class=\"neu-sidebar__content\">\n <ng-content />\n </div>\n\n <!-- Footer -->\n <div class=\"neu-sidebar__footer\">\n <ng-content select=\"[neu-sidebar-footer]\" />\n </div>\n </aside>\n `,\n styleUrl: './neu-sidebar.component.scss',\n})\nexport class NeuSidebarComponent {\n private readonly document = inject(DOCUMENT);\n private readonly urlState = inject(NeuUrlStateService);\n\n /** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */\n side = input<'left' | 'right'>('left');\n\n /** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */\n urlParam = input<string>('menu');\n\n /**\n * Modo persistente: el sidebar está siempre visible como parte del layout.\n * Usar en desktop (≥768px). El overlay y el toggle por URL no aplican.\n */\n persistent = input<boolean>(false);\n\n /**\n * Ocultar la cabecera del sidebar. Útil cuando el header ya está en el layout\n * principal y el sidebar persistente no necesita su propio header.\n */\n hideHeader = input<boolean>(false);\n\n /** Etiqueta accesible para el <aside> / Accessible label for the <aside> */\n ariaLabel = input<string>('Menú de navegación');\n\n /** Etiqueta accesible para el botón cerrar / Accessible label for the close button */\n closeLabel = input<string>('Cerrar menú de navegación');\n\n /** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */\n closeRequested = output<void>();\n\n /** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */\n readonly isOpen = computed(() => {\n if (this.persistent()) return true;\n return this.urlState.getParam(this.urlParam())() === 'open';\n });\n\n constructor() {\n effect((onCleanup) => {\n const shouldLockScroll = !this.persistent() && this.isOpen();\n\n if (!shouldLockScroll) {\n return;\n }\n\n lockDocumentScroll(this.document);\n\n onCleanup(() => {\n unlockDocumentScroll(this.document);\n });\n });\n }\n\n /** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */\n open(replaceUrl = false): void {\n this.urlState.setParam(this.urlParam(), 'open', replaceUrl);\n }\n\n /** Cierra el sidebar — elimina el parámetro de la URL / Closes the sidebar — removes the URL parameter */\n close(): void {\n this.urlState.setParam(this.urlParam(), null, true);\n this.closeRequested.emit();\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,40 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+
4
+ /**
5
+ * NeuralUI Skeleton Component
6
+ *
7
+ * Placeholder animado para simular la carga de contenido.
8
+ *
9
+ * Uso:
10
+ * <neu-skeleton width="100%" height="20px" />
11
+ * <neu-skeleton variant="circle" width="40px" height="40px" />
12
+ * <neu-skeleton variant="text" />
13
+ */
14
+ class NeuSkeletonComponent {
15
+ variant = input('rect', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
16
+ width = input('100%', ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
17
+ height = input('16px', ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
18
+ borderRadius = input('', ...(ngDevMode ? [{ debugName: "borderRadius" }] : /* istanbul ignore next */ []));
19
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSkeletonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
20
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: NeuSkeletonComponent, isStandalone: true, selector: "neu-skeleton", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, borderRadius: { classPropertyName: "borderRadius", publicName: "borderRadius", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.neu-skeleton--text": "variant() === \"text\"", "class.neu-skeleton--circle": "variant() === \"circle\"", "class.neu-skeleton--rect": "variant() === \"rect\"", "style.width": "width()", "style.height": "height()", "style.border-radius": "borderRadius()" }, classAttribute: "neu-skeleton" }, ngImport: i0, template: '', isInline: true, styles: [".neu-skeleton{display:block;background:linear-gradient(90deg,var(--neu-surface-2) 25%,var(--neu-surface-3) 50%,var(--neu-surface-2) 75%);background-size:200% 100%;animation:neu-skeleton-shimmer 1.5s ease-in-out infinite}.neu-skeleton--rect{border-radius:var(--neu-radius)}.neu-skeleton--text{border-radius:var(--neu-radius-sm);height:14px;width:100%}.neu-skeleton--text:not(:last-child){margin-bottom:var(--neu-space-2)}.neu-skeleton--circle{border-radius:var(--neu-radius-full)}@keyframes neu-skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
21
+ }
22
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSkeletonComponent, decorators: [{
23
+ type: Component,
24
+ args: [{ selector: 'neu-skeleton', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
25
+ class: 'neu-skeleton',
26
+ '[class.neu-skeleton--text]': 'variant() === "text"',
27
+ '[class.neu-skeleton--circle]': 'variant() === "circle"',
28
+ '[class.neu-skeleton--rect]': 'variant() === "rect"',
29
+ '[style.width]': 'width()',
30
+ '[style.height]': 'height()',
31
+ '[style.border-radius]': 'borderRadius()',
32
+ }, template: '', styles: [".neu-skeleton{display:block;background:linear-gradient(90deg,var(--neu-surface-2) 25%,var(--neu-surface-3) 50%,var(--neu-surface-2) 75%);background-size:200% 100%;animation:neu-skeleton-shimmer 1.5s ease-in-out infinite}.neu-skeleton--rect{border-radius:var(--neu-radius)}.neu-skeleton--text{border-radius:var(--neu-radius-sm);height:14px;width:100%}.neu-skeleton--text:not(:last-child){margin-bottom:var(--neu-space-2)}.neu-skeleton--circle{border-radius:var(--neu-radius-full)}@keyframes neu-skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}\n"] }]
33
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], borderRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "borderRadius", required: false }] }] } });
34
+
35
+ /**
36
+ * Generated bundle index. Do not edit.
37
+ */
38
+
39
+ export { NeuSkeletonComponent };
40
+ //# sourceMappingURL=neural-ui-core-skeleton.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-skeleton.mjs","sources":["../../../../projects/ui-core/skeleton/neu-skeleton.component.ts","../../../../projects/ui-core/skeleton/neural-ui-core-skeleton.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, input } from '@angular/core';\n\n/**\n * NeuralUI Skeleton Component\n *\n * Placeholder animado para simular la carga de contenido.\n *\n * Uso:\n * <neu-skeleton width=\"100%\" height=\"20px\" />\n * <neu-skeleton variant=\"circle\" width=\"40px\" height=\"40px\" />\n * <neu-skeleton variant=\"text\" />\n */\n@Component({\n selector: 'neu-skeleton',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'neu-skeleton',\n '[class.neu-skeleton--text]': 'variant() === \"text\"',\n '[class.neu-skeleton--circle]': 'variant() === \"circle\"',\n '[class.neu-skeleton--rect]': 'variant() === \"rect\"',\n '[style.width]': 'width()',\n '[style.height]': 'height()',\n '[style.border-radius]': 'borderRadius()',\n },\n template: '',\n styleUrl: './neu-skeleton.component.scss',\n})\nexport class NeuSkeletonComponent {\n readonly variant = input<'text' | 'circle' | 'rect'>('rect');\n readonly width = input<string>('100%');\n readonly height = input<string>('16px');\n readonly borderRadius = input<string>('');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":";;;AAEA;;;;;;;;;AASG;MAiBU,oBAAoB,CAAA;AACtB,IAAA,OAAO,GAAG,KAAK,CAA6B,MAAM,8EAAC;AACnD,IAAA,KAAK,GAAG,KAAK,CAAS,MAAM,4EAAC;AAC7B,IAAA,MAAM,GAAG,KAAK,CAAS,MAAM,6EAAC;AAC9B,IAAA,YAAY,GAAG,KAAK,CAAS,EAAE,mFAAC;uGAJ9B,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAApB,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,oBAAoB,i5BAHrB,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,ikBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,aAAA,EAAA,EAAA,CAAA,iBAAA,CAAA,IAAA,EAAA,CAAA;;2FAGD,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAhBhC,SAAS;+BACE,cAAc,EAAA,aAAA,EACT,iBAAiB,CAAC,IAAI,mBACpB,uBAAuB,CAAC,MAAM,EAAA,IAAA,EACzC;AACJ,wBAAA,KAAK,EAAE,cAAc;AACrB,wBAAA,4BAA4B,EAAE,sBAAsB;AACpD,wBAAA,8BAA8B,EAAE,wBAAwB;AACxD,wBAAA,4BAA4B,EAAE,sBAAsB;AACpD,wBAAA,eAAe,EAAE,SAAS;AAC1B,wBAAA,gBAAgB,EAAE,UAAU;AAC5B,wBAAA,uBAAuB,EAAE,gBAAgB;AAC1C,qBAAA,EAAA,QAAA,EACS,EAAE,EAAA,MAAA,EAAA,CAAA,ikBAAA,CAAA,EAAA;;;ACzBd;;AAEG;;;;"}
@@ -0,0 +1,146 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, computed, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+
4
+ /**
5
+ * NeuralUI Slider Component
6
+ *
7
+ * Control deslizante accesible que envuelve el <input type="range">
8
+ * nativo con estilos personalizados y tooltips de valor.
9
+ *
10
+ * Uso:
11
+ * <neu-slider [value]="volume" (valueChange)="volume = $event" />
12
+ * <neu-slider [value]="50" [min]="0" [max]="100" [step]="5" [showValue]="true" />
13
+ */
14
+ class NeuSliderComponent {
15
+ static _idCounter = 0;
16
+ sliderId = `neu-slider-${++NeuSliderComponent._idCounter}`;
17
+ /** Valor actual / Current value */
18
+ value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
19
+ /** Valor mínimo / Minimum value */
20
+ min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
21
+ /** Valor máximo / Maximum value */
22
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
23
+ /** Paso / Step */
24
+ step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
25
+ /** Etiqueta / Label */
26
+ label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
27
+ /** Muestra el valor numerico / Shows the numeric value */
28
+ showValue = input(true, ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
29
+ /** Muestra min/mid/max bajo la barra / Shows min/mid/max below the bar */
30
+ showTicks = input(false, ...(ngDevMode ? [{ debugName: "showTicks" }] : /* istanbul ignore next */ []));
31
+ /** Unidad a mostrar junto al valor / Unit to display next to the value */
32
+ unit = input('', ...(ngDevMode ? [{ debugName: "unit" }] : /* istanbul ignore next */ []));
33
+ /** Deshabilitado / Disabled */
34
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
35
+ /** Emite al mover el slider / Emits when the slider moves */
36
+ valueChange = output();
37
+ fillPercent = computed(() => {
38
+ const range = this.max() - this.min();
39
+ if (range === 0)
40
+ return 0;
41
+ return ((this.value() - this.min()) / range) * 100;
42
+ }, ...(ngDevMode ? [{ debugName: "fillPercent" }] : /* istanbul ignore next */ []));
43
+ onInput(event) {
44
+ const val = Number(event.target.value);
45
+ this.valueChange.emit(val);
46
+ }
47
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
48
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuSliderComponent, isStandalone: true, selector: "neu-slider", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, showTicks: { classPropertyName: "showTicks", publicName: "showTicks", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: `
49
+ <div class="neu-slider" [class.neu-slider--disabled]="disabled()">
50
+ @if (label()) {
51
+ <div class="neu-slider__header">
52
+ <label class="neu-slider__label" [for]="sliderId">{{ label() }}</label>
53
+ @if (showValue()) {
54
+ <span class="neu-slider__value">{{ value() }}{{ unit() }}</span>
55
+ }
56
+ </div>
57
+ } @else if (showValue()) {
58
+ <div class="neu-slider__header">
59
+ <span></span>
60
+ <span class="neu-slider__value">{{ value() }}{{ unit() }}</span>
61
+ </div>
62
+ }
63
+ <div class="neu-slider__track-wrap">
64
+ <div class="neu-slider__track">
65
+ <div class="neu-slider__fill" [style.width.%]="fillPercent()"></div>
66
+ </div>
67
+ <input
68
+ class="neu-slider__input"
69
+ type="range"
70
+ [id]="sliderId"
71
+ [min]="min()"
72
+ [max]="max()"
73
+ [step]="step()"
74
+ [value]="value()"
75
+ [disabled]="disabled()"
76
+ [attr.aria-label]="label() || 'Slider'"
77
+ [attr.aria-valuenow]="value()"
78
+ [attr.aria-valuemin]="min()"
79
+ [attr.aria-valuemax]="max()"
80
+ (input)="onInput($event)"
81
+ />
82
+ </div>
83
+ @if (showTicks()) {
84
+ <div class="neu-slider__ticks">
85
+ <span>{{ min() }}{{ unit() }}</span>
86
+ <span>{{ (max() - min()) / 2 + min() }}{{ unit() }}</span>
87
+ <span>{{ max() }}{{ unit() }}</span>
88
+ </div>
89
+ }
90
+ </div>
91
+ `, isInline: true, styles: [".neu-slider{display:flex;flex-direction:column;gap:8px;width:100%;font-family:var(--neu-font-sans)}.neu-slider--disabled{opacity:.45;pointer-events:none}.neu-slider__header{display:flex;align-items:center;justify-content:space-between;gap:8px}.neu-slider__label{font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted)}.neu-slider__value{font-size:var(--neu-text-xs);font-weight:600;color:var(--neu-primary);min-width:32px;text-align:right}.neu-slider__track-wrap{position:relative;height:18px;display:flex;align-items:center}.neu-slider__track{position:absolute;left:0;right:0;height:4px;background:var(--neu-surface-3);border-radius:var(--neu-radius-full);pointer-events:none}.neu-slider__fill{height:100%;background:var(--neu-primary);border-radius:var(--neu-radius-full);transition:width .05s linear}.neu-slider__input{position:relative;width:100%;height:18px;margin:0;background:transparent;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;z-index:1}.neu-slider__input::-webkit-slider-runnable-track{background:transparent;height:4px}.neu-slider__input::-moz-range-track{background:transparent;height:4px}.neu-slider__input::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--neu-surface);border:2.5px solid var(--neu-primary);box-shadow:0 1px 4px #00000026;transition:box-shadow .15s;cursor:pointer;margin-top:-7px}.neu-slider__input::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:var(--neu-surface);border:2.5px solid var(--neu-primary);box-shadow:0 1px 4px #00000026;cursor:pointer}.neu-slider__input:hover::-webkit-slider-thumb,.neu-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px var(--neu-primary-100)}.neu-slider__input:focus-visible{outline:none}.neu-slider__ticks{display:flex;justify-content:space-between;font-size:var(--neu-text-xs);color:var(--neu-text-disabled)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
92
+ }
93
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuSliderComponent, decorators: [{
94
+ type: Component,
95
+ args: [{ selector: 'neu-slider', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
96
+ <div class="neu-slider" [class.neu-slider--disabled]="disabled()">
97
+ @if (label()) {
98
+ <div class="neu-slider__header">
99
+ <label class="neu-slider__label" [for]="sliderId">{{ label() }}</label>
100
+ @if (showValue()) {
101
+ <span class="neu-slider__value">{{ value() }}{{ unit() }}</span>
102
+ }
103
+ </div>
104
+ } @else if (showValue()) {
105
+ <div class="neu-slider__header">
106
+ <span></span>
107
+ <span class="neu-slider__value">{{ value() }}{{ unit() }}</span>
108
+ </div>
109
+ }
110
+ <div class="neu-slider__track-wrap">
111
+ <div class="neu-slider__track">
112
+ <div class="neu-slider__fill" [style.width.%]="fillPercent()"></div>
113
+ </div>
114
+ <input
115
+ class="neu-slider__input"
116
+ type="range"
117
+ [id]="sliderId"
118
+ [min]="min()"
119
+ [max]="max()"
120
+ [step]="step()"
121
+ [value]="value()"
122
+ [disabled]="disabled()"
123
+ [attr.aria-label]="label() || 'Slider'"
124
+ [attr.aria-valuenow]="value()"
125
+ [attr.aria-valuemin]="min()"
126
+ [attr.aria-valuemax]="max()"
127
+ (input)="onInput($event)"
128
+ />
129
+ </div>
130
+ @if (showTicks()) {
131
+ <div class="neu-slider__ticks">
132
+ <span>{{ min() }}{{ unit() }}</span>
133
+ <span>{{ (max() - min()) / 2 + min() }}{{ unit() }}</span>
134
+ <span>{{ max() }}{{ unit() }}</span>
135
+ </div>
136
+ }
137
+ </div>
138
+ `, styles: [".neu-slider{display:flex;flex-direction:column;gap:8px;width:100%;font-family:var(--neu-font-sans)}.neu-slider--disabled{opacity:.45;pointer-events:none}.neu-slider__header{display:flex;align-items:center;justify-content:space-between;gap:8px}.neu-slider__label{font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted)}.neu-slider__value{font-size:var(--neu-text-xs);font-weight:600;color:var(--neu-primary);min-width:32px;text-align:right}.neu-slider__track-wrap{position:relative;height:18px;display:flex;align-items:center}.neu-slider__track{position:absolute;left:0;right:0;height:4px;background:var(--neu-surface-3);border-radius:var(--neu-radius-full);pointer-events:none}.neu-slider__fill{height:100%;background:var(--neu-primary);border-radius:var(--neu-radius-full);transition:width .05s linear}.neu-slider__input{position:relative;width:100%;height:18px;margin:0;background:transparent;cursor:pointer;appearance:none;-webkit-appearance:none;outline:none;z-index:1}.neu-slider__input::-webkit-slider-runnable-track{background:transparent;height:4px}.neu-slider__input::-moz-range-track{background:transparent;height:4px}.neu-slider__input::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--neu-surface);border:2.5px solid var(--neu-primary);box-shadow:0 1px 4px #00000026;transition:box-shadow .15s;cursor:pointer;margin-top:-7px}.neu-slider__input::-moz-range-thumb{width:18px;height:18px;border-radius:50%;background:var(--neu-surface);border:2.5px solid var(--neu-primary);box-shadow:0 1px 4px #00000026;cursor:pointer}.neu-slider__input:hover::-webkit-slider-thumb,.neu-slider__input:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 4px var(--neu-primary-100)}.neu-slider__input:focus-visible{outline:none}.neu-slider__ticks{display:flex;justify-content:space-between;font-size:var(--neu-text-xs);color:var(--neu-text-disabled)}\n"] }]
139
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTicks", required: false }] }], unit: [{ type: i0.Input, args: [{ isSignal: true, alias: "unit", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
140
+
141
+ /**
142
+ * Generated bundle index. Do not edit.
143
+ */
144
+
145
+ export { NeuSliderComponent };
146
+ //# sourceMappingURL=neural-ui-core-slider.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"neural-ui-core-slider.mjs","sources":["../../../../projects/ui-core/slider/neu-slider.component.ts","../../../../projects/ui-core/slider/neural-ui-core-slider.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n input,\n output,\n} from '@angular/core';\n\n/**\n * NeuralUI Slider Component\n *\n * Control deslizante accesible que envuelve el <input type=\"range\">\n * nativo con estilos personalizados y tooltips de valor.\n *\n * Uso:\n * <neu-slider [value]=\"volume\" (valueChange)=\"volume = $event\" />\n * <neu-slider [value]=\"50\" [min]=\"0\" [max]=\"100\" [step]=\"5\" [showValue]=\"true\" />\n */\n@Component({\n selector: 'neu-slider',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-slider\" [class.neu-slider--disabled]=\"disabled()\">\n @if (label()) {\n <div class=\"neu-slider__header\">\n <label class=\"neu-slider__label\" [for]=\"sliderId\">{{ label() }}</label>\n @if (showValue()) {\n <span class=\"neu-slider__value\">{{ value() }}{{ unit() }}</span>\n }\n </div>\n } @else if (showValue()) {\n <div class=\"neu-slider__header\">\n <span></span>\n <span class=\"neu-slider__value\">{{ value() }}{{ unit() }}</span>\n </div>\n }\n <div class=\"neu-slider__track-wrap\">\n <div class=\"neu-slider__track\">\n <div class=\"neu-slider__fill\" [style.width.%]=\"fillPercent()\"></div>\n </div>\n <input\n class=\"neu-slider__input\"\n type=\"range\"\n [id]=\"sliderId\"\n [min]=\"min()\"\n [max]=\"max()\"\n [step]=\"step()\"\n [value]=\"value()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"label() || 'Slider'\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n (input)=\"onInput($event)\"\n />\n </div>\n @if (showTicks()) {\n <div class=\"neu-slider__ticks\">\n <span>{{ min() }}{{ unit() }}</span>\n <span>{{ (max() - min()) / 2 + min() }}{{ unit() }}</span>\n <span>{{ max() }}{{ unit() }}</span>\n </div>\n }\n </div>\n `,\n styleUrl: './neu-slider.component.scss',\n})\nexport class NeuSliderComponent {\n private static _idCounter = 0;\n protected readonly sliderId = `neu-slider-${++NeuSliderComponent._idCounter}`;\n\n /** Valor actual / Current value */\n value = input<number>(0);\n\n /** Valor mínimo / Minimum value */\n min = input<number>(0);\n\n /** Valor máximo / Maximum value */\n max = input<number>(100);\n\n /** Paso / Step */\n step = input<number>(1);\n\n /** Etiqueta / Label */\n label = input<string>('');\n\n /** Muestra el valor numerico / Shows the numeric value */\n showValue = input<boolean>(true);\n\n /** Muestra min/mid/max bajo la barra / Shows min/mid/max below the bar */\n showTicks = input<boolean>(false);\n\n /** Unidad a mostrar junto al valor / Unit to display next to the value */\n unit = input<string>('');\n\n /** Deshabilitado / Disabled */\n disabled = input<boolean>(false);\n\n /** Emite al mover el slider / Emits when the slider moves */\n valueChange = output<number>();\n\n readonly fillPercent = computed(() => {\n const range = this.max() - this.min();\n if (range === 0) return 0;\n return ((this.value() - this.min()) / range) * 100;\n });\n\n onInput(event: Event): void {\n const val = Number((event.target as HTMLInputElement).value);\n this.valueChange.emit(val);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}