@neural-ui/core 1.7.6 → 1.8.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 (77) hide show
  1. package/fesm2022/neural-ui-core-accordion.mjs +22 -8
  2. package/fesm2022/neural-ui-core-accordion.mjs.map +1 -1
  3. package/fesm2022/neural-ui-core-alert.mjs +1 -1
  4. package/fesm2022/neural-ui-core-alert.mjs.map +1 -1
  5. package/fesm2022/neural-ui-core-autocomplete.mjs +50 -9
  6. package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -1
  7. package/fesm2022/neural-ui-core-button.mjs +1 -1
  8. package/fesm2022/neural-ui-core-button.mjs.map +1 -1
  9. package/fesm2022/neural-ui-core-calendar.mjs +26 -18
  10. package/fesm2022/neural-ui-core-calendar.mjs.map +1 -1
  11. package/fesm2022/neural-ui-core-command-palette.mjs +22 -8
  12. package/fesm2022/neural-ui-core-command-palette.mjs.map +1 -1
  13. package/fesm2022/neural-ui-core-context-menu.mjs +24 -8
  14. package/fesm2022/neural-ui-core-context-menu.mjs.map +1 -1
  15. package/fesm2022/neural-ui-core-empty-state.mjs +1 -1
  16. package/fesm2022/neural-ui-core-empty-state.mjs.map +1 -1
  17. package/fesm2022/neural-ui-core-icon.mjs +9 -2
  18. package/fesm2022/neural-ui-core-icon.mjs.map +1 -1
  19. package/fesm2022/neural-ui-core-inline-editor.mjs +1 -1
  20. package/fesm2022/neural-ui-core-inline-editor.mjs.map +1 -1
  21. package/fesm2022/neural-ui-core-input.mjs +1 -1
  22. package/fesm2022/neural-ui-core-input.mjs.map +1 -1
  23. package/fesm2022/neural-ui-core-listbox.mjs +50 -5
  24. package/fesm2022/neural-ui-core-listbox.mjs.map +1 -1
  25. package/fesm2022/neural-ui-core-menu.mjs +38 -16
  26. package/fesm2022/neural-ui-core-menu.mjs.map +1 -1
  27. package/fesm2022/neural-ui-core-modal.mjs +1 -1
  28. package/fesm2022/neural-ui-core-modal.mjs.map +1 -1
  29. package/fesm2022/neural-ui-core-multiselect.mjs +67 -7
  30. package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -1
  31. package/fesm2022/neural-ui-core-nav.mjs +1 -1
  32. package/fesm2022/neural-ui-core-nav.mjs.map +1 -1
  33. package/fesm2022/neural-ui-core-pick-list.mjs +43 -16
  34. package/fesm2022/neural-ui-core-pick-list.mjs.map +1 -1
  35. package/fesm2022/neural-ui-core-select.mjs +64 -5
  36. package/fesm2022/neural-ui-core-select.mjs.map +1 -1
  37. package/fesm2022/neural-ui-core-sidebar.mjs +1 -1
  38. package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -1
  39. package/fesm2022/neural-ui-core-split-button.mjs +22 -8
  40. package/fesm2022/neural-ui-core-split-button.mjs.map +1 -1
  41. package/fesm2022/neural-ui-core-stats-card.mjs +1 -1
  42. package/fesm2022/neural-ui-core-stats-card.mjs.map +1 -1
  43. package/fesm2022/neural-ui-core-table.mjs +1 -1
  44. package/fesm2022/neural-ui-core-table.mjs.map +1 -1
  45. package/fesm2022/neural-ui-core-tabs.mjs +22 -9
  46. package/fesm2022/neural-ui-core-tabs.mjs.map +1 -1
  47. package/fesm2022/neural-ui-core-tags.mjs +40 -13
  48. package/fesm2022/neural-ui-core-tags.mjs.map +1 -1
  49. package/fesm2022/neural-ui-core-timeline.mjs +39 -10
  50. package/fesm2022/neural-ui-core-timeline.mjs.map +1 -1
  51. package/fesm2022/neural-ui-core-toast.mjs +1 -1
  52. package/fesm2022/neural-ui-core-toast.mjs.map +1 -1
  53. package/fesm2022/neural-ui-core-toggle-button-group.mjs +22 -8
  54. package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -1
  55. package/fesm2022/neural-ui-core-tree-select.mjs +86 -12
  56. package/fesm2022/neural-ui-core-tree-select.mjs.map +1 -1
  57. package/fesm2022/neural-ui-core-tree.mjs +21 -6
  58. package/fesm2022/neural-ui-core-tree.mjs.map +1 -1
  59. package/package.json +1 -1
  60. package/types/neural-ui-core-accordion.d.ts +16 -2
  61. package/types/neural-ui-core-autocomplete.d.ts +23 -2
  62. package/types/neural-ui-core-calendar.d.ts +18 -3
  63. package/types/neural-ui-core-command-palette.d.ts +24 -10
  64. package/types/neural-ui-core-context-menu.d.ts +17 -3
  65. package/types/neural-ui-core-icon.d.ts +5 -1
  66. package/types/neural-ui-core-listbox.d.ts +23 -2
  67. package/types/neural-ui-core-menu.d.ts +23 -3
  68. package/types/neural-ui-core-multiselect.d.ts +33 -2
  69. package/types/neural-ui-core-pick-list.d.ts +32 -3
  70. package/types/neural-ui-core-select.d.ts +30 -2
  71. package/types/neural-ui-core-split-button.d.ts +15 -3
  72. package/types/neural-ui-core-tabs.d.ts +16 -3
  73. package/types/neural-ui-core-tags.d.ts +35 -4
  74. package/types/neural-ui-core-timeline.d.ts +27 -2
  75. package/types/neural-ui-core-toggle-button-group.d.ts +16 -2
  76. package/types/neural-ui-core-tree-select.d.ts +51 -3
  77. package/types/neural-ui-core-tree.d.ts +18 -3
