@neural-ui/core 1.1.2 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { makeEnvironmentProviders, inject, computed, Injectable, signal, input, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component, ElementRef, TemplateRef, Directive, contentChild, InjectionToken, output, viewChild, effect, Injector, HostListener, afterNextRender, DestroyRef } from '@angular/core';
2
+ import { makeEnvironmentProviders, inject, computed, Injectable, signal, input, forwardRef, ChangeDetectionStrategy, ViewEncapsulation, Component, ElementRef, TemplateRef, Directive, effect, untracked, contentChild, output, InjectionToken, viewChild, Injector, HostListener, afterNextRender, DestroyRef } from '@angular/core';
3
3
  import { provideIcons, provideNgIconsConfig, NgIcon } from '@ng-icons/core';
4
4
  import { lucideMinus, lucideTrendingDown, lucideTrendingUp, lucideInbox, lucideExternalLink, lucideChevronLeft, lucideChevronRight, lucideX, lucideInfo, lucideAlertTriangle, lucideXCircle, lucideCheckCircle, lucideAlertCircle } from '@ng-icons/lucide';
5
5
  import { toSignal } from '@angular/core/rxjs-interop';
@@ -149,9 +149,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
149
149
  * toast.error('Ha ocurrido un error', { title: 'Error', duration: 8000 });
150
150
  */
151
151
  class NeuToastService {
152
- /** Lista reactiva de toasts activos */
152
+ /** Lista reactiva de toasts activos / Reactive list of active toasts */
153
153
  toasts = signal([], ...(ngDevMode ? [{ debugName: "toasts" }] : /* istanbul ignore next */ []));
154
- /** Posición del contenedor de toasts */
154
+ /** Posición del contenedor de toasts / Toast container position */
155
155
  position = signal('top-right', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
156
156
  setPosition(position) {
157
157
  this.position.set(position);
@@ -213,7 +213,7 @@ class NeuCheckboxComponent {
213
213
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
214
214
  _id = `neu-checkbox-${_neuCheckboxIdSeq++}`;
215
215
  _checked = signal(false, ...(ngDevMode ? [{ debugName: "_checked" }] : /* istanbul ignore next */ []));
216
- /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState */
216
+ /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState / Internal disabled state — combines the `disabled` input with CVA setDisabledState */
217
217
  _cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
218
218
  _isDisabled = computed(() => this.disabled() || this._cvaDisabled(), ...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
219
219
  _onChange = () => { };
@@ -329,29 +329,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
329
329
  let _neuDateInputIdSeq = 0;
330
330
  class NeuDateInputComponent {
331
331
  el = inject(ElementRef);
332
- /** Tipo: date | time | datetime-local */
332
+ /** Tipo: date | time | datetime-local / Type: date | time | datetime-local */
333
333
  type = input('date', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
334
- /** Etiqueta del campo */
334
+ /** Etiqueta del campo / Field label */
335
335
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
336
- /** Texto de ayuda */
336
+ /** Texto de ayuda / Help text */
337
337
  hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
338
- /** Mensaje de error */
338
+ /** Mensaje de error / Error message */
339
339
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
340
- /** Deshabilita el campo */
340
+ /** Deshabilita el campo / Disables the field */
341
341
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
342
- /** Solo lectura */
342
+ /** Solo lectura / Read only */
343
343
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
344
- /** Nombre del campo (formularios nativos) */
344
+ /** Nombre del campo (formularios nativos) / Field name (native forms) */
345
345
  name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
346
- /** ID accesible */
346
+ /** ID accesible / Accessible ID */
347
347
  inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
348
- /** Requerido */
348
+ /** Requerido / Required */
349
349
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
350
- /** Mínimo (no implementado visualmente en v1) */
350
+ /** Mínimo (no implementado visualmente en v1) / Minimum (not visually implemented in v1) */
351
351
  min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
352
- /** Máximo (no implementado visualmente en v1) */
352
+ /** Máximo (no implementado visualmente en v1) / Maximum (not visually implemented in v1) */
353
353
  max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
354
- /** Paso */
354
+ /** Paso / Step */
355
355
  step = input(null, ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
356
356
  // ── Estado ──────────────────────────────────────────────
357
357
  _id = `neu-date-input-${++_neuDateInputIdSeq}`;
@@ -1170,7 +1170,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
1170
1170
  * <neu-icon name="lucideAlertCircle" size="1rem" />
1171
1171
  */
1172
1172
  class NeuIconComponent {
1173
- /** Nombre del icono registrado con provideIcons() */
1173
+ /** Nombre del icono registrado con provideIcons() / Icon name registered with provideIcons() */
1174
1174
  name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
1175
1175
  /**
1176
1176
  * Grosor del trazo. Default '2' para estética fina y técnica.
@@ -1182,7 +1182,7 @@ class NeuIconComponent {
1182
1182
  * Si no se especifica, usa la variable CSS `--neu-icon-size` (1.25rem por defecto).
1183
1183
  */
1184
1184
  size = input('', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
1185
- /** Tamaño resuelto: usa el input `size` o cae al token CSS. */
1185
+ /** Tamaño resuelto: usa el input `size` o cae al token CSS. / Resolved size: uses the `size` input or falls back to the CSS token. */
1186
1186
  resolvedSize = computed(() => this.size() || 'var(--neu-icon-size, 1.25rem)', ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
1187
1187
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1188
1188
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: NeuIconComponent, isStandalone: true, selector: "neu-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "\"inline-flex\"", "style.align-items": "\"center\"", "style.line-height": "\"1\"", "style.color": "\"inherit\"" }, classAttribute: "neu-icon" }, ngImport: i0, template: `<ng-icon [name]="name()" [size]="resolvedSize()" [strokeWidth]="strokeWidth()" />`, isInline: true, styles: [".neu-icon{color:inherit;vertical-align:middle;flex-shrink:0}\n"], dependencies: [{ kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
@@ -1198,7 +1198,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
1198
1198
  }, template: `<ng-icon [name]="name()" [size]="resolvedSize()" [strokeWidth]="strokeWidth()" />`, styles: [".neu-icon{color:inherit;vertical-align:middle;flex-shrink:0}\n"] }]
1199
1199
  }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
1200
1200
 
1201
- /** Contador global para IDs estables — seguro en SSR, predecible en hidratación */
1201
+ /** Contador global para IDs estables — seguro en SSR, predecible en hidratación / Global counter for stable IDs — SSR-safe, predictable on hydration */
1202
1202
  let _neuInputIdSeq = 0;
1203
1203
  /**
1204
1204
  * NeuralUI Input Component
@@ -1213,47 +1213,47 @@ let _neuInputIdSeq = 0;
1213
1213
  * <neu-input label="Correo" [formControl]="emailCtrl" [errorMessage]="emailError()" />
1214
1214
  */
1215
1215
  class NeuInputComponent {
1216
- /** Tipo de input HTML */
1216
+ /** Tipo de input HTML / HTML input type */
1217
1217
  type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
1218
- /** Texto del floating label */
1218
+ /** Texto del floating label / Floating label text */
1219
1219
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1220
- /** Placeholder visible cuando floatingLabel=false */
1220
+ /** Placeholder visible cuando floatingLabel=false / Visible placeholder when floatingLabel=false */
1221
1221
  placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
1222
- /** Muestra el label como flotante (true) o estático encima del campo (false) */
1222
+ /** Muestra el label como flotante (true) o estático encima del campo (false) / Shows the label as floating (true) or static above the field (false) */
1223
1223
  floatingLabel = input(true, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : /* istanbul ignore next */ []));
1224
- /** Hint de ayuda (visible cuando no hay error) */
1224
+ /** Hint de ayuda (visible cuando no hay error) / Help hint (visible when there is no error) */
1225
1225
  hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
1226
- /** Mensaje de error (activa el estado de error) */
1226
+ /** Mensaje de error (activa el estado de error) / Error message (activates the error state) */
1227
1227
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
1228
- /** Deshabilita el campo */
1228
+ /** Deshabilita el campo / Disables the field */
1229
1229
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1230
- /** Atributo autocomplete HTML */
1230
+ /** Atributo autocomplete HTML / HTML autocomplete attribute */
1231
1231
  autocomplete = input('off', ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
1232
- /** Muestra zona para icono al inicio */
1232
+ /** Muestra zona para icono al inicio / Shows icon slot at the start */
1233
1233
  startIcon = input(false, ...(ngDevMode ? [{ debugName: "startIcon" }] : /* istanbul ignore next */ []));
1234
- /** Muestra zona para icono al final */
1234
+ /** Muestra zona para icono al final / Shows icon slot at the end */
1235
1235
  endIcon = input(false, ...(ngDevMode ? [{ debugName: "endIcon" }] : /* istanbul ignore next */ []));
1236
- /** Nombre del icono lucide a renderizar dentro del campo */
1236
+ /** Nombre del icono lucide a renderizar dentro del campo / Lucide icon name to render inside the field */
1237
1237
  icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
1238
- /** Posición del icono cuando se usa `icon` */
1238
+ /** Posición del icono cuando se usa `icon` / Icon position when using `icon` */
1239
1239
  iconPosition = input('left', ...(ngDevMode ? [{ debugName: "iconPosition" }] : /* istanbul ignore next */ []));
1240
- /** ID accesible para el input — generado con contador estable (seguro en SSR) */
1240
+ /** ID accesible para el input — generado con contador estable (seguro en SSR) / Accessible ID for the input — generated with stable counter (SSR-safe) */
1241
1241
  inputId = input(`neu-input-${++_neuInputIdSeq}`, ...(ngDevMode ? [{ debugName: "inputId" }] : /* istanbul ignore next */ []));
1242
- /** Nombre del campo para formularios nativos */
1242
+ /** Nombre del campo para formularios nativos / Field name for native forms */
1243
1243
  name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
1244
- /** Marca el campo como requerido */
1244
+ /** Marca el campo como requerido / Marks the field as required */
1245
1245
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
1246
- /** Hace el campo de solo lectura */
1246
+ /** Hace el campo de solo lectura / Makes the field read-only */
1247
1247
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
1248
- /** Longitud máxima de caracteres */
1248
+ /** Longitud máxima de caracteres / Maximum character length */
1249
1249
  maxlength = input(null, ...(ngDevMode ? [{ debugName: "maxlength" }] : /* istanbul ignore next */ []));
1250
- /** Longitud mínima de caracteres */
1250
+ /** Longitud mínima de caracteres / Minimum character length */
1251
1251
  minlength = input(null, ...(ngDevMode ? [{ debugName: "minlength" }] : /* istanbul ignore next */ []));
1252
- /** Valor mínimo (para type=number/date) */
1252
+ /** Valor mínimo (para type=number/date) / Minimum value (for type=number/date) */
1253
1253
  min = input(null, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
1254
- /** Valor máximo (para type=number/date) */
1254
+ /** Valor máximo (para type=number/date) / Maximum value (for type=number/date) */
1255
1255
  max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
1256
- /** Patrón de validación HTML5 */
1256
+ /** Patrón de validación HTML5 / HTML5 validation pattern */
1257
1257
  pattern = input(null, ...(ngDevMode ? [{ debugName: "pattern" }] : /* istanbul ignore next */ []));
1258
1258
  // --- Estado interno reactivo ---
1259
1259
  _value = signal('', ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
@@ -1502,7 +1502,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
1502
1502
  }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], autocomplete: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocomplete", required: false }] }], startIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "startIcon", required: false }] }], endIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "endIcon", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], minlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minlength", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }] } });
1503
1503
 
1504
1504
  /**
1505
- * Directiva para personalizar el template de cada ítem del dropdown de Multiselect.
1505
+ * Directiva para personalizar el template de cada ítem del dropdown de Multiselect. / Directive to customize the template of each Multiselect dropdown item.
1506
1506
  *
1507
1507
  * Uso:
1508
1508
  * ```html
@@ -1528,42 +1528,69 @@ let _neuMultiselectIdSeq = 0;
1528
1528
  /**
1529
1529
  * NeuralUI Multiselect Component
1530
1530
  *
1531
- * Dropdown de selección múltiple con chips, búsqueda integrada y soporte
1532
- * completo para Angular Forms (ngModel y Reactive Forms).
1531
+ * Dropdown de selección múltiple con chips, búsqueda integrada y soporte / Multiple selection dropdown with chips, integrated search and support
1532
+ * completo para Angular Forms (ngModel y Reactive Forms). / for Angular Forms (ngModel and Reactive Forms).
1533
1533
  *
1534
1534
  * Uso:
1535
1535
  * <neu-multiselect label="Tecnologías" [options]="opts" [(ngModel)]="selected" />
1536
1536
  */
1537
1537
  class NeuMultiselectComponent {
1538
1538
  elementRef = inject(ElementRef);
1539
+ _urlState = inject(NeuUrlStateService);
1540
+ constructor() {
1541
+ effect(() => {
1542
+ const param = this.urlParam();
1543
+ if (!param)
1544
+ return;
1545
+ const urlRaw = this._urlState.getParam(param)();
1546
+ const urlVals = urlRaw ? urlRaw.split(',').filter(Boolean) : [];
1547
+ const current = untracked(() => this._values());
1548
+ if (JSON.stringify(urlVals) !== JSON.stringify(current)) {
1549
+ this._values.set(urlVals);
1550
+ this._onChange(urlVals);
1551
+ }
1552
+ });
1553
+ }
1539
1554
  /** @internal */
1540
1555
  _triggerId = `neu-multiselect-trigger-${_neuMultiselectIdSeq++}`;
1541
- /** Template personalizado para cada opción del dropdown */
1556
+ /** Template personalizado para cada opción del dropdown / Custom template for each dropdown option */
1542
1557
  itemTpl = contentChild(NeuMultiselectItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
1543
- /** Opciones del dropdown */
1558
+ /** Opciones del dropdown / Dropdown options */
1544
1559
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
1545
- /** Etiqueta del componente */
1560
+ /** Etiqueta del componente / Component label */
1546
1561
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
1547
- /** Muestra el label como flotante dentro del campo (true) o estático encima (false) */
1562
+ /** Muestra el label como flotante dentro del campo (true) o estático encima (false) / Shows the label as floating inside the field (true) or static above (false) */
1548
1563
  floatingLabel = input(false, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : /* istanbul ignore next */ []));
1549
- /** Placeholder cuando no hay selección */
1564
+ /** Placeholder cuando no hay selección / Placeholder when there is no selection */
1550
1565
  placeholder = input('Seleccionar...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
1551
- /** Mensaje de error */
1566
+ /** Mensaje de error / Error message */
1552
1567
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
1553
- /** Deshabilita el componente */
1568
+ /** Deshabilita el componente / Disables the component */
1554
1569
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1555
- /** Activa input de búsqueda/filtro en el panel */
1570
+ /** Activa input de búsqueda/filtro en el panel / Activates the search/filter input in the panel */
1556
1571
  searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
1557
- /** Placeholder del input de búsqueda */
1572
+ /** Placeholder del input de búsqueda / Search input placeholder */
1558
1573
  searchPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
1559
- /** Texto cuando no hay opciones tras filtrar */
1574
+ /** Texto cuando no hay opciones tras filtrar / Text when no options remain after filtering */
1560
1575
  noResultsMessage = input('Sin resultados', ...(ngDevMode ? [{ debugName: "noResultsMessage" }] : /* istanbul ignore next */ []));
1561
- /** Texto del botón de limpiar todas las selecciones */
1576
+ /** Texto del botón de limpiar todas las selecciones / Button text to clear all selections */
1562
1577
  clearAllLabel = input('Limpiar todo', ...(ngDevMode ? [{ debugName: "clearAllLabel" }] : /* istanbul ignore next */ []));
1563
- /** Muestra un botón × en el trigger para limpiar la selección de una vez */
1578
+ /** Muestra un botón × en el trigger para limpiar la selección de una vez / Shows a × button in the trigger to clear the selection at once */
1564
1579
  clearable = input(false, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
1565
- /** Aria-label del botón clear que aparece en el trigger */
1580
+ /** Aria-label del botón clear que aparece en el trigger / Aria-label for the clear button shown in the trigger */
1566
1581
  clearAriaLabel = input('Limpiar selección', ...(ngDevMode ? [{ debugName: "clearAriaLabel" }] : /* istanbul ignore next */ []));
1582
+ /**
1583
+ * Sincroniza los valores seleccionados con este query param de la URL.
1584
+ * Los valores se codifican como lista separada por comas: `?{urlParam}=a,b,c`.
1585
+ * Pasar `null` (default) deshabilita la sincronización.
1586
+ */
1587
+ urlParam = input(null, ...(ngDevMode ? [{ debugName: "urlParam" }] : /* istanbul ignore next */ []));
1588
+ /**
1589
+ * Emite el array de NeuSelectOption completo (incluyendo data) al cambiar la selección.
1590
+ * Emite [] al limpiar toda la selección.
1591
+ * Los valores de ngModel / formControl siguen siendo string[].
1592
+ */
1593
+ selectionChange = output();
1567
1594
  // --- Estado interno ---
1568
1595
  _values = signal([], ...(ngDevMode ? [{ debugName: "_values" }] : /* istanbul ignore next */ []));
1569
1596
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
@@ -1616,7 +1643,7 @@ class NeuMultiselectComponent {
1616
1643
  });
1617
1644
  }
1618
1645
  }
1619
- /** Abre el panel y mueve el foco al primer item */
1646
+ /** Abre el panel y mueve el foco al primer item / Opens the panel and moves focus to the first item */
1620
1647
  onTriggerKey(event) {
1621
1648
  event.preventDefault();
1622
1649
  if (!this.isOpen()) {
@@ -1627,7 +1654,7 @@ class NeuMultiselectComponent {
1627
1654
  });
1628
1655
  }
1629
1656
  }
1630
- /** Navega entre opciones con flechas */
1657
+ /** Navega entre opciones con flechas / Navigates between options with arrows */
1631
1658
  focusOptionByIndex(event, current, dir) {
1632
1659
  event.preventDefault();
1633
1660
  const opts = this.filteredOptions().filter((o) => !o.disabled);
@@ -1652,6 +1679,10 @@ class NeuMultiselectComponent {
1652
1679
  : [...current, option.value];
1653
1680
  this._values.set(next);
1654
1681
  this._onChange(next);
1682
+ this.selectionChange.emit(this.options().filter((o) => next.includes(o.value)));
1683
+ const param = this.urlParam();
1684
+ if (param)
1685
+ this._urlState.setParam(param, next.length ? next.join(',') : null);
1655
1686
  }
1656
1687
  removeValue(value, event) {
1657
1688
  event.stopPropagation();
@@ -1659,12 +1690,20 @@ class NeuMultiselectComponent {
1659
1690
  this._values.set(next);
1660
1691
  this._onChange(next);
1661
1692
  this._onTouched();
1693
+ this.selectionChange.emit(this.options().filter((o) => next.includes(o.value)));
1694
+ const param = this.urlParam();
1695
+ if (param)
1696
+ this._urlState.setParam(param, next.length ? next.join(',') : null);
1662
1697
  }
1663
1698
  clearAll(event) {
1664
1699
  event.stopPropagation();
1665
1700
  this._values.set([]);
1666
1701
  this._onChange([]);
1667
1702
  this._onTouched();
1703
+ this.selectionChange.emit([]);
1704
+ const param = this.urlParam();
1705
+ if (param)
1706
+ this._urlState.setParam(param, null);
1668
1707
  }
1669
1708
  toggleChipMode(event) {
1670
1709
  event.stopPropagation();
@@ -1676,7 +1715,7 @@ class NeuMultiselectComponent {
1676
1715
  }
1677
1716
  }
1678
1717
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuMultiselectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1679
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuMultiselectComponent, isStandalone: true, selector: "neu-multiselect", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAllLabel: { classPropertyName: "clearAllLabel", publicName: "clearAllLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "close()" } }, providers: [
1718
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuMultiselectComponent, isStandalone: true, selector: "neu-multiselect", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAllLabel: { classPropertyName: "clearAllLabel", publicName: "clearAllLabel", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "close()" } }, providers: [
1680
1719
  {
1681
1720
  provide: NG_VALUE_ACCESSOR,
1682
1721
  useExisting: forwardRef(() => NeuMultiselectComponent),
@@ -1894,7 +1933,7 @@ class NeuMultiselectComponent {
1894
1933
  @if (hasError()) {
1895
1934
  <p class="neu-multiselect__error" role="alert">{{ errorMessage() }}</p>
1896
1935
  }
1897
- `, isInline: true, styles: [".neu-multiselect__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-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));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-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__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-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not(:disabled){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:disabled{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__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-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__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-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__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)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary);border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1936
+ `, isInline: true, styles: [".neu-multiselect__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-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));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-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__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-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not(:disabled){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger:disabled{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__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-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__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-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__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)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary);border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1898
1937
  }
1899
1938
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuMultiselectComponent, decorators: [{
1900
1939
  type: Component,
@@ -2119,10 +2158,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
2119
2158
  @if (hasError()) {
2120
2159
  <p class="neu-multiselect__error" role="alert">{{ errorMessage() }}</p>
2121
2160
  }
2122
- `, styles: [".neu-multiselect__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-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));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-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__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-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not(:disabled){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:disabled{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__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-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__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-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__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)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary);border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}\n"] }]
2123
- }], propDecorators: { itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuMultiselectItemDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }] } });
2161
+ `, styles: [".neu-multiselect__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-multiselect__label{position:absolute;left:var(--neu-space-3);top:50%;transform:translateY(-50%);font-size:var(--neu-text-base);color:var(--neu-text-muted);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - var(--neu-space-8));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-multiselect--open .neu-multiselect__label,.neu-multiselect--has-value .neu-multiselect__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-multiselect--open .neu-multiselect__label{color:var(--neu-primary)}.neu-multiselect--error .neu-multiselect__label{color:var(--neu-error)}.neu-multiselect--disabled .neu-multiselect__label{background:var(--neu-surface-2)}.neu-multiselect{position:relative;font-family:var(--neu-font-sans)}.neu-multiselect__trigger{display:flex;align-items:center;width:100%;min-height:48px;padding:var(--neu-space-2) var(--neu-space-3);padding-right:36px;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);cursor:pointer;text-align:left;transition:border-color var(--neu-transition),box-shadow var(--neu-transition)}.neu-multiselect__trigger:hover:not(:disabled){border-color:var(--neu-border-hover)}.neu-multiselect__trigger:focus-visible{outline:none;border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect__trigger:disabled{opacity:.6;cursor:not-allowed;background:var(--neu-surface-2)}.neu-multiselect--open .neu-multiselect__trigger{border-color:var(--neu-primary);box-shadow:0 0 0 3px #007aff1f}.neu-multiselect--error .neu-multiselect__trigger{border-color:var(--neu-error)}.neu-multiselect--error .neu-multiselect__trigger:focus-visible{box-shadow:0 0 0 3px #ef44441f}.neu-multiselect__chips{display:flex;flex-wrap:wrap;gap:var(--neu-space-1);flex:1;min-width:0}.neu-multiselect__placeholder{color:var(--neu-text-disabled);font-size:var(--neu-text-base);line-height:1.5}.neu-multiselect:not(.neu-multiselect--no-float):not(.neu-multiselect--open) .neu-multiselect__placeholder{visibility:hidden}.neu-multiselect__chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 8px;background:var(--neu-primary-soft, rgba(0, 122, 255, .1));color:var(--neu-primary);border-radius:var(--neu-radius-sm);font-size:var(--neu-text-xs);font-weight:500;max-width:160px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.neu-multiselect__chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;cursor:pointer;color:inherit;opacity:.7;border-radius:2px;transition:opacity var(--neu-transition);flex-shrink:0}.neu-multiselect__chip-remove:hover{opacity:1}.neu-multiselect__chip-remove svg{width:10px;height:10px}.neu-multiselect__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-multiselect__clear svg{width:14px;height:14px}.neu-multiselect__clear:hover{color:var(--neu-text);background:var(--neu-surface-3)}.neu-multiselect__chevron{position:absolute;right:var(--neu-space-3);top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--neu-text-muted);pointer-events:none;transition:transform var(--neu-transition);flex-shrink:0}.neu-multiselect--open .neu-multiselect__chevron{transform:translateY(-50%) rotate(180deg)}.neu-multiselect__panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:200;background:var(--neu-surface);border:1.5px solid var(--neu-border);border-radius:var(--neu-radius);box-shadow:var(--neu-shadow-lg);overflow:hidden;max-height:280px;display:flex;flex-direction:column;animation:neu-multiselect-fade-in .12s ease}@keyframes neu-multiselect-fade-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.neu-multiselect__search{padding:var(--neu-space-2);border-bottom:1px solid var(--neu-border);flex-shrink:0}.neu-multiselect__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-multiselect__search-input:focus{border-color:var(--neu-primary);box-shadow:0 0 0 2px #007aff1f}.neu-multiselect__search-input::placeholder{color:var(--neu-text-disabled)}.neu-multiselect__options{flex:1;overflow-y:auto;min-height:0}.neu-multiselect__option{display:flex;align-items:center;gap:var(--neu-space-2);padding:10px var(--neu-space-3);cursor:pointer;font-size:var(--neu-text-sm);color:var(--neu-text);transition:background var(--neu-transition)}.neu-multiselect__option:hover:not(.neu-multiselect__option--disabled){background:var(--neu-surface-2)}.neu-multiselect__option--selected{background:var(--neu-primary-soft, rgba(0, 122, 255, .06));color:var(--neu-primary);font-weight:500}.neu-multiselect__option--disabled{opacity:.4;cursor:not-allowed}.neu-multiselect__checkbox{display:flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:3px;border:1.5px solid var(--neu-border);background:var(--neu-bg);flex-shrink:0;transition:border-color var(--neu-transition),background var(--neu-transition)}.neu-multiselect__checkbox--checked{background:var(--neu-primary);border-color:var(--neu-primary);color:#fff}.neu-multiselect__checkbox-check{width:10px;height:8px;opacity:0;transform:scale(.6);transition:opacity .12s ease,transform .12s ease}.neu-multiselect__checkbox--checked .neu-multiselect__checkbox-check{opacity:1;transform:scale(1)}.neu-multiselect__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)}.neu-multiselect__footer{display:flex;align-items:center;justify-content:space-between;padding:var(--neu-space-2) var(--neu-space-3);border-top:1px solid var(--neu-border);background:var(--neu-surface);flex-shrink:0}.neu-multiselect__footer-count{font-size:var(--neu-text-xs);color:var(--neu-text-muted)}.neu-multiselect__footer-actions{display:flex;align-items:center;gap:var(--neu-space-2)}.neu-multiselect__footer-mode{background:none;border:1px solid var(--neu-border);border-radius:var(--neu-radius-sm);padding:2px 6px;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-text-muted);cursor:pointer;line-height:1.4}.neu-multiselect__footer-mode:hover{background:var(--neu-surface-2);color:var(--neu-text)}.neu-multiselect__footer-clear{background:none;border:none;padding:0;font-size:var(--neu-text-xs);font-family:var(--neu-font-sans);color:var(--neu-primary);cursor:pointer;font-weight:500}.neu-multiselect__footer-clear:hover{text-decoration:underline}.neu-multiselect__count-badge{display:inline-flex;align-items:center;padding:2px 10px;background:var(--neu-primary-100, rgba(14, 165, 233, .12));color:var(--neu-primary);border-radius:var(--neu-radius-full);font-size:var(--neu-text-sm);font-weight:500}.neu-multiselect__chip--overflow{background:var(--neu-surface-2);color:var(--neu-text-muted);border:1px dashed var(--neu-border);cursor:default;pointer-events:none}.neu-multiselect__error{margin-top:var(--neu-space-1);font-size:var(--neu-text-xs);color:var(--neu-error-text, var(--neu-error));font-family:var(--neu-font-sans)}\n"] }]
2162
+ }], ctorParameters: () => [], propDecorators: { itemTpl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NeuMultiselectItemDirective), { isSignal: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAllLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAllLabel", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", 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"] }] } });
2124
2163
 
2125
- /** Token para que neu-radio encuentre a su grupo padre */
2164
+ /** Token para que neu-radio encuentre a su grupo padre / Token for neu-radio to find its parent group */
2126
2165
  const NEU_RADIO_GROUP = new InjectionToken('NEU_RADIO_GROUP');
2127
2166
  /**
2128
2167
  * NeuralUI Radio Group Component
@@ -2138,9 +2177,9 @@ const NEU_RADIO_GROUP = new InjectionToken('NEU_RADIO_GROUP');
2138
2177
  let _neuRadioGroupIdSeq = 0;
2139
2178
  class NeuRadioGroupComponent {
2140
2179
  direction = input('column', ...(ngDevMode ? [{ debugName: "direction" }] : /* istanbul ignore next */ []));
2141
- /** Etiqueta accesible del grupo (WCAG 4.1.2). Usar cuando no hay <legend> visible. */
2180
+ /** Etiqueta accesible del grupo (WCAG 4.1.2). Usar cuando no hay <legend> visible. / Accessible label for the group (WCAG 4.1.2). Use when there is no visible <legend>. */
2142
2181
  ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
2143
- /** Nombre HTML compartido por todos los neu-radio hijos — garantiza la exclusión mutua nativa */
2182
+ /** Nombre HTML compartido por todos los neu-radio hijos — garantiza la exclusión mutua nativa / HTML name shared by all child neu-radio — guarantees native mutual exclusion */
2144
2183
  _name = `neu-radio-group-${++_neuRadioGroupIdSeq}`;
2145
2184
  _value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
2146
2185
  _isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
@@ -2211,7 +2250,7 @@ class NeuRadioComponent {
2211
2250
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2212
2251
  group = inject(NEU_RADIO_GROUP);
2213
2252
  _id = `neu-radio-${_neuRadioIdSeq++}`;
2214
- /** Toma el nombre del grupo padre — así todos los radios del grupo comparten el mismo `name` nativo */
2253
+ /** Toma el nombre del grupo padre — así todos los radios del grupo comparten el mismo `name` nativo / Takes the parent group name — so all radios in the group share the same native `name` */
2215
2254
  _groupName = this.group._name;
2216
2255
  isChecked = computed(() => this.group._value() === this.value(), ...(ngDevMode ? [{ debugName: "isChecked" }] : /* istanbul ignore next */ []));
2217
2256
  isDisabled = computed(() => this.disabled() || this.group._isDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
@@ -2342,34 +2381,59 @@ let _neuSelectIdSeq = 0;
2342
2381
  */
2343
2382
  class NeuSelectComponent {
2344
2383
  elementRef = inject(ElementRef);
2384
+ _urlState = inject(NeuUrlStateService);
2385
+ constructor() {
2386
+ effect(() => {
2387
+ const param = this.urlParam();
2388
+ if (!param)
2389
+ return;
2390
+ const urlVal = this._urlState.getParam(param)();
2391
+ if (urlVal !== untracked(() => this._value())) {
2392
+ this._value.set(urlVal);
2393
+ this._onChange(urlVal);
2394
+ }
2395
+ });
2396
+ }
2345
2397
  /** @internal — ID \u00fanico para asociar label con trigger */
2346
2398
  _triggerId = `neu-select-trigger-${_neuSelectIdSeq++}`;
2347
- /** Template personalizado para cada opción del dropdown */
2399
+ /** Template personalizado para cada opción del dropdown / Custom template for each dropdown option */
2348
2400
  itemTpl = contentChild(NeuSelectItemDirective, ...(ngDevMode ? [{ debugName: "itemTpl" }] : /* istanbul ignore next */ []));
2349
- /** Template personalizado para el valor seleccionado en el trigger */
2401
+ /** Template personalizado para el valor seleccionado en el trigger / Custom template for the selected value in the trigger */
2350
2402
  selectedItemTpl = contentChild(NeuSelectSelectedDirective, ...(ngDevMode ? [{ debugName: "selectedItemTpl" }] : /* istanbul ignore next */ []));
2351
- /** Opciones del dropdown */
2403
+ /** Opciones del dropdown / Dropdown options */
2352
2404
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
2353
- /** Texto del floating label */
2405
+ /** Texto del floating label / Floating label text */
2354
2406
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2355
- /** Placeholder cuando no hay selección */
2407
+ /** Placeholder cuando no hay selección / Placeholder when there is no selection */
2356
2408
  placeholder = input('Seleccionar...', ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
2357
- /** Mensaje de error */
2409
+ /** Mensaje de error / Error message */
2358
2410
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
2359
- /** Deshabilita el select */
2411
+ /** Deshabilita el select / Disables the select */
2360
2412
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2361
- /** Muestra el label como flotante (true) o como label estático encima (false, por defecto) */
2413
+ /** Muestra el label como flotante (true) o como label estático encima (false, por defecto) / Shows the label as floating (true) or static above (false, default) */
2362
2414
  floatingLabel = input(false, ...(ngDevMode ? [{ debugName: "floatingLabel" }] : /* istanbul ignore next */ []));
2363
- /** Activa input de búsqueda/filtro en el panel */
2415
+ /** Activa input de búsqueda/filtro en el panel / Activates the search/filter input in the panel */
2364
2416
  searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
2365
- /** Placeholder del input de búsqueda */
2417
+ /** Placeholder del input de búsqueda / Search input placeholder */
2366
2418
  searchPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
2367
- /** Muestra un botón para limpiar la selección */
2419
+ /** Muestra un botón para limpiar la selección / Shows a button to clear the selection */
2368
2420
  clearable = input(false, ...(ngDevMode ? [{ debugName: "clearable" }] : /* istanbul ignore next */ []));
2369
- /** Texto cuando no hay opciones tras filtrar */
2421
+ /** Texto cuando no hay opciones tras filtrar / Text when no options remain after filtering */
2370
2422
  noResultsMessage = input('Sin resultados', ...(ngDevMode ? [{ debugName: "noResultsMessage" }] : /* istanbul ignore next */ []));
2371
- /** Aria-label del botón de limpiar */
2423
+ /** Aria-label del botón de limpiar / Aria-label for the clear button */
2372
2424
  clearAriaLabel = input('Limpiar selección', ...(ngDevMode ? [{ debugName: "clearAriaLabel" }] : /* istanbul ignore next */ []));
2425
+ /**
2426
+ * Sincroniza el valor seleccionado con este query param de la URL.
2427
+ * Al seleccionar una opción se añade `?{urlParam}=value` a la URL.
2428
+ * Pasar `null` (default) deshabilita la sincronización.
2429
+ */
2430
+ urlParam = input(null, ...(ngDevMode ? [{ debugName: "urlParam" }] : /* istanbul ignore next */ []));
2431
+ /**
2432
+ * Emite el objeto NeuSelectOption completo (incluyendo data) al seleccionar una opción.
2433
+ * Emite null al limpiar la selección.
2434
+ * El valor de ngModel / formControl sigue siendo string.
2435
+ */
2436
+ selectionChange = output();
2373
2437
  // Estado interno
2374
2438
  _value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
2375
2439
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
@@ -2416,7 +2480,7 @@ class NeuSelectComponent {
2416
2480
  this.searchQuery.set('');
2417
2481
  this._onTouched();
2418
2482
  }
2419
- /** Abre el panel y navega con flechas desde el trigger */
2483
+ /** Abre el panel y navega con flechas desde el trigger / Opens the panel and navigates with arrows from the trigger */
2420
2484
  onTriggerKey(event) {
2421
2485
  event.preventDefault();
2422
2486
  if (!this.isOpen()) {
@@ -2427,7 +2491,7 @@ class NeuSelectComponent {
2427
2491
  });
2428
2492
  }
2429
2493
  }
2430
- /** Navega entre opciones con flechas */
2494
+ /** Navega entre opciones con flechas / Navigates between options with arrows */
2431
2495
  focusOptionByIndex(event, current, dir) {
2432
2496
  event.preventDefault();
2433
2497
  const opts = this.filteredOptions().filter((o) => !o.disabled);
@@ -2442,7 +2506,11 @@ class NeuSelectComponent {
2442
2506
  event.stopPropagation();
2443
2507
  this._value.set(null);
2444
2508
  this._onChange(null);
2509
+ const param = this.urlParam();
2510
+ if (param)
2511
+ this._urlState.setParam(param, null);
2445
2512
  this._onTouched();
2513
+ this.selectionChange.emit(null);
2446
2514
  this.close();
2447
2515
  }
2448
2516
  selectOption(option) {
@@ -2450,6 +2518,10 @@ class NeuSelectComponent {
2450
2518
  return;
2451
2519
  this._value.set(option.value);
2452
2520
  this._onChange(option.value);
2521
+ const param = this.urlParam();
2522
+ if (param)
2523
+ this._urlState.setParam(param, option.value);
2524
+ this.selectionChange.emit(option);
2453
2525
  this.close();
2454
2526
  }
2455
2527
  onDocumentClick(event) {
@@ -2458,7 +2530,7 @@ class NeuSelectComponent {
2458
2530
  }
2459
2531
  }
2460
2532
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2461
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuSelectComponent, isStandalone: true, selector: "neu-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "close()" } }, providers: [
2533
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuSelectComponent, isStandalone: true, selector: "neu-select", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, floatingLabel: { classPropertyName: "floatingLabel", publicName: "floatingLabel", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessage: { classPropertyName: "noResultsMessage", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, clearAriaLabel: { classPropertyName: "clearAriaLabel", publicName: "clearAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, urlParam: { classPropertyName: "urlParam", publicName: "urlParam", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange" }, host: { listeners: { "document:click": "onDocumentClick($event)", "keydown.escape": "close()" } }, providers: [
2462
2534
  {
2463
2535
  provide: NG_VALUE_ACCESSOR,
2464
2536
  useExisting: forwardRef(() => NeuSelectComponent),
@@ -2784,7 +2856,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
2784
2856
  <p class="neu-select__error" role="alert">{{ errorMessage() }}</p>
2785
2857
  }
2786
2858
  `, styles: [".neu-select{position:relative;display:block}.neu-select--disabled{opacity:.6;pointer-events:none}.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(:disabled){border-color:var(--neu-border-hover)}.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--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:var(--neu-text-muted);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:var(--neu-text-disabled)}.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__panel{position:absolute;top:100%;left:0;right:0;z-index:var(--neu-z-dropdown);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}@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);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__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"] }]
2787
- }], propDecorators: { 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], noResultsMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], clearAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearAriaLabel", required: false }] }] } });
2859
+ }], ctorParameters: () => [], propDecorators: { 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 }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], floatingLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "floatingLabel", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", 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"] }] } });
2788
2860
 
2789
2861
  /**
2790
2862
  * NeuralUI Slider Component
@@ -2799,25 +2871,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
2799
2871
  class NeuSliderComponent {
2800
2872
  static _idCounter = 0;
2801
2873
  sliderId = `neu-slider-${++NeuSliderComponent._idCounter}`;
2802
- /** Valor actual */
2874
+ /** Valor actual / Current value */
2803
2875
  value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
2804
- /** Valor mínimo */
2876
+ /** Valor mínimo / Minimum value */
2805
2877
  min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
2806
- /** Valor máximo */
2878
+ /** Valor máximo / Maximum value */
2807
2879
  max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
2808
- /** Paso */
2880
+ /** Paso / Step */
2809
2881
  step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
2810
- /** Etiqueta */
2882
+ /** Etiqueta / Label */
2811
2883
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2812
- /** Muestra el valor numerico */
2884
+ /** Muestra el valor numerico / Shows the numeric value */
2813
2885
  showValue = input(true, ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
2814
- /** Muestra min/mid/max bajo la barra */
2886
+ /** Muestra min/mid/max bajo la barra / Shows min/mid/max below the bar */
2815
2887
  showTicks = input(false, ...(ngDevMode ? [{ debugName: "showTicks" }] : /* istanbul ignore next */ []));
2816
- /** Unidad a mostrar junto al valor */
2888
+ /** Unidad a mostrar junto al valor / Unit to display next to the value */
2817
2889
  unit = input('', ...(ngDevMode ? [{ debugName: "unit" }] : /* istanbul ignore next */ []));
2818
- /** Deshabilitado */
2890
+ /** Deshabilitado / Disabled */
2819
2891
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2820
- /** Emite al mover el slider */
2892
+ /** Emite al mover el slider / Emits when the slider moves */
2821
2893
  valueChange = output();
2822
2894
  fillPercent = computed(() => {
2823
2895
  const range = this.max() - this.min();
@@ -2939,7 +3011,7 @@ class NeuSwitchComponent {
2939
3011
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
2940
3012
  _id = `neu-switch-${_neuSwitchIdSeq++}`;
2941
3013
  _checked = signal(false, ...(ngDevMode ? [{ debugName: "_checked" }] : /* istanbul ignore next */ []));
2942
- /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState */
3014
+ /** Estado disabled interno — combina el input `disabled` con el CVA setDisabledState / Internal disabled state — combines the `disabled` input with CVA setDisabledState */
2943
3015
  _cvaDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_cvaDisabled" }] : /* istanbul ignore next */ []));
2944
3016
  _isDisabled = computed(() => this.disabled() || this._cvaDisabled(), ...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
2945
3017
  _onChange = () => { };
@@ -3039,7 +3111,7 @@ class NeuTextareaComponent {
3039
3111
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
3040
3112
  rows = input(3, ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
3041
3113
  autoResize = input(false, ...(ngDevMode ? [{ debugName: "autoResize" }] : /* istanbul ignore next */ []));
3042
- /** Permite al usuario redimensionar el campo manualmente (por defecto: true) */
3114
+ /** Permite al usuario redimensionar el campo manualmente (por defecto: true) / Allows the user to manually resize the field (default: true) */
3043
3115
  resizable = input(true, ...(ngDevMode ? [{ debugName: "resizable" }] : /* istanbul ignore next */ []));
3044
3116
  errorMessage = input('', ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
3045
3117
  hint = input('', ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
@@ -3199,8 +3271,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
3199
3271
  /**
3200
3272
  * NeuralUI ToggleButtonGroup Component
3201
3273
  *
3202
- * Grupo de botones de selección (single o múltiple).
3203
- * Equivalente técnicamente superior al SelectButton de PrimeNG.
3274
+ * Grupo de botones de selección (single o múltiple). / Selection button group (single or multiple).
3275
+ * Equivalente técnicamente superior al SelectButton de PrimeNG. / Technically superior equivalent to PrimeNG's SelectButton.
3204
3276
  *
3205
3277
  * Uso (single):
3206
3278
  * <neu-toggle-button-group [options]="opts" [(ngModel)]="value" />
@@ -3209,7 +3281,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
3209
3281
  * <neu-toggle-button-group [options]="opts" [multiple]="true" [(ngModel)]="values" />
3210
3282
  */
3211
3283
  class NeuToggleButtonGroupComponent {
3212
- /** Lista de opciones del grupo */
3284
+ /** Lista de opciones del grupo / Group option list */
3213
3285
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
3214
3286
  /**
3215
3287
  * Permite seleccionar múltiples opciones.
@@ -3217,11 +3289,11 @@ class NeuToggleButtonGroupComponent {
3217
3289
  * - true: valor es `T[]`
3218
3290
  */
3219
3291
  multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
3220
- /** Tamaño visual */
3292
+ /** Tamaño visual / Visual size */
3221
3293
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
3222
- /** Deshabilita todo el grupo */
3294
+ /** Deshabilita todo el grupo / Disables the entire group */
3223
3295
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
3224
- /** Emite el nuevo valor al cambiar (útil sin formControl) */
3296
+ /** Emite el nuevo valor al cambiar (útil sin formControl) / Emits the new value on change (useful without formControl) */
3225
3297
  neuChange = output();
3226
3298
  _value = signal(null, ...(ngDevMode ? [{ debugName: "_value" }] : /* istanbul ignore next */ []));
3227
3299
  _isDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_isDisabled" }] : /* istanbul ignore next */ []));
@@ -3363,9 +3435,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
3363
3435
  * ];
3364
3436
  */
3365
3437
  class NeuBreadcrumbComponent {
3366
- /** Lista de ítems de navegación */
3438
+ /** Lista de ítems de navegación / Navigation item list */
3367
3439
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
3368
- /** Separador personalizable */
3440
+ /** Separador personalizable / Customizable separator */
3369
3441
  separator = input('/', ...(ngDevMode ? [{ debugName: "separator" }] : /* istanbul ignore next */ []));
3370
3442
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuBreadcrumbComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3371
3443
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuBreadcrumbComponent, isStandalone: true, selector: "neu-breadcrumb", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
@@ -3421,7 +3493,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
3421
3493
  `, styles: [".neu-breadcrumb{display:inline-flex}.neu-breadcrumb__list{display:flex;align-items:center;flex-wrap:wrap;gap:4px;list-style:none;margin:0;padding:0;font-family:var(--neu-font-sans);font-size:var(--neu-text-sm)}.neu-breadcrumb__item{display:inline-flex;align-items:center;gap:4px}.neu-breadcrumb__link{color:var(--neu-text-muted);text-decoration:none;transition:color var(--neu-transition);border-radius:var(--neu-radius-xs);outline:none}.neu-breadcrumb__link:hover{color:var(--neu-text)}.neu-breadcrumb__link:focus-visible{outline:2px solid var(--neu-primary);outline-offset:2px}.neu-breadcrumb__separator{color:var(--neu-text-disabled);font-size:var(--neu-text-xs);-webkit-user-select:none;user-select:none;margin:0 2px}.neu-breadcrumb__current{color:var(--neu-text);font-weight:500}\n"] }]
3422
3494
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }] } });
3423
3495
 
3424
- /** @internal — componente flotante del tooltip, renderizado vía CDK Portal */
3496
+ /** @internal — componente flotante del tooltip, renderizado vía CDK Portal / floating tooltip component, rendered via CDK Portal */
3425
3497
  class NeuTooltipOverlayComponent {
3426
3498
  text = input.required(...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
3427
3499
  tooltipId = input('', ...(ngDevMode ? [{ debugName: "tooltipId" }] : /* istanbul ignore next */ []));
@@ -3455,7 +3527,7 @@ class NeuTooltipDirective {
3455
3527
  _elementRef = inject((ElementRef));
3456
3528
  _injector = inject(Injector);
3457
3529
  _tooltipId = `neu-tooltip-${Math.random().toString(36).slice(2, 7)}`;
3458
- /** Elementos HTML nativamente focusables que no necesitan tabindex extra */
3530
+ /** Elementos HTML nativamente focusables que no necesitan tabindex extra / Natively focusable HTML elements that don't need extra tabindex */
3459
3531
  _NATIVE_FOCUSABLE = /^(a|button|input|select|textarea|details|summary)$/i;
3460
3532
  _needsTabindex = () => !this._NATIVE_FOCUSABLE.test(this._elementRef.nativeElement.tagName);
3461
3533
  _overlayRef = null;
@@ -3563,29 +3635,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
3563
3635
 
3564
3636
  class NeuNavComponent {
3565
3637
  router = inject(Router);
3566
- // ---- Señal reactiva de ruta activa ----
3638
+ // ---- Señal reactiva de ruta activa / Reactive active route signal ----
3567
3639
  currentUrl = toSignal(this.router.events.pipe(filter$1((e) => e instanceof NavigationEnd)), { initialValue: null });
3568
3640
  // ---- Inputs ----
3569
- /** Lista de ítems de navegación */
3641
+ /** Lista de ítems de navegación / Navigation item list */
3570
3642
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
3571
- /** Estado inicial colapsado */
3643
+ /** Estado inicial colapsado / Initial collapsed state */
3572
3644
  collapsed = input(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
3573
- /** Muestra el botón de colapsar/expandir */
3645
+ /** Muestra el botón de colapsar/expandir / Shows the collapse/expand button */
3574
3646
  collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
3575
- /** Etiqueta accesible del <nav> */
3647
+ /** Etiqueta accesible del <nav> / Accessible label for the <nav> */
3576
3648
  ariaLabel = input('Navegación principal', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
3577
- /** Aria-label del botón cuando el nav está colapsado */
3649
+ /** Aria-label del botón cuando el nav está colapsado / Aria-label for the button when the nav is collapsed */
3578
3650
  expandLabel = input('Expandir menú', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
3579
- /** Aria-label del botón cuando el nav está expandido */
3651
+ /** Aria-label del botón cuando el nav está expandido / Aria-label for the button when the nav is expanded */
3580
3652
  collapseLabel = input('Colapsar menú', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
3581
- /** Emite cuando cambia el estado colapsado */
3653
+ /** Emite cuando cambia el estado colapsado / Emits when the collapsed state changes */
3582
3654
  collapsedChange = output();
3583
- // ---- Estado interno ----
3655
+ // ---- Estado interno / Internal state ----
3584
3656
  // Sigue el input `collapsed` del padre (permite el configurador)
3585
3657
  // pero puede ser sobreescrito localmente con toggleCollapse()
3586
3658
  isCollapsed = signal(this.collapsed(), ...(ngDevMode ? [{ debugName: "isCollapsed" }] : /* istanbul ignore next */ []));
3587
3659
  openGroups = signal(new Set(), ...(ngDevMode ? [{ debugName: "openGroups" }] : /* istanbul ignore next */ []));
3588
- // ---- Flyout para modo colapsado ----
3660
+ // ---- Flyout para modo colapsado / Flyout for collapsed mode ----
3589
3661
  flyoutState = signal(null, ...(ngDevMode ? [{ debugName: "flyoutState" }] : /* istanbul ignore next */ []));
3590
3662
  _flyoutTimer = null;
3591
3663
  constructor() {
@@ -3599,7 +3671,7 @@ class NeuNavComponent {
3599
3671
  clearTimeout(this._flyoutTimer);
3600
3672
  });
3601
3673
  }
3602
- // ---- Helpers de estado ----
3674
+ // ---- Helpers de estado / State helpers ----
3603
3675
  toggleCollapse() {
3604
3676
  this.isCollapsed.update((v) => {
3605
3677
  const next = !v;
@@ -4509,15 +4581,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
4509
4581
  * (pageChange)="currentPage = $event" />
4510
4582
  */
4511
4583
  class NeuPaginationComponent {
4512
- /** Página actual (1-indexed) */
4584
+ /** Página actual (1-indexed) / Current page (1-indexed) */
4513
4585
  page = input(1, ...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
4514
- /** Total de ítems */
4586
+ /** Total de ítems / Total items */
4515
4587
  total = input(0, ...(ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []));
4516
- /** Ítems por página */
4588
+ /** Ítems por página / Items per page */
4517
4589
  pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
4518
- /** Número máximo de botones de página visibles (sin contar anterior/siguiente) */
4590
+ /** Número máximo de botones de página visibles (sin contar anterior/siguiente) / Maximum number of visible page buttons (not counting prev/next) */
4519
4591
  maxVisible = input(7, ...(ngDevMode ? [{ debugName: "maxVisible" }] : /* istanbul ignore next */ []));
4520
- /** Emite la nueva página al hacer click */
4592
+ /** Emite la nueva página al hacer click / Emits the new page on click */
4521
4593
  pageChange = output();
4522
4594
  totalPages = computed(() => Math.max(1, Math.ceil(this.total() / this.pageSize())), ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
4523
4595
  pages = computed(() => {
@@ -4691,12 +4763,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
4691
4763
  /**
4692
4764
  * NeuralUI Sidebar Component
4693
4765
  *
4694
- * El estado abierto/cerrado se gestiona automáticamente desde la URL
4695
- * via NeuUrlStateService (?menu=open por defecto).
4766
+ * El estado abierto/cerrado se gestiona automáticamente desde la URL / The open/closed state is automatically managed from the URL
4767
+ * via NeuUrlStateService (?menu=open por defecto). / via NeuUrlStateService (?menu=open by default).
4696
4768
  *
4697
4769
  * Modos:
4698
- * - overlay (default): panel flotante sobre el contenido con backdrop
4699
- * - persistent: sidebar fijo integrado en el layout (desktop)
4770
+ * - overlay (default): panel flotante sobre el contenido con backdrop / floating panel above content with backdrop
4771
+ * - persistent: sidebar fijo integrado en el layout (desktop) / fixed sidebar integrated in the layout (desktop)
4700
4772
  *
4701
4773
  * Uso:
4702
4774
  * <neu-sidebar urlParam="menu" [persistent]="isDesktop()">
@@ -4705,14 +4777,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
4705
4777
  * <div neu-sidebar-footer>...</div>
4706
4778
  * </neu-sidebar>
4707
4779
  *
4708
- * Abrir desde cualquier parte:
4780
+ * Abrir desde cualquier parte: / Open from anywhere:
4709
4781
  * inject(NeuUrlStateService).setParam('menu', 'open', false);
4710
4782
  */
4711
4783
  class NeuSidebarComponent {
4712
4784
  urlState = inject(NeuUrlStateService);
4713
- /** Posición del sidebar: izquierda o derecha de la pantalla */
4785
+ /** Posición del sidebar: izquierda o derecha de la pantalla / Sidebar position: left or right of the screen */
4714
4786
  side = input('left', ...(ngDevMode ? [{ debugName: "side" }] : /* istanbul ignore next */ []));
4715
- /** QueryParam que controla el estado. Default: 'menu' (?menu=open) */
4787
+ /** QueryParam que controla el estado. Default: 'menu' (?menu=open) / QueryParam that controls the state. Default: 'menu' (?menu=open) */
4716
4788
  urlParam = input('menu', ...(ngDevMode ? [{ debugName: "urlParam" }] : /* istanbul ignore next */ []));
4717
4789
  /**
4718
4790
  * Modo persistente: el sidebar está siempre visible como parte del layout.
@@ -4724,23 +4796,23 @@ class NeuSidebarComponent {
4724
4796
  * principal y el sidebar persistente no necesita su propio header.
4725
4797
  */
4726
4798
  hideHeader = input(false, ...(ngDevMode ? [{ debugName: "hideHeader" }] : /* istanbul ignore next */ []));
4727
- /** Etiqueta accesible para el <aside> */
4799
+ /** Etiqueta accesible para el <aside> / Accessible label for the <aside> */
4728
4800
  ariaLabel = input('Menú de navegación', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
4729
- /** Etiqueta accesible para el botón cerrar */
4801
+ /** Etiqueta accesible para el botón cerrar / Accessible label for the close button */
4730
4802
  closeLabel = input('Cerrar menú de navegación', ...(ngDevMode ? [{ debugName: "closeLabel" }] : /* istanbul ignore next */ []));
4731
- /** Emite cuando el usuario cierra el sidebar (overlay click o botón) */
4803
+ /** Emite cuando el usuario cierra el sidebar (overlay click o botón) / Emits when the user closes the sidebar (overlay click or button) */
4732
4804
  closeRequested = output();
4733
- /** Signal reactivo: true si el sidebar debe mostrarse */
4805
+ /** Signal reactivo: true si el sidebar debe mostrarse / Reactive signal: true if the sidebar should be shown */
4734
4806
  isOpen = computed(() => {
4735
4807
  if (this.persistent())
4736
4808
  return true;
4737
4809
  return this.urlState.getParam(this.urlParam())() === 'open';
4738
4810
  }, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
4739
- /** Abre el sidebar — añade ?{urlParam}=open a la URL */
4811
+ /** Abre el sidebar — añade ?{urlParam}=open a la URL / Opens the sidebar — adds ?{urlParam}=open to the URL */
4740
4812
  open(replaceUrl = false) {
4741
4813
  this.urlState.setParam(this.urlParam(), 'open', replaceUrl);
4742
4814
  }
4743
- /** Cierra el sidebar — elimina el parámetro de la URL */
4815
+ /** Cierra el sidebar — elimina el parámetro de la URL / Closes the sidebar — removes the URL parameter */
4744
4816
  close() {
4745
4817
  this.urlState.setParam(this.urlParam(), null, true);
4746
4818
  this.closeRequested.emit();
@@ -4868,15 +4940,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
4868
4940
  * </neu-stepper>
4869
4941
  */
4870
4942
  class NeuStepperComponent {
4871
- /** Pasos del wizard */
4943
+ /** Pasos del wizard / Wizard steps */
4872
4944
  steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
4873
- /** Índice del paso activo (0-based) */
4945
+ /** Índice del paso activo (0-based) / Active step index (0-based) */
4874
4946
  activeStep = input(0, ...(ngDevMode ? [{ debugName: "activeStep" }] : /* istanbul ignore next */ []));
4875
- /** Si true, solo permite ir hacia adelante secuencialmente */
4947
+ /** Si true, solo permite ir hacia adelante secuencialmente / If true, only allows moving forward sequentially */
4876
4948
  linear = input(false, ...(ngDevMode ? [{ debugName: "linear" }] : /* istanbul ignore next */ []));
4877
- /** Emite el nuevo índice al cambiar */
4949
+ /** Emite el nuevo índice al cambiar / Emits the new index on change */
4878
4950
  stepChange = output();
4879
- /** Set de pasos completados */
4951
+ /** Set de pasos completados / Set of completed steps */
4880
4952
  _completed = signal(new Set(), ...(ngDevMode ? [{ debugName: "_completed" }] : /* istanbul ignore next */ []));
4881
4953
  isCompleted = (i) => this._completed().has(i) || (this.steps()[i]?.completed ?? false) || i < this.activeStep();
4882
4954
  goTo(i) {
@@ -4887,7 +4959,7 @@ class NeuStepperComponent {
4887
4959
  return;
4888
4960
  this.stepChange.emit(i);
4889
4961
  }
4890
- /** Marca el paso actual como completado y avanza al siguiente */
4962
+ /** Marca el paso actual como completado y avanza al siguiente / Marks the current step as completed and advances to the next */
4891
4963
  next() {
4892
4964
  const current = this.activeStep();
4893
4965
  const updated = new Set(this._completed());
@@ -5033,8 +5105,8 @@ const NEU_TABS_CONTEXT = new InjectionToken('NeuTabsContext');
5033
5105
  /**
5034
5106
  * NeuralUI Tabs Component
5035
5107
  *
5036
- * Sistema de pestañas con estado sincronizado a la URL via NeuUrlStateService.
5037
- * El panel activo se determina por ?{tabParam}={tabId}.
5108
+ * Sistema de pestañas con estado sincronizado a la URL via NeuUrlStateService. / Tab system with state synchronized to the URL via NeuUrlStateService.
5109
+ * El panel activo se determina por ?{tabParam}={tabId}. / The active panel is determined by ?{tabParam}={tabId}.
5038
5110
  *
5039
5111
  * Uso:
5040
5112
  * <neu-tabs [tabs]="tabs" tabParam="tab">
@@ -5053,17 +5125,17 @@ class NeuTabsComponent {
5053
5125
  requestAnimationFrame(() => this._updateIndicator());
5054
5126
  });
5055
5127
  }
5056
- /** Definición de pestañas */
5128
+ /** Definición de pestañas / Tab definitions */
5057
5129
  tabs = input([], ...(ngDevMode ? [{ debugName: "tabs" }] : /* istanbul ignore next */ []));
5058
- /** QueryParam que almacena la pestaña activa */
5130
+ /** QueryParam que almacena la pestaña activa / QueryParam that stores the active tab */
5059
5131
  tabParam = input('tab', ...(ngDevMode ? [{ debugName: "tabParam" }] : /* istanbul ignore next */ []));
5060
- /** Si true, elimina el padding interno de los paneles */
5132
+ /** Si true, elimina el padding interno de los paneles / If true, removes the internal padding from panels */
5061
5133
  flush = input(false, ...(ngDevMode ? [{ debugName: "flush" }] : /* istanbul ignore next */ []));
5062
- /** Etiqueta accesible del rol tablist */
5134
+ /** Etiqueta accesible del rol tablist / Accessible label for the tablist role */
5063
5135
  ariaLabel = input('Pestañas de contenido', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
5064
- /** Emite al cambiar de pestaña */
5136
+ /** Emite al cambiar de pestaña / Emits when the tab changes */
5065
5137
  tabChange = output();
5066
- /** ID de la pestaña activa (de la URL o la primera disponible) */
5138
+ /** ID de la pestaña activa (de la URL o la primera disponible) / Active tab ID (from the URL or the first available) */
5067
5139
  activeTabId = computed(() => {
5068
5140
  const fromUrl = this.urlState.getParam(this.tabParam())();
5069
5141
  const available = this.tabs().find((t) => t.id === fromUrl && !t.disabled);
@@ -5072,7 +5144,7 @@ class NeuTabsComponent {
5072
5144
  // Fallback: primera pestaña no deshabilitada
5073
5145
  return this.tabs().find((t) => !t.disabled)?.id ?? '';
5074
5146
  }, ...(ngDevMode ? [{ debugName: "activeTabId" }] : /* istanbul ignore next */ []));
5075
- /** Posición del indicador calculada mediante medición DOM */
5147
+ /** Posición del indicador calculada mediante medición DOM / Indicator position calculated via DOM measurement */
5076
5148
  _indicatorLeft = signal('0px', ...(ngDevMode ? [{ debugName: "_indicatorLeft" }] : /* istanbul ignore next */ []));
5077
5149
  _indicatorWidth = signal('0px', ...(ngDevMode ? [{ debugName: "_indicatorWidth" }] : /* istanbul ignore next */ []));
5078
5150
  indicatorStyle = computed(() => `left: ${this._indicatorLeft()}; width: ${this._indicatorWidth()}`, ...(ngDevMode ? [{ debugName: "indicatorStyle" }] : /* istanbul ignore next */ []));
@@ -5107,7 +5179,7 @@ class NeuTabsComponent {
5107
5179
  this.tabChange.emit(tab.id);
5108
5180
  requestAnimationFrame(() => this._updateIndicator());
5109
5181
  }
5110
- /** Mueve el foco entre tabs con flechas (roving tabindex — WAI-ARIA Tabs Pattern) */
5182
+ /** Mueve el foco entre tabs con flechas (roving tabindex — WAI-ARIA Tabs Pattern) / Moves focus between tabs with arrows (roving tabindex — WAI-ARIA Tabs Pattern) */
5111
5183
  focusTab(event, dir) {
5112
5184
  event.preventDefault();
5113
5185
  const enabledTabs = this.tabs().filter((t) => !t.disabled);
@@ -5214,15 +5286,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5214
5286
  /**
5215
5287
  * NeuralUI Tab Panel
5216
5288
  *
5217
- * Panel de contenido asociado a una pestaña de NeuTabsComponent.
5218
- * Solo se renderiza (no oculta con CSS) cuando la pestaña está activa.
5289
+ * Panel de contenido asociado a una pestaña de NeuTabsComponent. / Content panel associated with a NeuTabsComponent tab.
5290
+ * Solo se renderiza (no oculta con CSS) cuando la pestaña está activa. / Only rendered (not hidden with CSS) when the tab is active.
5219
5291
  *
5220
5292
  * Uso: hijo directo de <neu-tabs>
5221
5293
  * <neu-tab-panel tabId="api">...</neu-tab-panel>
5222
5294
  */
5223
5295
  class NeuTabPanelComponent {
5224
5296
  tabs = inject(NEU_TABS_CONTEXT, { optional: true });
5225
- /** ID que debe coincidir con NeuTab.id del padre */
5297
+ /** ID que debe coincidir con NeuTab.id del padre / ID that must match the parent NeuTab.id */
5226
5298
  tabId = input.required(...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
5227
5299
  isActive = computed(() => this.tabs?.activeTabId() === this.tabId(), ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
5228
5300
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuTabPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -5265,7 +5337,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5265
5337
  * NeuralUI Accordion Component
5266
5338
  *
5267
5339
  * Paneles expandibles / colapsables con animación suave.
5268
- * Soporta modo múltiple (varios abiertos a la vez) o exclusivo.
5340
+ * Soporta modo múltiple (varios abiertos a la vez) o exclusivo. / Supports multiple (several open at once) or exclusive mode.
5269
5341
  *
5270
5342
  * Uso:
5271
5343
  * <neu-accordion [items]="items" />
@@ -5273,13 +5345,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5273
5345
  */
5274
5346
  class NeuAccordionComponent {
5275
5347
  _sanitizer = inject(DomSanitizer);
5276
- /** Lista de paneles */
5348
+ /** Lista de paneles / Panel list */
5277
5349
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
5278
- /** Permite varios paneles abiertos a la vez */
5350
+ /** Permite varios paneles abiertos a la vez / Allows multiple panels open at once */
5279
5351
  multiple = input(false, ...(ngDevMode ? [{ debugName: "multiple" }] : /* istanbul ignore next */ []));
5280
- /** Borde exterior alrededor del accordion */
5352
+ /** Borde exterior alrededor del accordion / Outer border around the accordion */
5281
5353
  bordered = input(true, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
5282
- /** Emite el id del panel al abrirse/cerrarse */
5354
+ /** Emite el id del panel al abrirse/cerrarse / Emits the panel id on open/close */
5283
5355
  panelToggle = output();
5284
5356
  /**
5285
5357
  * Set de IDs actualmente expandidos.
@@ -5427,13 +5499,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5427
5499
  * </neu-card>
5428
5500
  */
5429
5501
  class NeuCardComponent {
5430
- /** Espaciado interior del cuerpo */
5502
+ /** Espaciado interior del cuerpo / Inner body padding */
5431
5503
  padding = input('md', ...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
5432
- /** Efecto hover con elevación de sombra */
5504
+ /** Efecto hover con elevación de sombra / Hover effect with shadow elevation */
5433
5505
  hoverable = input(false, ...(ngDevMode ? [{ debugName: "hoverable" }] : /* istanbul ignore next */ []));
5434
- /** Borde con acento de color primario */
5506
+ /** Borde con acento de color primario / Border with primary color accent */
5435
5507
  bordered = input(false, ...(ngDevMode ? [{ debugName: "bordered" }] : /* istanbul ignore next */ []));
5436
- /** Card compacta sin bordes ni sombras */
5508
+ /** Card compacta sin bordes ni sombras / Compact card without borders or shadows */
5437
5509
  flat = input(false, ...(ngDevMode ? [{ debugName: "flat" }] : /* istanbul ignore next */ []));
5438
5510
  hostClasses = computed(() => ({
5439
5511
  'neu-card': true,
@@ -5536,8 +5608,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5536
5608
  args: [{ providedIn: 'root' }]
5537
5609
  }] });
5538
5610
  /**
5539
- * NeuDialogComponent — Diálogo accesible con header, body y footer.
5540
- * Úsalo directamente como componente declarativo pasando `open` como signal.
5611
+ * NeuDialogComponent — Diálogo accesible con header, body y footer. / Accessible dialog with header, body and footer.
5612
+ * Úsalo directamente como componente declarativo pasando `open` como signal. / Use it directly as a declarative component passing `open` as a signal.
5541
5613
  *
5542
5614
  * Para uso programático, utiliza NeuDialogService.open().
5543
5615
  *
@@ -5550,17 +5622,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
5550
5622
  * </neu-dialog>
5551
5623
  */
5552
5624
  class NeuDialogComponent {
5553
- /** Controla la visibilidad del diálogo. */
5625
+ /** Controla la visibilidad del diálogo. / Controls dialog visibility. */
5554
5626
  open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
5555
- /** Título que aparece en el header. */
5627
+ /** Título que aparece en el header. / Title shown in the header. */
5556
5628
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
5557
- /** Tamaño del panel: sm | md | lg | xl | full. */
5629
+ /** Tamaño del panel: sm | md | lg | xl | full. / Panel size: sm | md | lg | xl | full. */
5558
5630
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
5559
- /** Si es true, el backdrop y el botón cerrar no funcionan. */
5631
+ /** Si es true, el backdrop y el botón cerrar no funcionan. / If true, the backdrop and close button do not work. */
5560
5632
  disableClose = input(false, ...(ngDevMode ? [{ debugName: "disableClose" }] : /* istanbul ignore next */ []));
5561
- /** Emite cuando el usuario cierra el diálogo. */
5633
+ /** Emite cuando el usuario cierra el diálogo. / Emits when the user closes the dialog. */
5562
5634
  closed = output();
5563
- /** @internal — ID único para aria-labelledby */
5635
+ /** @internal — ID único para aria-labelledby / Unique ID for aria-labelledby */
5564
5636
  _uid = Math.random().toString(36).slice(2, 7);
5565
5637
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5566
5638
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuDialogComponent, isStandalone: true, selector: "neu-dialog", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disableClose: { classPropertyName: "disableClose", publicName: "disableClose", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { properties: { "class.neu-dialog--open": "open()", "attr.aria-hidden": "!open()" } }, ngImport: i0, template: `
@@ -5711,7 +5783,7 @@ function asRows(data) {
5711
5783
  class NeuTableComponent {
5712
5784
  urlState = inject(NeuUrlStateService);
5713
5785
  expandTemplate = contentChild(NeuTableExpandDirective, ...(ngDevMode ? [{ debugName: "expandTemplate" }] : /* istanbul ignore next */ []));
5714
- // ---- Inputs de datos ----
5786
+ // ---- Inputs de datos / Data inputs ----
5715
5787
  columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
5716
5788
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
5717
5789
  pageSize = input(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
@@ -5719,20 +5791,20 @@ class NeuTableComponent {
5719
5791
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
5720
5792
  emptyMessage = input('No se encontraron resultados', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []));
5721
5793
  skeletonRows = input([1, 2, 3, 4, 5], ...(ngDevMode ? [{ debugName: "skeletonRows" }] : /* istanbul ignore next */ []));
5722
- // ---- Inputs de funcionalidad ----
5794
+ // ---- Inputs de funcionalidad / Functionality inputs ----
5723
5795
  searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
5724
5796
  searchPlaceholder = input('Buscar...', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
5725
5797
  exactMatchable = input(false, ...(ngDevMode ? [{ debugName: "exactMatchable" }] : /* istanbul ignore next */ []));
5726
5798
  exactMatchLabel = input('Búsqueda exacta', ...(ngDevMode ? [{ debugName: "exactMatchLabel" }] : /* istanbul ignore next */ []));
5727
- /** Aria-label del input de búsqueda */
5799
+ /** Aria-label del input de búsqueda / Aria-label for the search input */
5728
5800
  searchAriaLabel = input('Buscar en la tabla', ...(ngDevMode ? [{ debugName: "searchAriaLabel" }] : /* istanbul ignore next */ []));
5729
- /** Aria-label del botón de limpiar búsqueda */
5801
+ /** Aria-label del botón de limpiar búsqueda / Aria-label for the search clear button */
5730
5802
  clearSearchAriaLabel = input('Limpiar búsqueda', ...(ngDevMode ? [{ debugName: "clearSearchAriaLabel" }] : /* istanbul ignore next */ []));
5731
- /** Texto del botón que elimina el filtro activo */
5803
+ /** Texto del botón que elimina el filtro activo / Button text that removes the active filter */
5732
5804
  clearFilterLabel = input('Eliminar filtro', ...(ngDevMode ? [{ debugName: "clearFilterLabel" }] : /* istanbul ignore next */ []));
5733
- /** Aria-label del botón de página anterior */
5805
+ /** Aria-label del botón de página anterior / Aria-label for the previous page button */
5734
5806
  previousPageAriaLabel = input('Anterior', ...(ngDevMode ? [{ debugName: "previousPageAriaLabel" }] : /* istanbul ignore next */ []));
5735
- /** Aria-label del botón de página siguiente */
5807
+ /** Aria-label del botón de página siguiente / Aria-label for the next page button */
5736
5808
  nextPageAriaLabel = input('Siguiente', ...(ngDevMode ? [{ debugName: "nextPageAriaLabel" }] : /* istanbul ignore next */ []));
5737
5809
  sortable = input(false, ...(ngDevMode ? [{ debugName: "sortable" }] : /* istanbul ignore next */ []));
5738
5810
  selectable = input(false, ...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
@@ -5741,9 +5813,9 @@ class NeuTableComponent {
5741
5813
  exportFileName = input('export', ...(ngDevMode ? [{ debugName: "exportFileName" }] : /* istanbul ignore next */ []));
5742
5814
  pageSizeOptions = input([], ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
5743
5815
  stickyHeader = input(false, ...(ngDevMode ? [{ debugName: "stickyHeader" }] : /* istanbul ignore next */ []));
5744
- /** Clave del campo que identifica de forma única cada fila */
5816
+ /** Clave del campo que identifica de forma única cada fila / Field key that uniquely identifies each row */
5745
5817
  rowKey = input('id', ...(ngDevMode ? [{ debugName: "rowKey" }] : /* istanbul ignore next */ []));
5746
- // ---- URL params (personalizables para múltiples tablas) ----
5818
+ // ---- URL params (personalizables / customizable for multiple tables) ----
5747
5819
  pageParam = input('page', ...(ngDevMode ? [{ debugName: "pageParam" }] : /* istanbul ignore next */ []));
5748
5820
  searchParam = input('q', ...(ngDevMode ? [{ debugName: "searchParam" }] : /* istanbul ignore next */ []));
5749
5821
  sortParam = input('sort', ...(ngDevMode ? [{ debugName: "sortParam" }] : /* istanbul ignore next */ []));
@@ -5762,7 +5834,7 @@ class NeuTableComponent {
5762
5834
  const d = this.urlState.getParam(this.sortDirParam())();
5763
5835
  return d === 'desc' ? 'desc' : 'asc';
5764
5836
  }, ...(ngDevMode ? [{ debugName: "sortDir" }] : /* istanbul ignore next */ []));
5765
- // ---- Pipeline de datos ----
5837
+ // ---- Pipeline de datos / Data pipeline ----
5766
5838
  rows = computed(() => asRows(this.data()), ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
5767
5839
  exactMatch = signal(false, ...(ngDevMode ? [{ debugName: "exactMatch" }] : /* istanbul ignore next */ []));
5768
5840
  filteredData = computed(() => {
@@ -5827,7 +5899,7 @@ class NeuTableComponent {
5827
5899
  cols++;
5828
5900
  return cols;
5829
5901
  }, ...(ngDevMode ? [{ debugName: "totalColspan" }] : /* istanbul ignore next */ []));
5830
- // ---- Expansión de filas ----
5902
+ // ---- Expansión de filas / Row expansion ----
5831
5903
  _expandedKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "_expandedKeys" }] : /* istanbul ignore next */ []));
5832
5904
  isRowExpanded(row) {
5833
5905
  return this._expandedKeys().has(row[this.rowKey()]);
@@ -5841,7 +5913,7 @@ class NeuTableComponent {
5841
5913
  set.add(key);
5842
5914
  this._expandedKeys.set(set);
5843
5915
  }
5844
- // ---- Selección de filas ----
5916
+ // ---- Selección de filas / Row selection ----
5845
5917
  _selectedKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "_selectedKeys" }] : /* istanbul ignore next */ []));
5846
5918
  selectedCount = computed(() => this._selectedKeys().size, ...(ngDevMode ? [{ debugName: "selectedCount" }] : /* istanbul ignore next */ []));
5847
5919
  isAllSelected = computed(() => this.paginatedData().length > 0 &&
@@ -5880,7 +5952,7 @@ class NeuTableComponent {
5880
5952
  const selected = this.rows().filter((r) => keys.has(r[this.rowKey()]));
5881
5953
  this.rowSelectionChange.emit(selected);
5882
5954
  }
5883
- // ---- Acciones de URL ----
5955
+ // ---- Acciones de URL / URL actions ----
5884
5956
  goToPage(page) {
5885
5957
  this.urlState.setParam(this.pageParam(), String(Math.max(1, Math.min(page, this.totalPages()))));
5886
5958
  }
@@ -6707,21 +6779,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
6707
6779
  * <neu-avatar name="PM" size="lg" color="blue" status="online" />
6708
6780
  */
6709
6781
  class NeuAvatarComponent {
6710
- /** URL de la imagen. Si falla la carga, muestra las iniciales. */
6782
+ /** URL de la imagen. Si falla la carga, muestra las iniciales. / Image URL. If loading fails, shows the initials. */
6711
6783
  src = input('', ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
6712
- /** Texto alternativo de la imagen. */
6784
+ /** Texto alternativo de la imagen. / Image alternative text. */
6713
6785
  alt = input('', ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
6714
- /** Nombre completo — se usan las iniciales como fallback. */
6786
+ /** Nombre completo — se usan las iniciales como fallback. / Full name — initials are used as fallback. */
6715
6787
  name = input('', ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
6716
- /** Tamaño: xs (24) | sm (32) | md (40) | lg (48) | xl (64). Por defecto 'md'. */
6788
+ /** Tamaño: xs (24) | sm (32) | md (40) | lg (48) | xl (64). Por defecto 'md'. / Size: xs (24) | sm (32) | md (40) | lg (48) | xl (64). Default 'md'. */
6717
6789
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6718
- /** Forma: 'circle' (default) o 'square'. */
6790
+ /** Forma: 'circle' (default) o 'square'. / Shape: 'circle' (default) or 'square'. */
6719
6791
  shape = input('circle', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
6720
- /** Color de fondo para iniciales. */
6792
+ /** Color de fondo para iniciales. / Background color for initials. */
6721
6793
  color = input('blue', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
6722
- /** Indicador de presencia. */
6794
+ /** Indicador de presencia. / Presence indicator. */
6723
6795
  status = input('', ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
6724
- /** @internal Imagen fallida */
6796
+ /** @internal Imagen fallida / Failed image */
6725
6797
  imgError = signal(false, ...(ngDevMode ? [{ debugName: "imgError" }] : /* istanbul ignore next */ []));
6726
6798
  initials = computed(() => {
6727
6799
  const n = this.name().trim();
@@ -6800,21 +6872,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
6800
6872
  /**
6801
6873
  * NeuralUI Badge Component
6802
6874
  *
6803
- * Etiqueta de estado compacta y semántica.
6875
+ * Etiqueta de estado compacta y semántica. / Compact and semantic status label.
6804
6876
  *
6805
6877
  * Uso: <neu-badge variant="success">Activo</neu-badge>
6806
6878
  * <neu-badge variant="danger" [dot]="true">Error</neu-badge>
6807
6879
  */
6808
6880
  class NeuBadgeComponent {
6809
- /** Variante semántica */
6881
+ /** Variante semántica / Semantic variant */
6810
6882
  variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
6811
- /** Tamaño */
6883
+ /** Tamaño / Size */
6812
6884
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6813
- /** Muestra un punto de color a la izquierda */
6885
+ /** Muestra un punto de color a la izquierda / Shows a colored dot on the left */
6814
6886
  dot = input(false, ...(ngDevMode ? [{ debugName: "dot" }] : /* istanbul ignore next */ []));
6815
- /** Estilo con solo borde (outline) sin relleno */
6887
+ /** Estilo con solo borde (outline) sin relleno / Border-only style (outline) without fill */
6816
6888
  outline = input(false, ...(ngDevMode ? [{ debugName: "outline" }] : /* istanbul ignore next */ []));
6817
- /** Estilo completamente redondeado (pill) */
6889
+ /** Estilo completamente redondeado (pill) / Fully rounded style (pill) */
6818
6890
  pill = input(true, ...(ngDevMode ? [{ debugName: "pill" }] : /* istanbul ignore next */ []));
6819
6891
  hostClasses = computed(() => ({
6820
6892
  'neu-badge': true,
@@ -6853,27 +6925,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
6853
6925
  * son inputs reactivos. El estado se computa automáticamente con computed().
6854
6926
  */
6855
6927
  class NeuButtonComponent {
6856
- /** Variante visual del botón */
6928
+ /** Variante visual del botón / Visual button variant */
6857
6929
  variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
6858
- /** Tamaño del botón */
6930
+ /** Tamaño del botón / Button size */
6859
6931
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
6860
- /** Deshabilita el botón y bloquea la interacción */
6932
+ /** Deshabilita el botón y bloquea la interacción / Disables the button and blocks interaction */
6861
6933
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
6862
- /** Muestra un spinner y deshabilita mientras se procesa */
6934
+ /** Muestra un spinner y deshabilita mientras se procesa / Shows a spinner and disables while processing */
6863
6935
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
6864
- /** Ocupa el 100% del ancho de su contenedor */
6936
+ /** Ocupa el 100% del ancho de su contenedor / Takes up 100% of its container width */
6865
6937
  fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : /* istanbul ignore next */ []));
6866
- /** Nombre del icono Lucide (ej: 'lucideSave', 'lucidePlus') */
6938
+ /** Nombre del icono Lucide (ej: 'lucideSave', 'lucidePlus') / Lucide icon name (e.g. 'lucideSave', 'lucidePlus') */
6867
6939
  icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
6868
6940
  /** Posición del icono respecto al texto */
6869
6941
  iconPosition = input('left', ...(ngDevMode ? [{ debugName: "iconPosition" }] : /* istanbul ignore next */ []));
6870
- /** Modo solo-icono: aplica padding cuadrado y oculta el ng-content */
6942
+ /** Modo solo-icono: aplica padding cuadrado y oculta el ng-content / Icon-only mode: applies square padding and hides ng-content */
6871
6943
  iconOnly = input(false, ...(ngDevMode ? [{ debugName: "iconOnly" }] : /* istanbul ignore next */ []));
6872
- /** Etiqueta accesible obligatoria cuando se usa iconOnly (WCAG 4.1.2) */
6944
+ /** Etiqueta accesible obligatoria cuando se usa iconOnly (WCAG 4.1.2) / Required accessible label when using iconOnly (WCAG 4.1.2) */
6873
6945
  ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
6874
- /** Emite el evento de click cuando el botón está activo */
6946
+ /** Emite el evento de click cuando el botón está activo / Emits the click event when the button is active */
6875
6947
  neuClick = output();
6876
- /** @internal — reenvía el click nativo al output Angular */
6948
+ /** @internal — reenvía el click nativo al output Angular / forwards the native click to the Angular output */
6877
6949
  _onHostClick(event) {
6878
6950
  if (!this.isDisabled()) {
6879
6951
  this.neuClick.emit(event);
@@ -6957,9 +7029,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
6957
7029
  `, styles: [".neu-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--neu-space-2);border:1px solid transparent;border-radius:var(--neu-radius);font-family:var(--neu-font-sans);font-weight:500;line-height:1;cursor:pointer;text-decoration:none;white-space:nowrap;-webkit-user-select:none;user-select:none;transition:background-color var(--neu-transition),border-color var(--neu-transition),color var(--neu-transition),box-shadow var(--neu-transition),opacity var(--neu-transition);outline:none}.neu-button:focus-visible{box-shadow:0 0 0 3px #6366f173}.neu-button--sm{padding:var(--neu-space-2) var(--neu-space-3);font-size:var(--neu-text-sm);border-radius:var(--neu-radius-sm)}.neu-button--md{padding:var(--neu-space-2) var(--neu-space-5);font-size:var(--neu-text-base)}@media(min-width:400px){.neu-button--md{padding:.625rem var(--neu-space-6)}}.neu-button--lg{padding:var(--neu-space-3) var(--neu-space-8);font-size:var(--neu-text-lg)}.neu-button--full-width{width:100%}.neu-button--primary{background:var(--neu-primary);color:var(--neu-primary-fg);border-color:var(--neu-primary)}.neu-button--primary:hover:not(:disabled):not(.neu-button--disabled){background:var(--neu-primary-dark);border-color:var(--neu-primary-dark);box-shadow:var(--neu-shadow-glow)}.neu-button--primary:active:not(:disabled){background:var(--neu-primary-dark);transform:translateY(1px)}.neu-button--secondary{background:var(--neu-secondary);color:var(--neu-secondary-fg);border-color:var(--neu-secondary)}.neu-button--secondary:hover:not(:disabled):not(.neu-button--disabled){background:var(--neu-secondary-dark);border-color:var(--neu-secondary-dark)}.neu-button--outline{background:transparent;color:var(--neu-primary-light);border-color:var(--neu-primary)}.neu-button--outline:hover:not(:disabled):not(.neu-button--disabled){background:#6366f11a;border-color:var(--neu-primary-light)}.neu-button--ghost{background:transparent;color:var(--neu-text-muted);border-color:transparent}.neu-button--ghost:hover:not(:disabled):not(.neu-button--disabled){background:var(--neu-surface-2);color:var(--neu-text)}.neu-button--danger{background:var(--neu-error);color:#fff;border-color:var(--neu-error)}.neu-button--danger:hover:not(:disabled):not(.neu-button--disabled){background:#dc2626;border-color:#dc2626}.neu-button--disabled,.neu-button:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.neu-button--loading{cursor:wait;pointer-events:none}.neu-button--icon-only.neu-button--sm{width:30px;height:30px;padding:0}.neu-button--icon-only.neu-button--md{width:38px;height:38px;padding:0}.neu-button--icon-only.neu-button--lg{width:46px;height:46px;padding:0}.neu-button__spinner{display:inline-flex;flex-shrink:0;width:1em;height:1em}.neu-button__spinner svg{width:100%;height:100%;animation:neu-spin .8s linear infinite}@keyframes neu-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
6958
7030
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], iconOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconOnly", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], neuClick: [{ type: i0.Output, args: ["neuClick"] }] } });
6959
7031
 
6960
- /** Paleta por defecto Neural-Blue */
7032
+ /** Paleta por defecto Neural-Blue / Default Neural-Blue palette */
6961
7033
  const DEFAULT_COLORS = ['#007aff', '#5856d6', '#34c759', '#ff9f0a', '#ff3b30', '#64748b'];
6962
- /** Calcula la línea acumulada porcentual para un diagrama de Pareto. */
7034
+ /** Calcula la línea acumulada porcentual para un diagrama de Pareto. / Calculates the cumulative percentage line for a Pareto chart. */
6963
7035
  function computeParetoCumulative(data) {
6964
7036
  const total = data.reduce((s, v) => s + Math.abs(v), 0);
6965
7037
  if (total === 0)
@@ -6985,23 +7057,23 @@ function computeParetoCumulative(data) {
6985
7057
  * />
6986
7058
  */
6987
7059
  class NeuChartComponent {
6988
- /** Tipo de gráfica. */
7060
+ /** Tipo de gráfica. / Chart type. */
6989
7061
  type = input('line', ...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
6990
- /** Series para gráficas de ejes (line, area, bar, pareto…). */
7062
+ /** Series para gráficas de ejes (line, area, bar, pareto…). / Series for axis-based charts (line, area, bar, pareto…). */
6991
7063
  series = input([], ...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
6992
- /** Series para gráficas sin ejes (donut, pie). */
7064
+ /** Series para gráficas sin ejes (donut, pie). / Series for non-axis charts (donut, pie). */
6993
7065
  pieSeries = input([], ...(ngDevMode ? [{ debugName: "pieSeries" }] : /* istanbul ignore next */ []));
6994
- /** Etiquetas del eje X. */
7066
+ /** Etiquetas del eje X. / X-axis labels. */
6995
7067
  categories = input([], ...(ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []));
6996
- /** Etiquetas para donut/pie. */
7068
+ /** Etiquetas para donut/pie. / Labels for donut/pie. */
6997
7069
  labels = input([], ...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
6998
- /** Altura en px. */
7070
+ /** Altura en px. / Height in px. */
6999
7071
  height = input(280, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
7000
- /** Colores custom. Si no se proveen, usa la paleta Neural-Blue. */
7072
+ /** Colores custom. Si no se proveen, usa la paleta Neural-Blue. / Custom colors. If not provided, uses the Neural-Blue palette. */
7001
7073
  colors = input([], ...(ngDevMode ? [{ debugName: "colors" }] : /* istanbul ignore next */ []));
7002
- /** Muestra/oculta las etiquetas de datos. */
7074
+ /** Muestra/oculta las etiquetas de datos. / Shows/hides data labels. */
7003
7075
  showDataLabels = input(false, ...(ngDevMode ? [{ debugName: "showDataLabels" }] : /* istanbul ignore next */ []));
7004
- /** Título de la gráfica. */
7076
+ /** Título de la gráfica. / Chart title. */
7005
7077
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
7006
7078
  // --------------------------------------------------
7007
7079
  // Helpers privados
@@ -7210,21 +7282,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7210
7282
  * <neu-chip [selected]="true" (selectedChange)="toggle()">TypeScript</neu-chip>
7211
7283
  */
7212
7284
  class NeuChipComponent {
7213
- /** Variante de color */
7285
+ /** Variante de color / Color variant */
7214
7286
  variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
7215
- /** Tamaño */
7287
+ /** Tamaño / Size */
7216
7288
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
7217
- /** Estado seleccionado */
7289
+ /** Estado seleccionado / Selected state */
7218
7290
  selected = input(false, ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
7219
- /** Muestra botón de cierre */
7291
+ /** Muestra botón de cierre / Shows close button */
7220
7292
  removable = input(false, ...(ngDevMode ? [{ debugName: "removable" }] : /* istanbul ignore next */ []));
7221
- /** Deshabilitado */
7293
+ /** Deshabilitado / Disabled */
7222
7294
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
7223
- /** Aria-label del botón de eliminar */
7295
+ /** Aria-label del botón de eliminar / Aria-label for the delete button */
7224
7296
  removeAriaLabel = input('Eliminar', ...(ngDevMode ? [{ debugName: "removeAriaLabel" }] : /* istanbul ignore next */ []));
7225
- /** Emite al hacer clic o pulsar espacio/enter */
7297
+ /** Emite al hacer clic o pulsar espacio/enter / Emits on click or space/enter press */
7226
7298
  selectedChange = output();
7227
- /** Emite al pulsar el botón de cierre */
7299
+ /** Emite al pulsar el botón de cierre / Emits when the close button is pressed */
7228
7300
  removed = output();
7229
7301
  hostClasses = computed(() => ({
7230
7302
  'neu-chip': true,
@@ -7324,17 +7396,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7324
7396
  */
7325
7397
  class NeuCodeBlockComponent {
7326
7398
  doc = inject(DOCUMENT);
7327
- /** Código fuente a mostrar */
7399
+ /** Código fuente a mostrar / Source code to display */
7328
7400
  code = input('', ...(ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []));
7329
- /** Nombre del lenguaje (decorativo) */
7401
+ /** Nombre del lenguaje (decorativo) / Language name (decorative) */
7330
7402
  lang = input('TypeScript', ...(ngDevMode ? [{ debugName: "lang" }] : /* istanbul ignore next */ []));
7331
- /** Texto del botón cuando no se ha copiado */
7403
+ /** Texto del botón cuando no se ha copiado / Button text when not yet copied */
7332
7404
  copyLabel = input('Copiar', ...(ngDevMode ? [{ debugName: "copyLabel" }] : /* istanbul ignore next */ []));
7333
- /** Texto del botón tras copiar */
7405
+ /** Texto del botón tras copiar / Button text after copying */
7334
7406
  copiedLabel = input('Copiado', ...(ngDevMode ? [{ debugName: "copiedLabel" }] : /* istanbul ignore next */ []));
7335
- /** Aria-label del botón copiar */
7407
+ /** Aria-label del botón copiar / Aria-label for the copy button */
7336
7408
  copyAriaLabel = input('Copiar código', ...(ngDevMode ? [{ debugName: "copyAriaLabel" }] : /* istanbul ignore next */ []));
7337
- /** Aria-label del botón tras copiar */
7409
+ /** Aria-label del botón tras copiar / Aria-label for the button after copying */
7338
7410
  copiedAriaLabel = input('Código copiado', ...(ngDevMode ? [{ debugName: "copiedAriaLabel" }] : /* istanbul ignore next */ []));
7339
7411
  copied = signal(false, ...(ngDevMode ? [{ debugName: "copied" }] : /* istanbul ignore next */ []));
7340
7412
  _copyTimer;
@@ -7481,17 +7553,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7481
7553
  * />
7482
7554
  */
7483
7555
  class NeuEmptyStateComponent {
7484
- /** Nombre del icono Lucide registrado con provideIcons(). */
7556
+ /** Nombre del icono Lucide registrado con provideIcons(). / Lucide icon name registered with provideIcons(). */
7485
7557
  icon = input('lucideInbox', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
7486
- /** Tamaño del icono. Por defecto 3rem. */
7558
+ /** Tamaño del icono. Por defecto 3rem. / Icon size. Default 3rem. */
7487
7559
  iconSize = input('3rem', ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
7488
- /** Título principal del estado vacío. */
7560
+ /** Título principal del estado vacío. / Main title of the empty state. */
7489
7561
  title = input('No hay nada aquí', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
7490
- /** Descripción secundaria opcional. */
7562
+ /** Descripción secundaria opcional. / Optional secondary description. */
7491
7563
  description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
7492
- /** Texto del botón de acción. Si está vacío, no se muestra el botón. */
7564
+ /** Texto del botón de acción. Si está vacío, no se muestra el botón. / Action button text. If empty, the button is not shown. */
7493
7565
  actionLabel = input('', ...(ngDevMode ? [{ debugName: "actionLabel" }] : /* istanbul ignore next */ []));
7494
- /** Emite cuando el usuario hace clic en el botón de acción. */
7566
+ /** Emite cuando el usuario hace clic en el botón de acción. / Emits when the user clicks the action button. */
7495
7567
  action = output();
7496
7568
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuEmptyStateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7497
7569
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuEmptyStateComponent, isStandalone: true, selector: "neu-empty-state", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, iconSize: { classPropertyName: "iconSize", publicName: "iconSize", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, actionLabel: { classPropertyName: "actionLabel", publicName: "actionLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { action: "action" }, host: { classAttribute: "neu-empty-state" }, ngImport: i0, template: `
@@ -7553,17 +7625,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7553
7625
  * <neu-progress-bar [indeterminate]="true" />
7554
7626
  */
7555
7627
  class NeuProgressBarComponent {
7556
- /** Valor de 0 a 100 */
7628
+ /** Valor de 0 a 100 / Value from 0 to 100 */
7557
7629
  value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
7558
- /** Variante de color */
7630
+ /** Variante de color / Color variant */
7559
7631
  variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
7560
- /** Etiqueta descriptiva sobre la barra */
7632
+ /** Etiqueta descriptiva sobre la barra / Descriptive label above the bar */
7561
7633
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
7562
- /** Muestra el % a la derecha */
7634
+ /** Muestra el % a la derecha / Shows the % on the right */
7563
7635
  showValue = input(false, ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
7564
- /** Modo indeterminado (animación continua) */
7636
+ /** Modo indeterminado (animación continua) / Indeterminate mode (continuous animation) */
7565
7637
  indeterminate = input(false, ...(ngDevMode ? [{ debugName: "indeterminate" }] : /* istanbul ignore next */ []));
7566
- /** Altura de la barra */
7638
+ /** Altura de la barra / Bar height */
7567
7639
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
7568
7640
  clampedValue = computed(() => Math.min(100, Math.max(0, this.value())), ...(ngDevMode ? [{ debugName: "clampedValue" }] : /* istanbul ignore next */ []));
7569
7641
  hostClasses = computed(() => [`neu-progress--${this.variant()}`, `neu-progress--${this.size()}`].join(' '), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
@@ -7649,13 +7721,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7649
7721
  */
7650
7722
  class NeuRatingComponent {
7651
7723
  Math = Math;
7652
- /** Valor actual (1 a stars) */
7724
+ /** Valor actual (1 a stars) / Current value (1 to stars) */
7653
7725
  value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
7654
- /** Número de estrellas */
7726
+ /** Número de estrellas / Number of stars */
7655
7727
  stars = input(5, ...(ngDevMode ? [{ debugName: "stars" }] : /* istanbul ignore next */ []));
7656
- /** Modo solo lectura */
7728
+ /** Modo solo lectura / Read-only mode */
7657
7729
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
7658
- /** Emite el nuevo valor al seleccionar */
7730
+ /** Emite el nuevo valor al seleccionar / Emits the new value on selection */
7659
7731
  valueChange = output();
7660
7732
  hovered = signal(null, ...(ngDevMode ? [{ debugName: "hovered" }] : /* istanbul ignore next */ []));
7661
7733
  starsArray = computed(() => Array.from({ length: this.stars() }, (_, i) => i + 1), ...(ngDevMode ? [{ debugName: "starsArray" }] : /* istanbul ignore next */ []));
@@ -7826,17 +7898,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7826
7898
  * <neu-spinner color="#ff6b35" strokeWidth="6" />
7827
7899
  */
7828
7900
  class NeuSpinnerComponent {
7829
- /** Variante de color semántica */
7901
+ /** Variante de color semántica / Semantic color variant */
7830
7902
  severity = input('primary', ...(ngDevMode ? [{ debugName: "severity" }] : /* istanbul ignore next */ []));
7831
- /** Color CSS directo — sobreescribe severity */
7903
+ /** Color CSS directo — sobreescribe severity / Direct CSS color — overrides severity */
7832
7904
  color = input('', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
7833
- /** Grosor del trazo SVG (unidades SVG) */
7905
+ /** Grosor del trazo SVG (unidades SVG) / SVG stroke width (SVG units) */
7834
7906
  strokeWidth = input('4', ...(ngDevMode ? [{ debugName: "strokeWidth" }] : /* istanbul ignore next */ []));
7835
- /** Tamaño del spinner (CSS: '40px', '2rem', etc.) */
7907
+ /** Tamaño del spinner (CSS: '40px', '2rem', etc.) / Spinner size (CSS: '40px', '2rem', etc.) */
7836
7908
  size = input('40px', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
7837
- /** Duración de la animación de rotación */
7909
+ /** Duración de la animación de rotación / Rotation animation duration */
7838
7910
  animationDuration = input('1s', ...(ngDevMode ? [{ debugName: "animationDuration" }] : /* istanbul ignore next */ []));
7839
- /** Texto accesible para lectores de pantalla */
7911
+ /** Texto accesible para lectores de pantalla / Accessible text for screen readers */
7840
7912
  ariaLabel = input('Cargando...', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
7841
7913
  _severityColor = computed(() => {
7842
7914
  const map = {
@@ -7917,7 +7989,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7917
7989
  /**
7918
7990
  * NeuralUI SplitButton Component
7919
7991
  *
7920
- * Botón principal con un dropdown de acciones adicionales.
7992
+ * Botón principal con un dropdown de acciones adicionales. / Primary button with a dropdown of additional actions.
7921
7993
  *
7922
7994
  * Uso:
7923
7995
  * <neu-split-button
@@ -7929,25 +8001,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
7929
8001
  */
7930
8002
  class NeuSplitButtonComponent {
7931
8003
  el = inject(ElementRef);
7932
- /** Texto del botón principal */
8004
+ /** Texto del botón principal / Primary button text */
7933
8005
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
7934
- /** Variante visual */
8006
+ /** Variante visual / Visual variant */
7935
8007
  variant = input('primary', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
7936
- /** Tamaño */
8008
+ /** Tamaño / Size */
7937
8009
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
7938
- /** Deshabilita todo el componente */
8010
+ /** Deshabilita todo el componente / Disables the entire component */
7939
8011
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
7940
- /** Muestra spinner en el botón principal */
8012
+ /** Muestra spinner en el botón principal / Shows spinner on the primary button */
7941
8013
  loading = input(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
7942
- /** Acciones del dropdown */
8014
+ /** Acciones del dropdown / Dropdown actions */
7943
8015
  actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
7944
- /** Aria-label del botón de desplegable */
8016
+ /** Aria-label del botón de desplegable / Aria-label for the dropdown button */
7945
8017
  moreActionsAriaLabel = input('Más opciones', ...(ngDevMode ? [{ debugName: "moreActionsAriaLabel" }] : /* istanbul ignore next */ []));
7946
- /** Aria-label del menú desplegable */
8018
+ /** Aria-label del menú desplegable / Aria-label for the dropdown menu */
7947
8019
  actionsAriaLabel = input('Acciones', ...(ngDevMode ? [{ debugName: "actionsAriaLabel" }] : /* istanbul ignore next */ []));
7948
- /** Emite al hacer click en el botón principal */
8020
+ /** Emite al hacer click en el botón principal / Emits on primary button click */
7949
8021
  primaryClick = output();
7950
- /** Emite al seleccionar una acción del dropdown */
8022
+ /** Emite al seleccionar una acción del dropdown / Emits when a dropdown action is selected */
7951
8023
  actionClick = output();
7952
8024
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
7953
8025
  isDisabled = computed(() => this.disabled() || this.loading(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
@@ -8171,21 +8243,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
8171
8243
  * />
8172
8244
  */
8173
8245
  class NeuStatsCardComponent {
8174
- /** Título o etiqueta de la métrica. */
8246
+ /** Título o etiqueta de la métrica. / Metric title or label. */
8175
8247
  title = input('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
8176
- /** Valor principal formateado (p.ej. "$12,450" o "98.2%"). */
8248
+ /** Valor principal formateado (p.ej. "$12,450" o "98.2%"). / Main formatted value (e.g. "$12,450" or "98.2%"). */
8177
8249
  value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
8178
- /** Cambio porcentual o absoluto (p.ej. "+12.5%" o "-3"). */
8250
+ /** Cambio porcentual o absoluto (p.ej. "+12.5%" o "-3"). / Percentage or absolute change (e.g. "+12.5%" or "-3"). */
8179
8251
  change = input('', ...(ngDevMode ? [{ debugName: "change" }] : /* istanbul ignore next */ []));
8180
- /** Dirección del cambio. Afecta el color del change. */
8252
+ /** Dirección del cambio. Afecta el color del change. / Change direction. Affects the change color. */
8181
8253
  trend = input('neutral', ...(ngDevMode ? [{ debugName: "trend" }] : /* istanbul ignore next */ []));
8182
- /** Texto auxiliar bajo el cambio (p.ej. "vs. mes anterior"). */
8254
+ /** Texto auxiliar bajo el cambio (p.ej. "vs. mes anterior"). / Auxiliary text below the change (e.g. "vs. previous month"). */
8183
8255
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
8184
- /** Nombre del icono Lucide para el encabezado. */
8256
+ /** Nombre del icono Lucide para el encabezado. / Lucide icon name for the header. */
8185
8257
  icon = input('', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
8186
- /** Array de valores numéricos para la sparkline. Mín. 2 puntos. */
8258
+ /** Array de valores numéricos para la sparkline. Mín. 2 puntos. / Array of numeric values for the sparkline. Min. 2 points. */
8187
8259
  sparkData = input([], ...(ngDevMode ? [{ debugName: "sparkData" }] : /* istanbul ignore next */ []));
8188
- /** @internal Genera los puntos SVG de la sparkline */
8260
+ /** @internal Genera los puntos SVG de la sparkline / Generates the SVG sparkline points */
8189
8261
  sparkPoints = computed(() => {
8190
8262
  const data = this.sparkData();
8191
8263
  if (data.length < 2)
@@ -8313,14 +8385,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
8313
8385
  /**
8314
8386
  * NeuralUI Timeline Component
8315
8387
  *
8316
- * Lista vertical de eventos cronológicos con línea conectora.
8388
+ * Lista vertical de eventos cronológicos con línea conectora. / Vertical list of chronological events with a connector line.
8317
8389
  *
8318
8390
  * Uso:
8319
8391
  * <neu-timeline [items]="events" />
8320
8392
  * <neu-timeline [items]="events" align="right" />
8321
8393
  */
8322
8394
  class NeuTimelineComponent {
8323
- /** Eventos a mostrar */
8395
+ /** Eventos a mostrar / Events to display */
8324
8396
  items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
8325
8397
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NeuTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8326
8398
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NeuTimelineComponent, isStandalone: true, selector: "neu-timeline", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
@@ -8418,7 +8490,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
8418
8490
  `, styles: [".neu-timeline{list-style:none;margin:0;padding:0;font-family:var(--neu-font-sans)}.neu-timeline__item{display:flex;gap:var(--neu-space-4);min-height:56px}.neu-timeline__axis{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:24px}.neu-timeline__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0;border:2.5px solid;background:var(--neu-surface)}.neu-timeline__dot--default{border-color:var(--neu-border);color:var(--neu-text-disabled);background:var(--neu-surface-2)}.neu-timeline__dot--success{border-color:var(--neu-success);color:var(--neu-success)}.neu-timeline__dot--warning{border-color:var(--neu-warning);color:var(--neu-warning)}.neu-timeline__dot--danger{border-color:var(--neu-error);color:var(--neu-error)}.neu-timeline__dot--info{border-color:var(--neu-primary);color:var(--neu-primary)}.neu-timeline__dot-icon{width:12px;height:12px}.neu-timeline__line{width:2px;flex:1;background:var(--neu-border);margin:4px 0;min-height:16px}.neu-timeline__content{flex:1;padding-bottom:var(--neu-space-5);padding-top:2px}.neu-timeline__header{display:flex;align-items:baseline;justify-content:space-between;gap:var(--neu-space-3);margin-bottom:4px}.neu-timeline__title{font-size:var(--neu-text-sm);font-weight:600;color:var(--neu-text)}.neu-timeline__time{font-size:var(--neu-text-xs);color:var(--neu-text-disabled);white-space:nowrap;flex-shrink:0}.neu-timeline__desc{font-size:var(--neu-text-sm);color:var(--neu-text-muted);line-height:1.6;margin:0}\n"] }]
8419
8491
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }] } });
8420
8492
 
8421
- /** Mapa de iconos Lucide por tipo de toast */
8493
+ /** Mapa de iconos Lucide por tipo de toast / Map of Lucide icons by toast type */
8422
8494
  const TOAST_ICONS = {
8423
8495
  success: 'lucideCheckCircle',
8424
8496
  error: 'lucideXCircle',