@@ -1 +1 @@
1
- {"version":3,"file":"neural-ui-core-nav.mjs","sources":["../../../../projects/ui-core/nav/neu-nav.component.ts","../../../../projects/ui-core/nav/neural-ui-core-nav.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';\nimport { filter } from 'rxjs';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\nimport { NeuTooltipDirective } from '@neural-ui/core/tooltip';\n\n// ---- Tipos públicos / Public types ----\n\n/**\n * Ítem de navegación con soporte para 3 niveles de profundidad.\n *\n * Destino del enlace — usa UNO de los dos:\n * - `route` → navegación interna Angular (RouterLink)\n * - `href` → URL externa, se abre en nueva pestaña con rel=\"noopener noreferrer\"\n *\n * Los ítems con `children` actúan como grupo acordeón (sin destino propio).\n * Máximo 3 niveles: raíz → hijos → nietos.\n * Los nietos no pueden tener `children`.\n */\nexport interface NeuNavItem {\n id: string;\n label: string;\n icon: string;\n /** Ruta Angular interna (RouterLink). Excluye `href`. / Internal Angular route (RouterLink). Excludes `href`. */\n route?: string;\n /** URL externa. Se abre en nueva pestaña. Excluye `route`. / External URL. Opens in a new tab. Excludes `route`. */\n href?: string;\n /** Ítems hijo (nivel 2). Cada hijo puede tener sus propios `children` (nivel 3). / Child items (level 2). Each child can have its own `children` (level 3). */\n children?: NeuNavItem[];\n badge?: string;\n badgeVariant?: 'default' | 'success' | 'warning' | 'danger' | 'info';\n disabled?: boolean;\n}\n\n@Component({\n selector: 'neu-nav',\n imports: [RouterLink, RouterLinkActive, NeuIconComponent, NeuTooltipDirective],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-nav-wrapper\" [class.neu-nav-wrapper--collapsed]=\"isCollapsed()\">\n <nav\n class=\"neu-nav\"\n [class.neu-nav--collapsed]=\"isCollapsed()\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <!-- Brand slot -->\n <div class=\"neu-nav__brand\">\n <!-- Icono visible solo en modo colapsado -->\n <div class=\"neu-nav__brand-icon\">\n <ng-content select=\"[neu-nav-brand-icon]\" />\n </div>\n <!-- Contenido completo visible en modo expandido -->\n <div class=\"neu-nav__brand-content\">\n <ng-content select=\"[neu-nav-brand]\" />\n </div>\n </div>\n\n <!-- Items (nivel 1) -->\n <div class=\"neu-nav__items\" role=\"list\">\n @for (item of items(); track item.id) {\n @if (item.children?.length) {\n <!-- NIVEL 1 — Grupo acordeón -->\n <div\n class=\"neu-nav__group\"\n [class.neu-nav__group--open]=\"isGroupOpen(item.id)\"\n role=\"listitem\"\n (mouseenter)=\"onGroupMouseEnter(item, $event)\"\n (mouseleave)=\"onGroupMouseLeave()\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(item)\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(item.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"item.disabled ? '' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n (click)=\"!isCollapsed() && toggleGroup(item.id)\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"14px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 2 -->\n @if (!isCollapsed() && isGroupOpen(item.id)) {\n <div class=\"neu-nav__submenu\" role=\"list\">\n @for (child of item.children; track child.id) {\n @if (child.children?.length) {\n <!-- NIVEL 2 — Subgrupo acordeón -->\n <div\n class=\"neu-nav__group neu-nav__group--nested\"\n [class.neu-nav__group--open]=\"isGroupOpen(child.id)\"\n role=\"listitem\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--child neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(child)\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(child.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"child.disabled ? '' : null\"\n (click)=\"toggleGroup(child.id)\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"13px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 3 -->\n @if (isGroupOpen(child.id)) {\n <div class=\"neu-nav__submenu neu-nav__submenu--nested\" role=\"list\">\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <!-- NIVEL 3 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [href]=\"grand.disabled ? null : grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"grand.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"11px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 3 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [routerLink]=\"grand.disabled ? null : (grand.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"\n isCurrentRoute(grand.route ?? '') ? 'page' : null\n \"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n @if (grand.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n grand.badgeVariant ?? 'default'\n }}\"\n >{{ grand.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (child.href) {\n <!-- NIVEL 2 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [href]=\"child.disabled ? null : child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"12px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 2 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [routerLink]=\"child.disabled ? null : (child.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"isCurrentRoute(child.route ?? '') ? 'page' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (item.href) {\n <!-- NIVEL 1 — Enlace externo -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [href]=\"item.disabled ? null : item.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"13px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 1 — Enlace interno -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [routerLink]=\"item.disabled ? null : (item.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: item.route === '/' }\"\n [attr.aria-current]=\"isCurrentRoute(item.route ?? '') ? 'page' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n\n <!-- Footer slot -->\n <div class=\"neu-nav__footer\">\n <ng-content select=\"[neu-nav-footer]\" />\n </div>\n </nav>\n\n <!-- Flyout panel para grupos en modo colapsado -->\n @if (flyoutState(); as flyout) {\n <div\n class=\"neu-nav__flyout\"\n [style.top.px]=\"flyout.top\"\n [style.left.px]=\"flyout.left\"\n role=\"menu\"\n (mouseenter)=\"onFlyoutMouseEnter()\"\n (mouseleave)=\"onFlyoutMouseLeave()\"\n >\n <div class=\"neu-nav__flyout-title\">{{ flyout.item.label }}</div>\n @for (child of flyout.item.children ?? []; track child.id) {\n @if (child.children?.length) {\n <div class=\"neu-nav__flyout-group\">\n <span class=\"neu-nav__flyout-group-label\">{{ child.label }}</span>\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"10px\"\n class=\"neu-nav__external-icon\"\n />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"grand.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n </a>\n }\n }\n </div>\n } @else if (child.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n <neu-icon name=\"lucideExternalLink\" size=\"10px\" class=\"neu-nav__external-icon\" />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n </a>\n }\n }\n </div>\n }\n\n <!-- Pestaña collapse/expand — fuera del nav para no ser recortada -->\n @if (collapsible()) {\n <button\n class=\"neu-nav__toggle-tab\"\n type=\"button\"\n [attr.aria-label]=\"isCollapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n (click)=\"toggleCollapse()\"\n >\n <neu-icon\n [name]=\"isCollapsed() ? 'lucideChevronRight' : 'lucideChevronLeft'\"\n size=\"12px\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n `,\n styleUrl: './neu-nav.component.scss',\n})\nexport class NeuNavComponent {\n private readonly router = inject(Router);\n\n // ---- Señal reactiva de ruta activa / Reactive active route signal ----\n private readonly currentUrl = toSignal(\n this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)),\n { initialValue: null },\n );\n\n // ---- Inputs ----\n\n /** Lista de ítems de navegación / Navigation item list */\n items = input<NeuNavItem[]>([]);\n\n /** Estado inicial colapsado / Initial collapsed state */\n collapsed = input<boolean>(false);\n\n /** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */\n collapsible = input<boolean>(true);\n\n /** Etiqueta accesible del <nav> / Accessible label for the <nav> */\n ariaLabel = input<string>('Navegación principal');\n\n /** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */\n expandLabel = input<string>('Expandir menú');\n\n /** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */\n collapseLabel = input<string>('Colapsar menú');\n\n /** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */\n collapsedChange = output<boolean>();\n\n // ---- Estado interno / Internal state ----\n\n // Sigue el input `collapsed` del padre (permite el configurador)\n // pero puede ser sobreescrito localmente con toggleCollapse()\n readonly isCollapsed = linkedSignal(() => this.collapsed());\n private readonly openGroups = signal<Set<string>>(new Set());\n\n // ---- Flyout para modo colapsado / Flyout for collapsed mode ----\n readonly flyoutState = signal<{ item: NeuNavItem; top: number; left: number } | null>(null);\n private _flyoutTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n // Abrimos el grupo activo DESPUÉS de que el padre haya pasado los inputs\n afterNextRender(() => this._openActiveGroup());\n // Limpiamos el timer del flyout al destruir el componente\n inject(DestroyRef).onDestroy(() => {\n if (this._flyoutTimer) clearTimeout(this._flyoutTimer);\n });\n }\n\n // ---- Helpers de estado / State helpers ----\n\n toggleCollapse(): void {\n this.isCollapsed.update((v) => {\n const next = !v;\n this.collapsedChange.emit(next);\n return next;\n });\n }\n\n toggleGroup(id: string): void {\n this.openGroups.update((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n isGroupOpen(id: string): boolean {\n return this.openGroups().has(id);\n }\n\n isCurrentRoute(route: string): boolean {\n if (!route) return false;\n // Consume la señal para que OnPush re-evalúe tras navegación\n this.currentUrl();\n return this.router.url === route || this.router.url.startsWith(route + '?');\n }\n\n isGroupActive(item: NeuNavItem): boolean {\n if (!item.children?.length) return false;\n return item.children.some(\n (c) =>\n this.isCurrentRoute(c.route ?? '') ||\n (c.children?.some((g) => this.isCurrentRoute(g.route ?? '')) ?? false),\n );\n }\n\n // ---- Flyout handlers ----\n\n onGroupMouseEnter(item: NeuNavItem, event: MouseEvent): void {\n if (!this.isCollapsed() || !item.children?.length) return;\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n this.flyoutState.set({ item, top: rect.top, left: rect.right });\n }\n\n onGroupMouseLeave(): void {\n if (!this.isCollapsed()) return;\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n onFlyoutMouseEnter(): void {\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n }\n\n onFlyoutMouseLeave(): void {\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n private _openActiveGroup(): void {\n const toOpen = new Set<string>();\n for (const item of this.items()) {\n if (!item.children) continue;\n for (const child of item.children) {\n if (child.route && this.router.url.startsWith(child.route)) {\n toOpen.add(item.id);\n }\n if (child.children) {\n for (const grand of child.children) {\n if (grand.route && this.router.url.startsWith(grand.route)) {\n toOpen.add(item.id);\n toOpen.add(child.id);\n }\n }\n }\n }\n }\n if (toOpen.size > 0) {\n this.openGroups.set(toOpen);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"neural-ui-core-nav.mjs","sources":["../../../../projects/ui-core/nav/neu-nav.component.ts","../../../../projects/ui-core/nav/neural-ui-core-nav.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ViewEncapsulation,\n afterNextRender,\n inject,\n input,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { RouterLink, RouterLinkActive, Router, NavigationEnd } from '@angular/router';\nimport { filter } from 'rxjs';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { NeuIconComponent } from '@neural-ui/core/icon';\nimport { NeuTooltipDirective } from '@neural-ui/core/tooltip';\n\n// ---- Tipos públicos / Public types ----\n\n/**\n * Ítem de navegación con soporte para 3 niveles de profundidad.\n *\n * Destino del enlace — usa UNO de los dos:\n * - `route` → navegación interna Angular (RouterLink)\n * - `href` → URL externa, se abre en nueva pestaña con rel=\"noopener noreferrer\"\n *\n * Los ítems con `children` actúan como grupo acordeón (sin destino propio).\n * Máximo 3 niveles: raíz → hijos → nietos.\n * Los nietos no pueden tener `children`.\n */\nexport interface NeuNavItem {\n id: string;\n label: string;\n icon: string;\n /** Ruta Angular interna (RouterLink). Excluye `href`. / Internal Angular route (RouterLink). Excludes `href`. */\n route?: string;\n /** URL externa. Se abre en nueva pestaña. Excluye `route`. / External URL. Opens in a new tab. Excludes `route`. */\n href?: string;\n /** Ítems hijo (nivel 2). Cada hijo puede tener sus propios `children` (nivel 3). / Child items (level 2). Each child can have its own `children` (level 3). */\n children?: NeuNavItem[];\n badge?: string;\n badgeVariant?: 'default' | 'success' | 'warning' | 'danger' | 'info';\n disabled?: boolean;\n}\n\n@Component({\n selector: 'neu-nav',\n imports: [RouterLink, RouterLinkActive, NeuIconComponent, NeuTooltipDirective],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-nav-wrapper\" [class.neu-nav-wrapper--collapsed]=\"isCollapsed()\">\n <nav\n class=\"neu-nav\"\n [class.neu-nav--collapsed]=\"isCollapsed()\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <!-- Brand slot -->\n <div class=\"neu-nav__brand\">\n <!-- Icono visible solo en modo colapsado -->\n <div class=\"neu-nav__brand-icon\">\n <ng-content select=\"[neu-nav-brand-icon]\" />\n </div>\n <!-- Contenido completo visible en modo expandido -->\n <div class=\"neu-nav__brand-content\">\n <ng-content select=\"[neu-nav-brand]\" />\n </div>\n </div>\n\n <!-- Items (nivel 1) -->\n <div class=\"neu-nav__items\" role=\"list\">\n @for (item of items(); track item.id) {\n @if (item.children?.length) {\n <!-- NIVEL 1 — Grupo acordeón -->\n <div\n class=\"neu-nav__group\"\n [class.neu-nav__group--open]=\"isGroupOpen(item.id)\"\n role=\"listitem\"\n (mouseenter)=\"onGroupMouseEnter(item, $event)\"\n (mouseleave)=\"onGroupMouseLeave()\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(item)\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(item.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"item.disabled ? '' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n (click)=\"!isCollapsed() && toggleGroup(item.id)\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"14px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 2 -->\n @if (!isCollapsed() && isGroupOpen(item.id)) {\n <div class=\"neu-nav__submenu\" role=\"list\">\n @for (child of item.children; track child.id) {\n @if (child.children?.length) {\n <!-- NIVEL 2 — Subgrupo acordeón -->\n <div\n class=\"neu-nav__group neu-nav__group--nested\"\n [class.neu-nav__group--open]=\"isGroupOpen(child.id)\"\n role=\"listitem\"\n >\n <button\n class=\"neu-nav__item neu-nav__item--child neu-nav__item--parent\"\n type=\"button\"\n [class.neu-nav__item--active]=\"isGroupActive(child)\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [attr.aria-expanded]=\"isGroupOpen(child.id)\"\n [attr.aria-haspopup]=\"true\"\n [attr.disabled]=\"child.disabled ? '' : null\"\n (click)=\"toggleGroup(child.id)\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideChevronRight\"\n size=\"13px\"\n class=\"neu-nav__group-chevron\"\n aria-hidden=\"true\"\n />\n </button>\n\n <!-- Submenú nivel 3 -->\n @if (isGroupOpen(child.id)) {\n <div class=\"neu-nav__submenu neu-nav__submenu--nested\" role=\"list\">\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <!-- NIVEL 3 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [href]=\"grand.disabled ? null : grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"grand.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"11px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 3 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--grandchild\"\n [class.neu-nav__item--disabled]=\"grand.disabled\"\n [routerLink]=\"grand.disabled ? null : (grand.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"\n isCurrentRoute(grand.route ?? '') ? 'page' : null\n \"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"grand.icon\"\n size=\"14px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ grand.label }}</span>\n @if (grand.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n grand.badgeVariant ?? 'default'\n }}\"\n >{{ grand.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (child.href) {\n <!-- NIVEL 2 — Enlace externo -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [href]=\"child.disabled ? null : child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"child.disabled ? 'true' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"12px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 2 — Enlace interno -->\n <a\n class=\"neu-nav__item neu-nav__item--child\"\n [class.neu-nav__item--disabled]=\"child.disabled\"\n [routerLink]=\"child.disabled ? null : (child.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n [attr.aria-current]=\"isCurrentRoute(child.route ?? '') ? 'page' : null\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"child.icon\"\n size=\"15px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ child.label }}</span>\n @if (child.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n child.badgeVariant ?? 'default'\n }}\"\n >{{ child.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n }\n </div>\n } @else if (item.href) {\n <!-- NIVEL 1 — Enlace externo -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [href]=\"item.disabled ? null : item.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.aria-disabled]=\"item.disabled ? 'true' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"13px\"\n class=\"neu-nav__external-icon\"\n aria-hidden=\"true\"\n />\n </a>\n } @else {\n <!-- NIVEL 1 — Enlace interno -->\n <a\n class=\"neu-nav__item\"\n [class.neu-nav__item--disabled]=\"item.disabled\"\n [routerLink]=\"item.disabled ? null : (item.route ?? null)\"\n routerLinkActive=\"neu-nav__item--active\"\n [routerLinkActiveOptions]=\"{ exact: item.route === '/' }\"\n [attr.aria-current]=\"isCurrentRoute(item.route ?? '') ? 'page' : null\"\n [neuTooltip]=\"isCollapsed() ? item.label : ''\"\n neuTooltipPosition=\"right\"\n role=\"listitem\"\n >\n <neu-icon\n [name]=\"item.icon\"\n size=\"18px\"\n class=\"neu-nav__item-icon\"\n aria-hidden=\"true\"\n />\n <span class=\"neu-nav__item-label\">{{ item.label }}</span>\n @if (item.badge) {\n <span\n class=\"neu-nav__item-badge neu-nav__item-badge--{{\n item.badgeVariant ?? 'default'\n }}\"\n >{{ item.badge }}</span\n >\n }\n </a>\n }\n }\n </div>\n\n <!-- Footer slot -->\n <div class=\"neu-nav__footer\">\n <ng-content select=\"[neu-nav-footer]\" />\n </div>\n </nav>\n\n <!-- Flyout panel para grupos en modo colapsado -->\n @if (flyoutState(); as flyout) {\n <div\n class=\"neu-nav__flyout\"\n [style.top.px]=\"flyout.top\"\n [style.left.px]=\"flyout.left\"\n role=\"menu\"\n (mouseenter)=\"onFlyoutMouseEnter()\"\n (mouseleave)=\"onFlyoutMouseLeave()\"\n >\n <div class=\"neu-nav__flyout-title\">{{ flyout.item.label }}</div>\n @for (child of flyout.item.children ?? []; track child.id) {\n @if (child.children?.length) {\n <div class=\"neu-nav__flyout-group\">\n <span class=\"neu-nav__flyout-group-label\">{{ child.label }}</span>\n @for (grand of child.children; track grand.id) {\n @if (grand.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"grand.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n <neu-icon\n name=\"lucideExternalLink\"\n size=\"10px\"\n class=\"neu-nav__external-icon\"\n />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"grand.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"grand.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ grand.label }}</span>\n </a>\n }\n }\n </div>\n } @else if (child.href) {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [href]=\"child.href\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n <neu-icon name=\"lucideExternalLink\" size=\"10px\" class=\"neu-nav__external-icon\" />\n </a>\n } @else {\n <a\n class=\"neu-nav__flyout-item\"\n role=\"menuitem\"\n [routerLink]=\"child.route\"\n routerLinkActive=\"neu-nav__flyout-item--active\"\n (click)=\"flyoutState.set(null)\"\n >\n <neu-icon [name]=\"child.icon\" size=\"13px\" aria-hidden=\"true\" />\n <span>{{ child.label }}</span>\n </a>\n }\n }\n </div>\n }\n\n <!-- Pestaña collapse/expand — fuera del nav para no ser recortada -->\n @if (collapsible()) {\n <button\n class=\"neu-nav__toggle-tab\"\n type=\"button\"\n [attr.aria-label]=\"isCollapsed() ? expandLabel() : collapseLabel()\"\n [attr.aria-expanded]=\"!isCollapsed()\"\n (click)=\"toggleCollapse()\"\n >\n <neu-icon\n [name]=\"isCollapsed() ? 'lucideChevronRight' : 'lucideChevronLeft'\"\n size=\"12px\"\n aria-hidden=\"true\"\n />\n </button>\n }\n </div>\n `,\n styleUrl: './neu-nav.component.scss',\n})\nexport class NeuNavComponent {\n private readonly router = inject(Router);\n\n // ---- Señal reactiva de ruta activa / Reactive active route signal ----\n private readonly currentUrl = toSignal(\n this.router.events.pipe(filter((e): e is NavigationEnd => e instanceof NavigationEnd)),\n { initialValue: null },\n );\n\n // ---- Inputs ----\n\n /** Lista de ítems de navegación / Navigation item list */\n items = input<NeuNavItem[]>([]);\n\n /** Estado inicial colapsado / Initial collapsed state */\n collapsed = input<boolean>(false);\n\n /** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */\n collapsible = input<boolean>(true);\n\n /** Etiqueta accesible del <nav> / Accessible label for the <nav> */\n ariaLabel = input<string>('Navegación principal');\n\n /** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */\n expandLabel = input<string>('Expandir menú');\n\n /** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */\n collapseLabel = input<string>('Colapsar menú');\n\n /** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */\n collapsedChange = output<boolean>();\n\n // ---- Estado interno / Internal state ----\n\n // Sigue el input `collapsed` del padre (permite el configurador)\n // pero puede ser sobreescrito localmente con toggleCollapse()\n readonly isCollapsed = linkedSignal(() => this.collapsed());\n private readonly openGroups = signal<Set<string>>(new Set());\n\n // ---- Flyout para modo colapsado / Flyout for collapsed mode ----\n readonly flyoutState = signal<{ item: NeuNavItem; top: number; left: number } | null>(null);\n private _flyoutTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n // Abrimos el grupo activo DESPUÉS de que el padre haya pasado los inputs\n afterNextRender(() => this._openActiveGroup());\n // Limpiamos el timer del flyout al destruir el componente\n inject(DestroyRef).onDestroy(() => {\n if (this._flyoutTimer) clearTimeout(this._flyoutTimer);\n });\n }\n\n // ---- Helpers de estado / State helpers ----\n\n toggleCollapse(): void {\n this.isCollapsed.update((v) => {\n const next = !v;\n this.collapsedChange.emit(next);\n return next;\n });\n }\n\n toggleGroup(id: string): void {\n this.openGroups.update((s) => {\n const next = new Set(s);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n }\n\n isGroupOpen(id: string): boolean {\n return this.openGroups().has(id);\n }\n\n isCurrentRoute(route: string): boolean {\n if (!route) return false;\n // Consume la señal para que OnPush re-evalúe tras navegación\n this.currentUrl();\n return this.router.url === route || this.router.url.startsWith(route + '?');\n }\n\n isGroupActive(item: NeuNavItem): boolean {\n if (!item.children?.length) return false;\n return item.children.some(\n (c) =>\n this.isCurrentRoute(c.route ?? '') ||\n (c.children?.some((g) => this.isCurrentRoute(g.route ?? '')) ?? false),\n );\n }\n\n // ---- Flyout handlers ----\n\n onGroupMouseEnter(item: NeuNavItem, event: MouseEvent): void {\n if (!this.isCollapsed() || !item.children?.length) return;\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect();\n this.flyoutState.set({ item, top: rect.top, left: rect.right });\n }\n\n onGroupMouseLeave(): void {\n if (!this.isCollapsed()) return;\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n onFlyoutMouseEnter(): void {\n if (this._flyoutTimer) {\n clearTimeout(this._flyoutTimer);\n this._flyoutTimer = null;\n }\n }\n\n onFlyoutMouseLeave(): void {\n this._flyoutTimer = setTimeout(() => this.flyoutState.set(null), 150);\n }\n\n private _openActiveGroup(): void {\n const toOpen = new Set<string>();\n for (const item of this.items()) {\n if (!item.children) continue;\n for (const child of item.children) {\n if (child.route && this.router.url.startsWith(child.route)) {\n toOpen.add(item.id);\n }\n if (child.children) {\n for (const grand of child.children) {\n if (grand.route && this.router.url.startsWith(grand.route)) {\n toOpen.add(item.id);\n toOpen.add(child.id);\n }\n }\n }\n }\n }\n if (toOpen.size > 0) {\n this.openGroups.set(toOpen);\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,33 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, signal, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
2
+ import { Directive, contentChild, input, output, signal, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
3
+ import { NgTemplateOutlet } from '@angular/common';
3
4
 
5
+ class NeuPickListItemDirective {
6
+ templateRef;
7
+ constructor(templateRef) {
8
+ this.templateRef = templateRef;
9
+ }
10
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuPickListItemDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
11
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuPickListItemDirective, isStandalone: true, selector: "ng-template[neuPickListItem]", ngImport: i0 });
12
+ }
13
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuPickListItemDirective, decorators: [{
14
+ type: Directive,
15
+ args: [{ selector: 'ng-template[neuPickListItem]' }]
16
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
17
+ class NeuOrderListItemDirective {
18
+ templateRef;
19
+ constructor(templateRef) {
20
+ this.templateRef = templateRef;
21
+ }
22
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuOrderListItemDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
23
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuOrderListItemDirective, isStandalone: true, selector: "ng-template[neuOrderListItem]", ngImport: i0 });
24
+ }
25
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuOrderListItemDirective, decorators: [{
26
+ type: Directive,
27
+ args: [{ selector: 'ng-template[neuOrderListItem]' }]
28
+ }], ctorParameters: () => [{ type: i0.TemplateRef }] });
4
29
  class NeuPickListComponent {
30
+ itemTpl = contentChild(NeuPickListItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
5
31
  source = input([], ...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
6
32
  target = input([], ...(ngDevMode ? [{ debugName: "target" }] : /* istanbul ignore next */ []));
7
33
  sourceHeader = input('Available', ...(ngDevMode ? [{ debugName: "sourceHeader" }] : /* istanbul ignore next */ []));
@@ -40,12 +66,12 @@ class NeuPickListComponent {
40
66
  return next;
41
67
  }
42
68
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuPickListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
43
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuPickListComponent, isStandalone: true, selector: "neu-pick-list", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, sourceHeader: { classPropertyName: "sourceHeader", publicName: "sourceHeader", isSignal: true, isRequired: false, transformFunction: null }, targetHeader: { classPropertyName: "targetHeader", publicName: "targetHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sourceChange: "sourceChange", targetChange: "targetChange", itemsChange: "itemsChange" }, host: { classAttribute: "neu-pick-list" }, ngImport: i0, template: `
69
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuPickListComponent, isStandalone: true, selector: "neu-pick-list", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null }, sourceHeader: { classPropertyName: "sourceHeader", publicName: "sourceHeader", isSignal: true, isRequired: false, transformFunction: null }, targetHeader: { classPropertyName: "targetHeader", publicName: "targetHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sourceChange: "sourceChange", targetChange: "targetChange", itemsChange: "itemsChange" }, host: { classAttribute: "neu-pick-list" }, queries: [{ propertyName: "itemTpl", first: true, predicate: NeuPickListItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
44
70
  <section class="neu-pick-list__column">
45
71
  <h3>{{ sourceHeader() }}</h3>
46
72
  @for (item of source(); track item.value) {
47
73
  <button type="button" [class.is-selected]="sourceSelection().has(item.value)" [disabled]="item.disabled" (click)="toggleSource(item.value)">
48
- {{ item.label }}
74
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, selected: sourceSelection().has(item.value), location: 'source' }" /> } @else { {{ item.label }} }
49
75
  </button>
50
76
  }
51
77
  </section>
@@ -57,20 +83,20 @@ class NeuPickListComponent {
57
83
  <h3>{{ targetHeader() }}</h3>
58
84
  @for (item of target(); track item.value) {
59
85
  <button type="button" [class.is-selected]="targetSelection().has(item.value)" [disabled]="item.disabled" (click)="toggleTarget(item.value)">
60
- {{ item.label }}
86
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, selected: targetSelection().has(item.value), location: 'target' }" /> } @else { {{ item.label }} }
61
87
  </button>
62
88
  }
63
89
  </section>
64
- `, isInline: true, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
90
+ `, isInline: true, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
65
91
  }
66
92
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuPickListComponent, decorators: [{
67
93
  type: Component,
68
- args: [{ selector: 'neu-pick-list', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-pick-list' }, template: `
94
+ args: [{ selector: 'neu-pick-list', imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-pick-list' }, template: `
69
95
  <section class="neu-pick-list__column">
70
96
  <h3>{{ sourceHeader() }}</h3>
71
97
  @for (item of source(); track item.value) {
72
98
  <button type="button" [class.is-selected]="sourceSelection().has(item.value)" [disabled]="item.disabled" (click)="toggleSource(item.value)">
73
- {{ item.label }}
99
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, selected: sourceSelection().has(item.value), location: 'source' }" /> } @else { {{ item.label }} }
74
100
  </button>
75
101
  }
76
102
  </section>
@@ -82,13 +108,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
82
108
  <h3>{{ targetHeader() }}</h3>
83
109
  @for (item of target(); track item.value) {
84
110
  <button type="button" [class.is-selected]="targetSelection().has(item.value)" [disabled]="item.disabled" (click)="toggleTarget(item.value)">
85
- {{ item.label }}
111
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, selected: targetSelection().has(item.value), location: 'target' }" /> } @else { {{ item.label }} }
86
112
  </button>
87
113
  }
88
114
  </section>
89
115
  `, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"] }]
90
- }], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], sourceHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceHeader", required: false }] }], targetHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "targetHeader", required: false }] }], sourceChange: [{ type: i0.Output, args: ["sourceChange"] }], targetChange: [{ type: i0.Output, args: ["targetChange"] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }] } });
116
+ }], propDecorators: { itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuPickListItemDirective), { isSignal: true }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], target: [{ type: i0.Input, args: [{ isSignal: true, alias: "target", required: false }] }], sourceHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceHeader", required: false }] }], targetHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "targetHeader", required: false }] }], sourceChange: [{ type: i0.Output, args: ["sourceChange"] }], targetChange: [{ type: i0.Output, args: ["targetChange"] }], itemsChange: [{ type: i0.Output, args: ["itemsChange"] }] } });
91
117
  class NeuOrderListComponent {
118
+ itemTpl = contentChild(NeuOrderListItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
92
119
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
93
120
  orderChange = output();
94
121
  move(index, direction) {
@@ -98,36 +125,36 @@ class NeuOrderListComponent {
98
125
  this.orderChange.emit(next);
99
126
  }
100
127
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuOrderListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
101
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuOrderListComponent, isStandalone: true, selector: "neu-order-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { orderChange: "orderChange" }, host: { classAttribute: "neu-order-list" }, ngImport: i0, template: `
128
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: NeuOrderListComponent, isStandalone: true, selector: "neu-order-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { orderChange: "orderChange" }, host: { classAttribute: "neu-order-list" }, queries: [{ propertyName: "itemTpl", first: true, predicate: NeuOrderListItemDirective, descendants: true, isSignal: true }], ngImport: i0, template: `
102
129
  <div class="neu-order-list__items">
103
130
  @for (item of items(); track item.value; let i = $index) {
104
131
  <div class="neu-order-list__item">
105
- <span>{{ item.label }}</span>
132
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, index: i }" /> } @else { <span>{{ item.label }}</span> }
106
133
  <button type="button" [disabled]="i === 0" (click)="move(i, -1)">↑</button>
107
134
  <button type="button" [disabled]="i === items().length - 1" (click)="move(i, 1)">↓</button>
108
135
  </div>
109
136
  }
110
137
  </div>
111
- `, isInline: true, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
138
+ `, isInline: true, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
112
139
  }
113
140
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuOrderListComponent, decorators: [{
114
141
  type: Component,
115
- args: [{ selector: 'neu-order-list', imports: [], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-order-list' }, template: `
142
+ args: [{ selector: 'neu-order-list', imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'neu-order-list' }, template: `
116
143
  <div class="neu-order-list__items">
117
144
  @for (item of items(); track item.value; let i = $index) {
118
145
  <div class="neu-order-list__item">
119
- <span>{{ item.label }}</span>
146
+ @if (itemTpl()) { <ng-container [ngTemplateOutlet]="itemTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: item, index: i }" /> } @else { <span>{{ item.label }}</span> }
120
147
  <button type="button" [disabled]="i === 0" (click)="move(i, -1)">↑</button>
121
148
  <button type="button" [disabled]="i === items().length - 1" (click)="move(i, 1)">↓</button>
122
149
  </div>
123
150
  }
124
151
  </div>
125
152
  `, styles: [".neu-pick-list{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.75rem;align-items:center}.neu-pick-list__column,.neu-order-list__items{display:grid;gap:.375rem;min-height:12rem;border:1px solid var(--neu-border, #d1d5db);border-radius:.75rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.75rem}.neu-pick-list__column h3{margin:0 0 .5rem;font-size:.875rem;color:var(--neu-text, #111827)}.neu-pick-list__column button,.neu-pick-list__actions button,.neu-order-list__item button{border:1px solid var(--neu-border, #d1d5db);border-radius:.5rem;background:var(--neu-surface, #fff);color:var(--neu-text, #111827);padding:.5rem .625rem}.neu-pick-list__column button{text-align:left}.neu-pick-list__column button.is-selected{background:color-mix(in srgb,var(--neu-primary, #2563eb) 14%,transparent)}.neu-pick-list__actions{display:grid;gap:.5rem}.neu-order-list__item{display:grid;grid-template-columns:1fr auto auto;gap:.375rem;align-items:center}@media(max-width:640px){.neu-pick-list{grid-template-columns:minmax(0,1fr)}.neu-pick-list__actions{grid-template-columns:repeat(2,auto);justify-content:center}}\n"] }]
126
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], orderChange: [{ type: i0.Output, args: ["orderChange"] }] } });
153
+ }], propDecorators: { itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuOrderListItemDirective), { isSignal: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], orderChange: [{ type: i0.Output, args: ["orderChange"] }] } });
127
154
 
128
155
  /**
129
156
  * Generated bundle index. Do not edit.
130
157
  */
131
158
 
132
- export { NeuOrderListComponent, NeuPickListComponent };
159
+ export { NeuOrderListComponent, NeuOrderListItemDirective, NeuPickListComponent, NeuPickListItemDirective };
133
160
  //# sourceMappingURL=neural-ui-core-pick-list.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"neural-ui-core-pick-list.mjs","sources":["../../../../projects/ui-core/pick-list/neu-pick-list.component.ts","../../../../projects/ui-core/pick-list/neural-ui-core-pick-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, ViewEncapsulation, input, output, signal } from '@angular/core';\n\nexport interface NeuTransferItem {\n value: string;\n label: string;\n disabled?: boolean;\n data?: unknown;\n}\n\n@Component({\n selector: 'neu-pick-list',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-pick-list' },\n template: `\n <section class=\"neu-pick-list__column\">\n <h3>{{ sourceHeader() }}</h3>\n @for (item of source(); track item.value) {\n <button type=\"button\" [class.is-selected]=\"sourceSelection().has(item.value)\" [disabled]=\"item.disabled\" (click)=\"toggleSource(item.value)\">\n {{ item.label }}\n </button>\n }\n </section>\n <div class=\"neu-pick-list__actions\">\n <button type=\"button\" (click)=\"moveToTarget()\" [disabled]=\"!sourceSelection().size\">›</button>\n <button type=\"button\" (click)=\"moveToSource()\" [disabled]=\"!targetSelection().size\">‹</button>\n </div>\n <section class=\"neu-pick-list__column\">\n <h3>{{ targetHeader() }}</h3>\n @for (item of target(); track item.value) {\n <button type=\"button\" [class.is-selected]=\"targetSelection().has(item.value)\" [disabled]=\"item.disabled\" (click)=\"toggleTarget(item.value)\">\n {{ item.label }}\n </button>\n }\n </section>\n `,\n styleUrl: './neu-pick-list.component.scss',\n})\nexport class NeuPickListComponent {\n readonly source = input<NeuTransferItem[]>([]);\n readonly target = input<NeuTransferItem[]>([]);\n readonly sourceHeader = input('Available');\n readonly targetHeader = input('Selected');\n readonly sourceChange = output<NeuTransferItem[]>();\n readonly targetChange = output<NeuTransferItem[]>();\n readonly itemsChange = output<{ source: NeuTransferItem[]; target: NeuTransferItem[] }>();\n readonly sourceSelection = signal(new Set<string>());\n readonly targetSelection = signal(new Set<string>());\n\n toggleSource(value: string): void {\n this.sourceSelection.set(this.toggleSet(this.sourceSelection(), value));\n }\n\n toggleTarget(value: string): void {\n this.targetSelection.set(this.toggleSet(this.targetSelection(), value));\n }\n\n moveToTarget(): void {\n const selected = this.sourceSelection();\n const moved = this.source().filter((item) => selected.has(item.value));\n this.commit(\n this.source().filter((item) => !selected.has(item.value)),\n [...this.target(), ...moved],\n );\n this.sourceSelection.set(new Set());\n }\n\n moveToSource(): void {\n const selected = this.targetSelection();\n const moved = this.target().filter((item) => selected.has(item.value));\n this.commit(\n [...this.source(), ...moved],\n this.target().filter((item) => !selected.has(item.value)),\n );\n this.targetSelection.set(new Set());\n }\n\n private commit(source: NeuTransferItem[], target: NeuTransferItem[]): void {\n this.sourceChange.emit(source);\n this.targetChange.emit(target);\n this.itemsChange.emit({ source, target });\n }\n\n private toggleSet(source: Set<string>, value: string): Set<string> {\n const next = new Set(source);\n next.has(value) ? next.delete(value) : next.add(value);\n return next;\n }\n}\n\n@Component({\n selector: 'neu-order-list',\n imports: [],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-order-list' },\n template: `\n <div class=\"neu-order-list__items\">\n @for (item of items(); track item.value; let i = $index) {\n <div class=\"neu-order-list__item\">\n <span>{{ item.label }}</span>\n <button type=\"button\" [disabled]=\"i === 0\" (click)=\"move(i, -1)\">↑</button>\n <button type=\"button\" [disabled]=\"i === items().length - 1\" (click)=\"move(i, 1)\">↓</button>\n </div>\n }\n </div>\n `,\n styleUrl: './neu-pick-list.component.scss',\n})\nexport class NeuOrderListComponent {\n readonly items = input<NeuTransferItem[]>([]);\n readonly orderChange = output<NeuTransferItem[]>();\n\n move(index: number, direction: -1 | 1): void {\n const next = [...this.items()];\n const target = index + direction;\n [next[index], next[target]] = [next[target]!, next[index]!];\n this.orderChange.emit(next);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"neural-ui-core-pick-list.mjs","sources":["../../../../projects/ui-core/pick-list/neu-pick-list.component.ts","../../../../projects/ui-core/pick-list/neural-ui-core-pick-list.ts"],"sourcesContent":["import { ChangeDetectionStrategy, Component, Directive, TemplateRef, ViewEncapsulation, contentChild, input, output, signal } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\n\nexport interface NeuTransferItem {\n value: string;\n label: string;\n disabled?: boolean;\n data?: unknown;\n}\n@Directive({ selector: 'ng-template[neuPickListItem]' })\nexport class NeuPickListItemDirective { constructor(readonly templateRef: TemplateRef<{ $implicit: NeuTransferItem; selected: boolean; location: 'source' | 'target' }>) {} }\n@Directive({ selector: 'ng-template[neuOrderListItem]' })\nexport class NeuOrderListItemDirective { constructor(readonly templateRef: TemplateRef<{ $implicit: NeuTransferItem; index: number }>) {} }\n\n@Component({\n selector: 'neu-pick-list',\n imports: [NgTemplateOutlet],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-pick-list' },\n template: `\n <section class=\"neu-pick-list__column\">\n <h3>{{ sourceHeader() }}</h3>\n @for (item of source(); track item.value) {\n <button type=\"button\" [class.is-selected]=\"sourceSelection().has(item.value)\" [disabled]=\"item.disabled\" (click)=\"toggleSource(item.value)\">\n @if (itemTpl()) { <ng-container [ngTemplateOutlet]=\"itemTpl()!.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: item, selected: sourceSelection().has(item.value), location: 'source' }\" /> } @else { {{ item.label }} }\n </button>\n }\n </section>\n <div class=\"neu-pick-list__actions\">\n <button type=\"button\" (click)=\"moveToTarget()\" [disabled]=\"!sourceSelection().size\">›</button>\n <button type=\"button\" (click)=\"moveToSource()\" [disabled]=\"!targetSelection().size\">‹</button>\n </div>\n <section class=\"neu-pick-list__column\">\n <h3>{{ targetHeader() }}</h3>\n @for (item of target(); track item.value) {\n <button type=\"button\" [class.is-selected]=\"targetSelection().has(item.value)\" [disabled]=\"item.disabled\" (click)=\"toggleTarget(item.value)\">\n @if (itemTpl()) { <ng-container [ngTemplateOutlet]=\"itemTpl()!.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: item, selected: targetSelection().has(item.value), location: 'target' }\" /> } @else { {{ item.label }} }\n </button>\n }\n </section>\n `,\n styleUrl: './neu-pick-list.component.scss',\n})\nexport class NeuPickListComponent {\n readonly itemTpl = contentChild(NeuPickListItemDirective);\n readonly source = input<NeuTransferItem[]>([]);\n readonly target = input<NeuTransferItem[]>([]);\n readonly sourceHeader = input('Available');\n readonly targetHeader = input('Selected');\n readonly sourceChange = output<NeuTransferItem[]>();\n readonly targetChange = output<NeuTransferItem[]>();\n readonly itemsChange = output<{ source: NeuTransferItem[]; target: NeuTransferItem[] }>();\n readonly sourceSelection = signal(new Set<string>());\n readonly targetSelection = signal(new Set<string>());\n\n toggleSource(value: string): void {\n this.sourceSelection.set(this.toggleSet(this.sourceSelection(), value));\n }\n\n toggleTarget(value: string): void {\n this.targetSelection.set(this.toggleSet(this.targetSelection(), value));\n }\n\n moveToTarget(): void {\n const selected = this.sourceSelection();\n const moved = this.source().filter((item) => selected.has(item.value));\n this.commit(\n this.source().filter((item) => !selected.has(item.value)),\n [...this.target(), ...moved],\n );\n this.sourceSelection.set(new Set());\n }\n\n moveToSource(): void {\n const selected = this.targetSelection();\n const moved = this.target().filter((item) => selected.has(item.value));\n this.commit(\n [...this.source(), ...moved],\n this.target().filter((item) => !selected.has(item.value)),\n );\n this.targetSelection.set(new Set());\n }\n\n private commit(source: NeuTransferItem[], target: NeuTransferItem[]): void {\n this.sourceChange.emit(source);\n this.targetChange.emit(target);\n this.itemsChange.emit({ source, target });\n }\n\n private toggleSet(source: Set<string>, value: string): Set<string> {\n const next = new Set(source);\n next.has(value) ? next.delete(value) : next.add(value);\n return next;\n }\n}\n\n@Component({\n selector: 'neu-order-list',\n imports: [NgTemplateOutlet],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { class: 'neu-order-list' },\n template: `\n <div class=\"neu-order-list__items\">\n @for (item of items(); track item.value; let i = $index) {\n <div class=\"neu-order-list__item\">\n @if (itemTpl()) { <ng-container [ngTemplateOutlet]=\"itemTpl()!.templateRef\" [ngTemplateOutletContext]=\"{ $implicit: item, index: i }\" /> } @else { <span>{{ item.label }}</span> }\n <button type=\"button\" [disabled]=\"i === 0\" (click)=\"move(i, -1)\">↑</button>\n <button type=\"button\" [disabled]=\"i === items().length - 1\" (click)=\"move(i, 1)\">↓</button>\n </div>\n }\n </div>\n `,\n styleUrl: './neu-pick-list.component.scss',\n})\nexport class NeuOrderListComponent {\n readonly itemTpl = contentChild(NeuOrderListItemDirective);\n readonly items = input<NeuTransferItem[]>([]);\n readonly orderChange = output<NeuTransferItem[]>();\n\n move(index: number, direction: -1 | 1): void {\n const next = [...this.items()];\n const target = index + direction;\n [next[index], next[target]] = [next[target]!, next[index]!];\n this.orderChange.emit(next);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
@@ -50,6 +50,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
50
50
  type: Directive,
51
51
  args: [{ selector: '[neuSelectSelected]', standalone: true }]
52
52
  }] });
53
+ /** Optional content slots for the select panel. */
54
+ class NeuSelectHeaderDirective {
55
+ templateRef = inject(TemplateRef);
56
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
57
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuSelectHeaderDirective, isStandalone: true, selector: "[neuSelectHeader]", ngImport: i0 });
58
+ }
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectHeaderDirective, decorators: [{
60
+ type: Directive,
61
+ args: [{ selector: '[neuSelectHeader]', standalone: true }]
62
+ }] });
63
+ class NeuSelectFooterDirective {
64
+ templateRef = inject(TemplateRef);
65
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectFooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
66
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuSelectFooterDirective, isStandalone: true, selector: "[neuSelectFooter]", ngImport: i0 });
67
+ }
68
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectFooterDirective, decorators: [{
69
+ type: Directive,
70
+ args: [{ selector: '[neuSelectFooter]', standalone: true }]
71
+ }] });
72
+ class NeuSelectEmptyDirective {
73
+ templateRef = inject(TemplateRef);
74
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectEmptyDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
75
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuSelectEmptyDirective, isStandalone: true, selector: "[neuSelectEmpty]", ngImport: i0 });
76
+ }
77
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectEmptyDirective, decorators: [{
78
+ type: Directive,
79
+ args: [{ selector: '[neuSelectEmpty]', standalone: true }]
80
+ }] });
81
+ class NeuSelectGroupDirective {
82
+ templateRef = inject(TemplateRef);
83
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectGroupDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
84
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: NeuSelectGroupDirective, isStandalone: true, selector: "[neuSelectGroup]", ngImport: i0 });
85
+ }
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: NeuSelectGroupDirective, decorators: [{
87
+ type: Directive,
88
+ args: [{ selector: '[neuSelectGroup]', standalone: true }]
89
+ }] });
53
90
 
54
91
  let _neuSelectIdSeq = 0;
55
92
  /**
@@ -106,6 +143,10 @@ class NeuSelectComponent {
106
143
  itemTpl = contentChild(NeuSelectItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
107
144
  /** Template personalizado para el valor seleccionado en el trigger / Custom template for the selected value in the trigger */
108
145
  selectedItemTpl = contentChild(NeuSelectSelectedDirective, ...(ngDevMode ? [{ debugName: "selectedItemTpl" }] : /* istanbul ignore next */ []));
146
+ headerTpl = contentChild(NeuSelectHeaderDirective, ...(ngDevMode ? [{ debugName: "headerTpl" }] : /* istanbul ignore next */ []));
147
+ footerTpl = contentChild(NeuSelectFooterDirective, ...(ngDevMode ? [{ debugName: "footerTpl" }] : /* istanbul ignore next */ []));
148
+ emptyTpl = contentChild(NeuSelectEmptyDirective, ...(ngDevMode ? [{ debugName: "emptyTpl" }] : /* istanbul ignore next */ []));
149
+ groupTpl = contentChild(NeuSelectGroupDirective, ...(ngDevMode ? [{ debugName: "groupTpl" }] : /* istanbul ignore next */ []));
109
150
  /** Opciones del dropdown / Dropdown options */
110
151
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
111
152
  /** Texto del floating label / Floating label text */
@@ -212,6 +253,10 @@ class NeuSelectComponent {
212
253
  return this.options();
213
254
  return this.options().filter((o) => o.label.toLowerCase().includes(q));
214
255
  }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
256
+ previousGroup(option) {
257
+ const index = this.filteredOptions().indexOf(option);
258
+ return index > 0 ? this.filteredOptions()[index - 1]?.group : undefined;
259
+ }
215
260
  selectedLabel = computed(() => this.options().find((o) => o.value === this._value())?.label ?? null, ...(ngDevMode ? [{ debugName: "selectedLabel" }] : /* istanbul ignore next */ []));
216
261
  _selectedOption = computed(() => this.options().find((o) => o.value === this._value()) ?? null, ...(ngDevMode ? [{ debugName: "_selectedOption" }] : /* istanbul ignore next */ []));
217
262
  resultsAnnouncement = computed(() => {
@@ -433,7 +478,7 @@ class NeuSelectComponent {
433
478
  useExisting: forwardRef(() => NeuSelectComponent),
434
479
  multi: true,
435
480
  },
436
- ], queries: [{ propertyName: "itemTpl", first: true, predicate: NeuSelectItemDirective, descendants: true, isSignal: true }, { propertyName: "selectedItemTpl", first: true, predicate: NeuSelectSelectedDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "_viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: `
481
+ ], queries: [{ propertyName: "itemTpl", first: true, predicate: NeuSelectItemDirective, descendants: true, isSignal: true }, { propertyName: "selectedItemTpl", first: true, predicate: NeuSelectSelectedDirective, descendants: true, isSignal: true }, { propertyName: "headerTpl", first: true, predicate: NeuSelectHeaderDirective, descendants: true, isSignal: true }, { propertyName: "footerTpl", first: true, predicate: NeuSelectFooterDirective, descendants: true, isSignal: true }, { propertyName: "emptyTpl", first: true, predicate: NeuSelectEmptyDirective, descendants: true, isSignal: true }, { propertyName: "groupTpl", first: true, predicate: NeuSelectGroupDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "_viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }], ngImport: i0, template: `
437
482
  @if (!floatingLabel() && label()) {
438
483
  <label class="neu-select__static-label" [for]="_triggerId" (click)="focusTrigger()">{{
439
484
  label()
@@ -528,6 +573,7 @@ class NeuSelectComponent {
528
573
  stroke-linejoin="round"
529
574
  aria-hidden="true"
530
575
  >
576
+ @if (headerTpl()) { <ng-container [ngTemplateOutlet]="headerTpl()!.templateRef" /> }
531
577
  <polyline points="6 9 12 15 18 9" />
532
578
  </svg>
533
579
  </div>
@@ -629,6 +675,10 @@ class NeuSelectComponent {
629
675
  </cdk-virtual-scroll-viewport>
630
676
  } @else {
631
677
  @for (option of filteredOptions(); track option.value) {
678
+ @if (option.group && option.group !== previousGroup(option)) {
679
+ @if (groupTpl()) { <ng-container [ngTemplateOutlet]="groupTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: option.group }" /> }
680
+ @else { <div class="neu-select__group">{{ option.group }}</div> }
681
+ }
632
682
  <ng-container
633
683
  [ngTemplateOutlet]="selectOptionTpl"
634
684
  [ngTemplateOutletContext]="{ $implicit: option }"
@@ -636,8 +686,10 @@ class NeuSelectComponent {
636
686
  }
637
687
  }
638
688
  @if (!loading() && filteredOptions().length === 0) {
639
- <div class="neu-select__empty">{{ noResultsMessage() }}</div>
689
+ @if (emptyTpl()) { <ng-container [ngTemplateOutlet]="emptyTpl()!.templateRef" /> }
690
+ @else { <div class="neu-select__empty">{{ noResultsMessage() }}</div> }
640
691
  }
692
+ @if (footerTpl()) { <ng-container [ngTemplateOutlet]="footerTpl()!.templateRef" /> }
641
693
  </div>
642
694
  </ng-template>
643
695
  <div class="neu-select__sr-status" aria-live="polite" aria-atomic="true">
@@ -761,6 +813,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
761
813
  stroke-linejoin="round"
762
814
  aria-hidden="true"
763
815
  >
816
+ @if (headerTpl()) { <ng-container [ngTemplateOutlet]="headerTpl()!.templateRef" /> }
764
817
  <polyline points="6 9 12 15 18 9" />
765
818
  </svg>
766
819
  </div>
@@ -862,6 +915,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
862
915
  </cdk-virtual-scroll-viewport>
863
916
  } @else {
864
917
  @for (option of filteredOptions(); track option.value) {
918
+ @if (option.group && option.group !== previousGroup(option)) {
919
+ @if (groupTpl()) { <ng-container [ngTemplateOutlet]="groupTpl()!.templateRef" [ngTemplateOutletContext]="{ $implicit: option.group }" /> }
920
+ @else { <div class="neu-select__group">{{ option.group }}</div> }
921
+ }
865
922
  <ng-container
866
923
  [ngTemplateOutlet]="selectOptionTpl"
867
924
  [ngTemplateOutletContext]="{ $implicit: option }"
@@ -869,8 +926,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
869
926
  }
870
927
  }
871
928
  @if (!loading() && filteredOptions().length === 0) {
872
- <div class="neu-select__empty">{{ noResultsMessage() }}</div>
929
+ @if (emptyTpl()) { <ng-container [ngTemplateOutlet]="emptyTpl()!.templateRef" /> }
930
+ @else { <div class="neu-select__empty">{{ noResultsMessage() }}</div> }
873
931
  }
932
+ @if (footerTpl()) { <ng-container [ngTemplateOutlet]="footerTpl()!.templateRef" /> }
874
933
  </div>
875
934
  </ng-template>
876
935
  <div class="neu-select__sr-status" aria-live="polite" aria-atomic="true">
@@ -887,11 +946,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
887
946
  <p class="neu-select__hint" [id]="_triggerId + '-hint'">{{ hint() }}</p>
888
947
  }
889
948
  `, styles: [".neu-select{position:relative;display:block}.neu-select--disabled{pointer-events:none}.neu-select--sm .neu-select__trigger{height:36px;font-size:var(--neu-text-sm)}.neu-select--lg .neu-select__trigger{height:56px}.neu-select__trigger{display:flex;align-items:center;width:100%;height:48px;padding:0 var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);font-family:var(--neu-font-sans);font-size:var(--neu-text-base);color:var(--neu-text);cursor:pointer;text-align:left;outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition);position:relative}.neu-select__trigger:hover:not([aria-disabled=true]){border-color:var(--neu-border-hover)}.neu-select__trigger[aria-disabled=true]{cursor:not-allowed;background:var(--neu-surface-2)}.neu-select__trigger:focus-visible{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-select--open .neu-select__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f;border-bottom-left-radius:0;border-bottom-right-radius:0}.neu-select--open-above .neu-select__trigger{border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:var(--neu-radius);border-bottom-right-radius:var(--neu-radius)}.neu-select--error .neu-select__trigger{border-color:var(--neu-error)}.neu-select--error .neu-select__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-select__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:color-mix(in srgb,var(--neu-text) 68%,var(--neu-surface) 32%);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-6));transition:top var(--neu-transition),font-size var(--neu-transition),color var(--neu-transition),transform var(--neu-transition),padding var(--neu-transition),background var(--neu-transition)}.neu-select--open .neu-select__label,.neu-select--has-value .neu-select__label{top:0;transform:translateY(-50%);font-size:12px;font-weight:600;letter-spacing:.01em;background:var(--neu-surface);padding:0 4px;left:calc(var(--neu-space-3) - 4px)}.neu-select--open .neu-select__label{color:var(--neu-primary)}.neu-select--error .neu-select__label{color:var(--neu-error)}.neu-select--disabled .neu-select__label{background:var(--neu-surface-2)}.neu-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.neu-select--no-float .neu-select__value{padding-top:0}.neu-select__placeholder{color:color-mix(in srgb,var(--neu-text) 62%,var(--neu-surface) 38%)}.neu-select:not(.neu-select--no-float):not(.neu-select--open) .neu-select__placeholder{visibility:hidden}.neu-select__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:18px;height:18px;color:var(--neu-text-muted);flex-shrink:0;transition:transform var(--neu-transition)}.neu-select--open .neu-select__chevron{transform:translateY(-50%) rotate(180deg);color:var(--neu-primary)}.neu-select__clear{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin-right:2px;padding:0;border:none;background:transparent;color:var(--neu-text-muted);cursor:pointer;border-radius:var(--neu-radius-sm);flex-shrink:0;transition:color var(--neu-transition),background var(--neu-transition)}.neu-select__clear svg{width:14px;height:14px}.neu-select__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-select__clear:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-select__panel{position:relative;z-index:var(--neu-z-dropdown);box-sizing:border-box;width:100%;background:var(--neu-surface);border:1.5px solid var(--neu-primary);border-top:none;border-bottom-left-radius:var(--neu-radius);border-bottom-right-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);max-height:240px;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--neu-surface-3) transparent;animation:neu-select-open .15s ease forwards}.neu-select__panel::-webkit-scrollbar{width:4px}.neu-select__panel::-webkit-scrollbar-thumb{background:var(--neu-surface-3);border-radius:99px}.neu-select__panel--above{border-top:1.5px solid var(--neu-primary);border-bottom:none;border-top-left-radius:var(--neu-radius);border-top-right-radius:var(--neu-radius);border-bottom-left-radius:0;border-bottom-right-radius:0}.neu-select__panel--virtual{overflow:visible}.neu-select__viewport{width:100%}@media(max-width:600px){.neu-select__panel{left:auto;right:0;width:min(max(100%,220px),100vw - 2rem);max-width:calc(100vw - 2rem)}}@keyframes neu-select-open{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-select__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:var(--neu-space-3) var(--neu-space-4);min-height:var(--neu-select-option-height, 44px);box-sizing:border-box;font-size:var(--neu-text-sm);color:var(--neu-text);cursor:pointer;transition:background-color var(--neu-transition)}.neu-select__option:hover:not(.neu-select__option--disabled){background:var(--neu-primary-50);color:var(--neu-primary)}.neu-select__option--selected{color:var(--neu-primary);font-weight:600;background:var(--neu-primary-50)}.neu-select__option--disabled{opacity:.4;cursor:not-allowed}.neu-select__check{width:14px;height:14px;flex-shrink:0}.neu-select__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text);font-family:var(--neu-font-sans)}.neu-select__hint{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-text-muted);font-family:var(--neu-font-sans)}.neu-select__sr-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.neu-select__static-label{display:block;font-size:var(--neu-text-sm);font-weight:500;color:var(--neu-text-muted);margin-bottom:var(--neu-space-2)}.neu-select__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);position:sticky;top:0;background:var(--neu-surface);z-index:1}.neu-select__search-input{width:100%;height:34px;padding:0 var(--neu-space-3);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius-sm);background:var(--neu-bg);font-family:var(--neu-font-sans);font-size:var(--neu-text-sm);color:var(--neu-text);outline:none;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-select__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-select__search-input::placeholder{color:var(--neu-text-disabled)}.neu-select__empty{padding:var(--neu-space-4);text-align:center;font-size:var(--neu-text-sm);color:var(--neu-text-disabled);font-family:var(--neu-font-sans)}\n"] }]
890
- }], ctorParameters: () => [], propDecorators: { _viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectItemDirective), { isSignal: true }] }], selectedItemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectSelectedDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollVisibleItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollVisibleItems", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
949
+ }], ctorParameters: () => [], propDecorators: { _viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectItemDirective), { isSignal: true }] }], selectedItemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectSelectedDirective), { isSignal: true }] }], headerTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectHeaderDirective), { isSignal: true }] }], footerTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectFooterDirective), { isSignal: true }] }], emptyTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectEmptyDirective), { isSignal: true }] }], groupTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuSelectGroupDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], virtualScroll: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScroll", required: false }] }], virtualScrollVisibleItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "virtualScrollVisibleItems", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }], urlParam: [{ type: i0.Input, args: [{ isSignal: true, alias: "urlParam", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }] } });
891
950
 
892
951
  /**
893
952
  * Generated bundle index. Do not edit.
894
953
  */
895
954
 
896
- export { NeuSelectComponent, NeuSelectItemDirective, NeuSelectSelectedDirective };
955
+ export { NeuSelectComponent, NeuSelectEmptyDirective, NeuSelectFooterDirective, NeuSelectGroupDirective, NeuSelectHeaderDirective, NeuSelectItemDirective, NeuSelectSelectedDirective };
897
956
  //# sourceMappingURL=neural-ui-core-select.mjs.map