npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sapenlinea-components

v0.3.58

Published

Esta librería incluye una colección de componentes reutilizables para formularios, tablas y filtros. A continuación se documenta **qué hace cada componente** y **cómo se utiliza**.

Readme

Componentes de la librería sapenlinea-components

Esta librería incluye una colección de componentes reutilizables para formularios, tablas y filtros. A continuación se documenta qué hace cada componente y cómo se utiliza.

Nota: todos los componentes son standalone de Angular, por lo que se importan directamente en el imports del componente donde se usen.

1. lib-date-time-filter (DateTimeFilter)

Qué hace
Componente para gestionar filtros de fecha y fecha/hora a partir de una lista de filtros configurables. Implementa ControlValueAccessor para integrarse con formularios reactivos.

Selector: lib-date-time-filter

Inputs:

  • filters: FilterItem[] (requerido)
    • Cada FilterItem define un filtro disponible:
    • label: string – Texto visible en el chip/botón.
    • value: string – Identificador interno del filtro.
    • type: 'date' | 'datetime' – Tipo de filtro.
    • placeholder?: string – Placeholder específico.
    • minDate?: Date / maxDate?: Date – Rango permitido.

Outputs:

  • dateSelected: EventEmitter<DateFilterSelection> – Emite { filter: string; value: Date } con el filtro activo y la fecha seleccionada.
  • dateChange: EventEmitter<Date | null> – Emite la fecha seleccionada al cambiar (o null si se limpia).

Uso con formularios reactivos:

<lib-date-time-filter
  [filters]="dateFilters"
  (dateSelected)="onDateSelected($event)"
  (dateChange)="onDateChange($event)"
  formControlName="fechaFiltro"
></lib-date-time-filter>
const form = this.fb.group({
  fechaFiltro: [null],
});

dateFilters: FilterItem[] = [
  { label: 'Fecha inicio', value: 'startDate', type: 'date', placeholder: 'Seleccionar fecha inicio' },
  { label: 'Fecha fin', value: 'endDate', type: 'date', placeholder: 'Seleccionar fecha fin' },
];

2. lib-date-time-picker (DateTimePicker)

Qué hace
Componente de selector de fecha o fecha/hora independiente (sin lista de filtros). Implementa ControlValueAccessor.

Selector: lib-date-time-picker

Inputs:

  • mode: 'date' | 'datetime' = 'date' – Modo fecha sola o fecha + hora.
  • placeholder: string = 'Seleccionar fecha' – Texto cuando no hay valor.
  • minDate: Date | null = null – Fecha mínima.
  • maxDate: Date | null = null – Fecha máxima.

Outputs:

  • dateChange: EventEmitter<Date | null> – Emite la fecha seleccionada.

Ejemplo de uso:

<lib-date-time-picker
  mode="datetime"
  [minDate]="minDate"
  [maxDate]="maxDate"
  (dateChange)="onDateChange($event)"
  formControlName="fechaEvento"
></lib-date-time-picker>

3. lib-dialog-alert-component (DialogAlertComponent)

Qué hace
Componente de diálogo/modal de alerta/confirmación, con opción de exigir una razón (select + textarea) antes de confirmar.

Selector: lib-dialog-alert-component

Inputs:

  • title: string = 'Mensaje' – Título del diálogo.
  • message: string – Mensaje principal.
  • type: 'warning' | 'error' | 'info' | 'success' = 'info' – Tipo visual de alerta.
  • action?: string – Acción asociada (ej. 'deactivate', 'delete', 'anulate', 'sancionar', 'active').
  • showReason: boolean = false – Forzar mostrar campo de razón.
  • confirm: boolean = false – Indica si muestra botón de confirmación principal.
  • confirmLabel: string = 'Aceptar' – Texto del botón de confirmación.
  • reasonOptions: { label: string; value: any }[] = [] – Opciones para el campo "Razón" cuando se requiere.

Outputs:

  • close: EventEmitter<boolean> – Emite true al confirmar y false al cancelar.
  • confirmReason: EventEmitter<string | undefined> – Emite la razón seleccionada (o undefined).

Ejemplo de uso:

<lib-dialog-alert-component
  [title]="'Desactivar usuario'"
  [message]="'¿Está seguro que desea desactivar este usuario?'"
  type="warning"
  action="deactivate"
  [showReason]="true"
  [reasonOptions]="reasonOptions"
  (close)="onClose($event)"
  (confirmReason)="onConfirmReason($event)"
></lib-dialog-alert-component>

4. lib-dynamic-form-fields (DynamicFormFields)

Qué hace Componente que renderiza dinámicamente campos de formulario a partir de una configuración (sections y fields), soportando textos, números, selects, checkboxes, radios, toggles, textarea, fechas y más. Maneja lógicas de copiado automático entre campos.

Selector: lib-dynamic-form-fields

Inputs:

  • form: FormGroup (requerido) – Formulario reactivo que contiene los controles.
  • sections: SectionConfig[] = [] – Secciones y campos del formulario.
  • compact: boolean = false – Permite estilos compactos.

Tipos principales:

export interface Option {
  value: string | number | boolean;
  label: string;
  subtitle?: string; // Texto secundario opcional bajo el label (solo checkbox)
}

export interface FieldConfig {
  key: string;
  label?: string;
  type: 'text' | 'email' | 'number' | 'date' | 'datetime-local' | 'select'
      | 'radio' | 'checkbox' | 'textarea' | 'disabled' | 'password'
      | 'time' | 'file' | 'toggle';
  placeholder?: string;
  required?: boolean;
  options?: Option[];
  col?: number;          // Columnas en el grid de 12 (default 6). No aplica a toggle.
  disabled?: boolean;
  readonly?: boolean;
  matchWith?: string;
  copyFrom?: string;
  pattern?: string;
  patternType?: 'numbers' | 'phone' | 'custom' | 'text' | 'username' | 'alphanumeric';
  minDate?: Date;
  maxDate?: Date;
  variant?: 'cards';       // Variante visual del checkbox
  uppercase?: boolean;     // Texto de opciones en mayúsculas. Default: true (solo checkbox)
  radioGroup?: string;     // Ver sección "Checkbox — comportamientos de selección"
  atLeastOneGroup?: string;
}

export interface SectionConfig {
  title?: string;
  description?: string;
  fields: FieldConfig[];
}

Comportamiento del layout:

| Tipo | Comportamiento en el grid | |---|---| | text, number, email... | Respeta col (default 6 de 12) | | radio, checkbox | Respeta col (default 6 de 12) | | toggle | Siempre ocupa la fila completa. Hasta 4 toggles consecutivos comparten la misma fila (cada uno ocupa 1/4 del ancho). Nunca comparte fila con otros tipos. |

Checkbox — subtítulo y mayúsculas:

{
  key: 'acepta',
  type: 'checkbox',
  uppercase: false,        // opcional, default true
  options: [
    {
      label: 'Evidencia fotográfica',
      value: 'foto',
      subtitle: 'Adjunta imágenes del incidente'  // opcional
    }
  ]
}

Checkbox — comportamientos de selección entre fields

Cuando cada FieldConfig de tipo checkbox tiene una sola opción, se pueden agrupar fields con comportamiento especial usando radioGroup o atLeastOneGroup.

Ambas propiedades buscan a través de todas las secciones pasadas al componente, no solo la sección actual.

radioGroup — exclusión mutua: al marcar un field se desmarcan todos los demás del mismo grupo (comportamiento radio).

// FormGroup: cada key es un FormArray de un solo control
form = new FormGroup({
  evidencia: new FormArray([new FormControl(true)]),
  incidente: new FormArray([new FormControl(false)]),
  accidente: new FormArray([new FormControl(false)]),
});

sections: SectionConfig[] = [{
  title: 'Tipo de reporte',
  fields: [
    { key: 'evidencia', type: 'checkbox', variant: 'cards', radioGroup: 'tipoReporte', col: 4, options: [{ label: 'Evidencia pedagógica', value: 'evidencia' }] },
    { key: 'incidente', type: 'checkbox', variant: 'cards', radioGroup: 'tipoReporte', col: 4, options: [{ label: 'Incidente vial',       value: 'incidente' }] },
    { key: 'accidente', type: 'checkbox', variant: 'cards', radioGroup: 'tipoReporte', col: 4, options: [{ label: 'Accidente',            value: 'accidente' }] },
  ],
}];

atLeastOneGroup — mínimo uno activo: permite seleccionar varios, pero impide desmarcar el último activo del grupo.

form = new FormGroup({
  foto:      new FormArray([new FormControl(true)]),
  video:     new FormArray([new FormControl(false)]),
  documento: new FormArray([new FormControl(false)]),
});

sections: SectionConfig[] = [{
  title: 'Evidencias requeridas',
  fields: [
    { key: 'foto',      type: 'checkbox', variant: 'cards', atLeastOneGroup: 'evidencia', col: 4, options: [{ label: 'Foto',      value: 'foto' }] },
    { key: 'video',     type: 'checkbox', variant: 'cards', atLeastOneGroup: 'evidencia', col: 4, options: [{ label: 'Video',     value: 'video' }] },
    { key: 'documento', type: 'checkbox', variant: 'cards', atLeastOneGroup: 'evidencia', col: 4, options: [{ label: 'Documento', value: 'documento' }] },
  ],
}];

radioGroup y atLeastOneGroup son independientes entre sí. Se pueden usar en diferentes SectionConfig del mismo formulario sin interferencia.

Ejemplo de uso:

<lib-dynamic-form-fields
  [form]="form"
  [sections]="sections"
  [compact]="true"
></lib-dynamic-form-fields>

5. lib-input-text-filter (InputTextFilter)

Qué hace
Componente de filtro por texto con chips de filtros configurables (por ejemplo, buscar por nombre, documento, etc.). Implementa ControlValueAccessor.

Selector: lib-input-text-filter

Inputs:

  • filters: FilterItem[] (requerido) – Filtros disponibles de texto.
  • clearTrigger: number = 0 – Al incrementar este valor desde el padre se limpian todos los filtros.

Outputs:

  • filterSelected: EventEmitter<{ filter: string; value: string }> – Emite el filtro y el valor aplicado.
  • valueChange: EventEmitter<string | null> – Emite el valor actual del filtro de texto.

Ejemplo de uso:

<lib-input-text-filter
  [filters]="textFilters"
  [clearTrigger]="clearVersion"
  (filterSelected)="onTextFilter($event)"
  (valueChange)="onTextValueChange($event)"
></lib-input-text-filter>

6. lib-input-number-filter (InputNumberFilter)

Qué hace
Componente de filtro numérico con múltiples chips (ej. "monto mínimo", "monto máximo"). Implementa ControlValueAccessor.

Selector: lib-input-number-filter

Inputs:

  • filters: FilterItem[] (requerido) – Filtros numéricos.
  • clearTrigger: number = 0 – Limpia filtros al cambiar.

Outputs:

  • filterSelected: EventEmitter<{ filter: string; value: string }> – Filtro seleccionado y valor.
  • valueChange: EventEmitter<string | null> – Valor numérico aplicado.

Ejemplo de uso:

<lib-input-number-filter
  [filters]="numberFilters"
  (filterSelected)="onNumberFilter($event)"
></lib-input-number-filter>

7. lib-input-select-filter (InputSelectFilter)

Qué hace
Componente de filtro basado en select con chips. Permite seleccionar una opción por cada tipo de filtro configurado.

Selector: lib-input-select-filter

Inputs:

  • filters: FilterItem[] (requerido) – Deben incluir options con { label, value }.
  • clearTrigger: number = 0 – Limpia filtros.

Outputs:

  • filterSelected: EventEmitter<{ filter: string; value: string }> – Filtro e identificador de opción seleccionada.
  • valueChange: EventEmitter<string | null> – Valor del select actual.

Ejemplo de uso:

<lib-input-select-filter
  [filters]="statusFilters"
  (filterSelected)="onStatusFilter($event)"
></lib-input-select-filter>

8. lib-select-custom-search (SelectCustomSearch)

Qué hace
Componente de select con buscador y filtrado en tiempo real sobre las opciones. Implementa ControlValueAccessor.

Selector: lib-select-custom-search

Inputs:

  • options: { value: any; label: string }[] = [] – Opciones disponibles.
  • placeholder: string = 'Seleccionar opción' – Texto cuando no hay selección.

Outputs:

  • selectionChange: EventEmitter<Option | null> – Emite la opción seleccionada (o null).

Ejemplo de uso:

<lib-select-custom-search
  [options]="userOptions"
  (selectionChange)="onUserSelected($event)"
  formControlName="usuarioId"
></lib-select-custom-search>

9. lib-pagination (PaginationComponent)

Qué hace
Componente de paginación para tablas o listas, con opción de selector de tamaño de página.

Selector: lib-pagination

Inputs:

  • page: number = 1 – Página actual.
  • pageSize: number = 10 – Elementos por página (valor inicial).
  • totalItems: number = 0 – Total de elementos.
  • showPageSizeSelector: boolean = false – Muestra/oculta el selector de tamaño de página.
  • pageSizeOptions: number[] = [5, 10, 20, 50] – Opciones disponibles.

Outputs:

  • pageChange: EventEmitter<number> – Emite la nueva página seleccionada.
  • pageSizeChange: EventEmitter<number> – Emite el nuevo tamaño de página.

Ejemplo de uso:

<lib-pagination
  [page]="currentPage"
  [pageSize]="pageSize"
  [totalItems]="totalItems"
  [showPageSizeSelector]="true"
  [pageSizeOptions]="[10, 20, 50]"
  (pageChange)="onPageChange($event)"
  (pageSizeChange)="onPageSizeChange($event)"
></lib-pagination>

10. lib-table (Table)

Qué hace Componente de tabla dinámica con soporte de ordenamiento, acciones por fila, estados con tonos configurables y traducción de estados mediante enum.

Selector: lib-table

Inputs:

  • columns: TableColumn[] (requerido) – Definición de columnas.
  • data: TableRow[] (requerido) – Datos a mostrar.
  • actions: TableAction[] | ((row: TableRow) => TableAction[]) – Acciones por fila.
  • showActions: boolean = true – Muestra/oculta columna de acciones.
  • statusToneMap: StatusToneMap – Mapa de estado normalizado → tono visual (success, error, warning, info, neutral).
  • statusEnumMap: Record<string, string> – Traduce el valor crudo del estado (ej. 'ACTIVE') a la etiqueta que se muestra (ej. 'Activo'). La resolución del tono usa la etiqueta traducida.

Outputs:

  • optionSelected: EventEmitter<{ action: string; row: TableRow }> – Emite la acción seleccionada y la fila.

Uso con estados en inglés (enum):

// Enum que refleja los valores que devuelve el backend
export enum UserStatus {
  ACTIVE    = 'ACTIVE',
  INACTIVE  = 'INACTIVE',
  PENDING   = 'PENDING',
  CANCELLED = 'CANCELLED',
}

// Traducción enum → etiqueta visible
statusEnumMap: Record<string, string> = {
  [UserStatus.ACTIVE]:    'Activo',
  [UserStatus.INACTIVE]:  'Inactivo',
  [UserStatus.PENDING]:   'Pendiente',
  [UserStatus.CANCELLED]: 'Cancelado',
};

// Tono visual usando la etiqueta normalizada (minúsculas)
statusToneMap: StatusToneMap = {
  activo:    'success',
  inactivo:  'neutral',
  pendiente: 'warning',
  cancelado: 'error',
};
<lib-table
  [columns]="columns"
  [data]="rows"
  [actions]="rowActions"
  [statusToneMap]="statusToneMap"
  [statusEnumMap]="statusEnumMap"
  (optionSelected)="onTableAction($event)"
></lib-table>

11. lib-modal-form (ModalForm)

Qué hace
Componente de modal genérico de formulario multi-paso, que delega la navegación de pasos a lib-wizard-form.

Selector: lib-modal-form

Inputs:

  • title: string = 'Formulario' – Título del modal.
  • submitLabel: string = 'Guardar' – Texto del botón de guardar.
  • form: FormGroup – Formulario reactivo principal.
  • steps: ModalFormStep[] = [] – Pasos del formulario.
export interface ModalFormStep {
  key: string;          // Nombre del subgrupo dentro de form
  label: string;        // Texto visible del paso
  component: Type<any>; // Componente que se renderiza en ese paso
}

Outputs:

  • onSubmit: EventEmitter<any> – Emite el valor completo del formulario.
  • onCancel: EventEmitter<void> – Emite cuando se cancela el modal.

Ejemplo de uso:

<lib-modal-form
  [title]="'Registro de usuario'"
  [submitLabel]="'Guardar'"
  [form]="form"
  [steps]="steps"
  (onSubmit)="onSubmit($event)"
  (onCancel)="onCancel()"
></lib-modal-form>

12. lib-wizard-form (WizardForm)

Qué hace
Componente que orquesta la lógica de pasos de un formulario tipo wizard, validando el sub-formulario del paso actual y notificando si se puede continuar.

Selector: lib-wizard-form

Inputs:

  • form: FormGroup – Formulario principal que contiene subgrupos.
  • currentStep: number = 1 – Paso actual (1-based).
  • steps: ModalFormStep[] = [] – Definición de los pasos.

Outputs:

  • canContinue: EventEmitter<boolean> – Emite si el grupo del paso actual es válido.

Uso habitual (interno de lib-modal-form):
No suele consumirse directamente, pero puede utilizarse si se quiere un wizard sin modal.


13. lib-input (Input)

Qué hace
Campo de entrada reutilizable con modos search y select, usado para buscadores simples con dropdown de opciones.

Selector: lib-input

Inputs principales:

  • mode: 'search' | 'select' = 'search'
  • placeholder?: string
  • type: string = 'text'
  • options?: { code: string; name: string }[] (modo select)

Outputs principales:

  • valueChange: EventEmitter<string>
  • onSearch: EventEmitter<string>
  • onSelect: EventEmitter<string>

14. lib-dialog-confirmation (DialogConfirmation)

Qué hace
Modal ligero de confirmación con lista de ítems informativos y botón de aceptar.

Selector: lib-dialog-confirmation

Inputs principales:

  • title: string
  • confirm: boolean
  • confirmLabel: string
  • items: DialogItem[] – Lista de ítems con posibles hijos expandibles.

Outputs:

  • close: EventEmitter<boolean>true al confirmar, false al cerrar sin confirmar.

15. lib-not-found-modal (NotFoundModal)

Qué hace
Modal genérico para mostrar estados de “no hay resultados / no encontrado” con acción de cierre.

Selector: lib-not-found-modal

Outputs:

  • onClose: EventEmitter<void>

16. lib-loader (Loader)

Qué hace
Indicador de carga centrado para usar como overlay dentro de contenedores o modales.

Selector: lib-loader


17. lib-progress-bar y ProgressFormService

Qué hacen
lib-progress-bar muestra el avance de un flujo (por ejemplo, formularios multi-paso); ProgressFormService expone señales para currentPage y totalPages.

Selector: lib-progress-bar

Uso típico: inyectar ProgressFormService en componentes que actualizan el progreso.


18. lib-processing-overlay (ProcessingOverlay)

Qué hace
Overlay de pantalla completa o contenedor con spinner y texto (“Cargando…”) para procesos en curso.

Selector: lib-processing-overlay

Inputs:

  • loadingText: string = 'Cargando'

19. lib-info-group (InfoGroup)

Qué hace Muestra bloques de información clave (label + value) agrupados en dos columnas, útil para pantallas de detalle o resúmenes de entidad.

Selector: lib-info-group

El componente tiene tres modos de uso: info (grid de dos columnas), comparación (columnas independientes) y box (tarjeta de persona).

Inputs:

| Input | Tipo | Default | Descripción | |---|---|---|---| | title | string \| null | null | Título visible sobre el contenido | | titleAlign | 'center' \| 'left' \| 'right' | 'center' | Alineación del título | | items | InfoItem[] | [] | Modo info: items distribuidos en grid de 2 columnas | | itemsLeft | InfoItem[] | [] | Modo comparación: items de la columna izquierda | | itemsRight | InfoItem[] | [] | Modo comparación: items de la columna derecha | | titleLeft | string \| null | null | Encabezado de la columna izquierda (sin divider) | | titleRight | string \| null | null | Encabezado de la columna derecha (sin divider) | | showBox | boolean | false | Activa modo tarjeta de persona | | type | 'success' \| 'error' \| 'info' | 'info' | Color del modo showBox | | fullName | string \| null | null | Nombre completo (modo showBox) | | typeDocument | string \| null | null | Tipo de documento (modo showBox) | | document | string \| null | null | Número de documento (modo showBox) |

El modo comparación se activa automáticamente cuando se pasa itemsLeft o itemsRight. Si ninguno tiene valores, se usa el modo info (items).

Modo info — grid de dos columnas:

<lib-info-group
  title="Datos del usuario"
  [titleAlign]="'left'"
  [items]="infoItems"
/>
infoItems: InfoItem[] = [
  { label: 'Nombre',   value: 'Julian Pérez' },
  { label: 'Estado',   value: 'Activo' },
  { label: 'Email',    value: '[email protected]' },
  { label: 'Rol',      value: 'Administrador' },
];

Modo comparación — columnas independientes:

Útil para comparar datos actuales vs nuevos, o dos entidades distintas. Cada columna tiene sus propios items y título opcional.

<lib-info-group
  title="Comparación de datos"
  [itemsLeft]="datosActuales"
  [itemsRight]="datosNuevos"
  titleLeft="Datos actuales"
  titleRight="Datos nuevos"
/>
datosActuales: InfoItem[] = [
  { label: 'Nombre',    value: 'Julian Fernando' },
  { label: 'Apellido',  value: 'Pérez García' },
  { label: 'Documento', value: '1020304050' },
];

datosNuevos: InfoItem[] = [
  { label: 'Nombre',    value: 'Julián Andrés' },
  { label: 'Apellido',  value: 'Pérez Rodríguez' },
  { label: 'Documento', value: '9876543210' },
];

Modo box — tarjeta de persona:

<lib-info-group
  [showBox]="true"
  type="success"
  [fullName]="persona.nombre"
  [typeDocument]="persona.tipoDoc"
  [document]="persona.documento"
/>

20. lib-feature-card (FeatureCard)

Qué hace
Tarjeta compacta para resaltar una “feature” o métrica con icono, título y descripción/valor.

Selector: lib-feature-card

Inputs:

  • feature: Feature{ icon: string; title: string; description: string }

21. lib-side-card y lib-side-card-detail

Qué hacen
Tarjetas laterales para flujos con mapa o dashboards, mostrando secciones de información y acciones (sliders, botones de sección, estados).

Selectores: lib-side-card, lib-side-card-detail

Inputs principales:

  • sections: SideCardSection[]
  • statusValue: 1 | 2

Outputs típicos:

  • statusChange, tabChange, sectionButtonClick, etc. según el componente.

22. lib-devices-carousel (DevicesCarousel)

Qué hace
Carrusel horizontal de tarjetas de dispositivo con estado (batería, geocerca, conectividad).

Selector: lib-devices-carousel

Inputs:

  • devices: DeviceCard[]

Outputs:

  • btnClickIcon: EventEmitter<DeviceCard> – Al pulsar acción sobre un dispositivo.

23. lib-title-filters (TitleFilters)

Qué hace Encabezado de sección con título, botones de acción configurables y grupo de filtros (texto, número, select, fecha, hora).

Selector: lib-title-filters

buttonMode

| Valor | Descripción | |---|---| | 'toggle' | Botón "Filtros" que muestra/oculta el panel de filtros (default) | | 'action' | Botón "Ir al Mapa" — fijo, en producción, no modificar | | 'click' | Botón primario reutilizable con ícono y texto configurables |

Inputs:

  • title: string = 'Listado'
  • filtersConfig: TitleFilterConfig[]
  • buttonMode: 'toggle' | 'action' | 'click' = 'toggle'
  • clickButtonLabel: string = 'Acción' — texto del botón en modo click
  • clickButtonIcon: string = '' — clase CSS del ícono en modo click
  • alwaysShowFilters: boolean = false — muestra los filtros permanentemente sin necesidad de toggle
  • showSecondaryButton: boolean = false — muestra un botón secundario al final de la fila del título
  • secondaryButtonLabel: string = 'Exportar'
  • secondaryButtonIcon: string = ''
  • showButtonBack: boolean = false

Outputs:

  • filtersChange: Record<string, string | number | Date | null>
  • applyFilters: void
  • clearFilters: void
  • filterButtonClicked: void — emitido al hacer clic en el botón click o action
  • secondaryButtonClicked: void
  • clickButtonBack: void

Íconos disponibles (clase CSS, patrón mask-image):

| Clase | Descripción | |---|---| | icon-download | Descargar | | icon-upload | Cargar / subir | | icon-export | Exportar tabla |

Ejemplo — modo click con filtros permanentes y botón secundario:

<lib-title-filters
  title="Órdenes"
  buttonMode="click"
  clickButtonLabel="Nueva Orden"
  clickButtonIcon="icon-upload"
  [alwaysShowFilters]="true"
  [showSecondaryButton]="true"
  secondaryButtonLabel="Exportar"
  secondaryButtonIcon="icon-export"
  [filtersConfig]="filtersConfig"
  (filterButtonClicked)="onNuevaOrden()"
  (secondaryButtonClicked)="onExportar()"
  (filtersChange)="onFiltersChange($event)"
  (applyFilters)="onApply()"
/>

TitleFilterConfig:

export interface TitleFilterConfig {
  type: 'text' | 'number' | 'select' | 'date' | 'datetime' | 'time';
  filters: FilterItem[];
}

24. lib-notification-modal (NotificationModal)

Qué hace
Modal de notificación tipo “toast grande” centrado, para mensajes importantes con iconografía y botón de acción.

Selector: lib-notification-modal


25. lib-footer (Footer)

Qué hace
Footer reutilizable para modales o pantallas, con información de marca / texto legal.

Selector: lib-footer


26. lib-button-cards (ButtonCards)

Qué hace
Botón estilizado como tarjeta seleccionable, usado para opciones tipo “cards” (ej. selección de variante).

Selector: lib-button-cards

Inputs principales:

  • label: string
  • subtitle?: string
  • variant?: 'primary' | 'danger' | ...

Outputs:

  • selectedChange: EventEmitter<boolean>

27. lib-tabs (Tabs)

Qué hace Componente de pestañas horizontales. Puede usarse solo como barra de navegación (el padre maneja el contenido) o en modo automático, renderizando lib-card-content o lib-info-group por pestaña según la configuración.

Selector: lib-tabs

Inputs:

  • tabs: TabItem[]
  • activeTab: TabId | null
  • validateOnTabChange: boolean = false – Bloquea el cambio de tab si el formulario activo tiene campos inválidos.

Outputs:

  • tabChange: TabId
  • activeTabChange: TabId
  • tabValidationFailed: TabId – Emite el id del tab actual cuando la validación impide el cambio.

TabItem:

export interface TabItem {
  id: TabId;               // string | number
  label: string;
  disabled?: boolean;
  cards?: TabCardConfig[]; // si se define, el panel se renderiza automáticamente
}

TabCardConfig — todas las propiedades son opcionales excepto title:

export interface TabCardConfig {
  title: string;

  // --- Modo formulario (lib-card-content) ---
  isForm?: boolean;
  form?: FormGroup;
  sections?: SectionConfig[];
  variant?: 'default' | 'numeric';
  sectionNumber?: number | null;
  bgColor?: 'default' | 'light' | string;
  withSearch?: boolean;
  searchPlaceholder?: string;
  onSearch?: (value: string) => void;
  onSearchClear?: () => void;

  // --- Modo informativo (lib-info-group) ---
  // Si se define infoItems, se renderiza lib-info-group en lugar de lib-card-content
  infoItems?: InfoItem[];
  infoTitleAlign?: 'center' | 'left' | 'right'; // default 'center'
}

Modo formulario (comportamiento existente, sin cambios):

tabs: TabItem[] = [
  {
    id: 'datos',
    label: 'Datos',
    cards: [{ title: 'Información', isForm: true, form: this.form, sections: this.sections }]
  }
];

Modo informativo (nuevo — pantallas de detalle):

tabs: TabItem[] = [
  {
    id: 'detalle',
    label: 'Detalle',
    cards: [
      {
        title: 'Información General',
        infoItems: [
          { label: 'Nombre',  value: 'Julian Pérez' },
          { label: 'Estado',  value: 'Activo' },
          { label: 'Email',   value: '[email protected]' },
          { label: 'Rol',     value: 'Administrador' },
        ],
        infoTitleAlign: 'left',
      }
    ]
  }
];
<lib-tabs [tabs]="tabs" />

Los tres modos (barra sin cards, formulario, informativo) son totalmente compatibles y se pueden mezclar en el mismo componente.


28. lib-not-found-section (NotFoundSection)

Qué hace
Sección de “no hay datos” para usar dentro de vistas (en vez de modal), con botón opcional para crear/recargar.

Selector: lib-not-found-section

Inputs típicos:

  • buttonLabel?: string

Outputs:

  • openModal: EventEmitter<void>

29. lib-toast y ToastService

Qué hacen
Sistema de notificaciones tipo toast:

  • lib-toast: componente visual que muestra la cola de toasts.
  • ToastService: servicio para disparar toasts (success, error, info, etc.).

Uso típico:

  • Declarar <lib-toast></lib-toast> una sola vez (por ejemplo en AppComponent).
  • Inyectar ToastService donde se necesiten notificaciones.

30. lib-card-content (CardContent)

Qué hace Card contenedora de secciones de formulario o contenido libre (ng-content), con header configurable, barra de búsqueda integrada y color de fondo personalizable.

Selector: lib-card-content

Inputs:

| Input | Tipo | Default | Descripción | |---|---|---|---| | title | string | 'Título de sección' | Título del header | | variant | 'default' \| 'numeric' | 'default' | Estilo del header | | sectionNumber | number \| null | null | Número en ícono circular (variant='numeric') | | isForm | boolean | false | Renderiza lib-dynamic-form-fields internamente | | form | FormGroup | — | Formulario reactivo (requiere isForm=true) | | sections | SectionConfig[] | [] | Secciones del formulario | | bgColor | 'default' \| 'light' \| string | 'default' | Color de fondo (preset o valor CSS libre) | | withSearch | boolean | false | Muestra barra de búsqueda (ocupa 50% del ancho) | | searchPlaceholder | string | 'Buscar...' | Placeholder del input de búsqueda | | searchValue | string (model) | '' | Valor del input — soporta [(searchValue)] |

Outputs:

  • onSearch: string — emitido al presionar Enter o el botón buscar
  • onSearchClear: void — emitido al limpiar el input

Colores de fondo (bgColor):

import { CARD_BG } from 'sapenlinea-components';

// Presets disponibles
CARD_BG.default  // '#EBE8D6' (beige, default)
CARD_BG.light    // '#ededdf' (más claro)

// O cualquier valor CSS
bgColor = '#FFFFFF';
bgColor = 'rgb(235, 232, 214)';

El componente sincroniza automáticamente background y --sl-form-surface para que los labels flotantes del formulario siempre coincidan con el fondo.

Ejemplo — formulario con búsqueda y color custom:

<lib-card-content
  title="Usuarios"
  variant="numeric"
  [sectionNumber]="1"
  [isForm]="true"
  [form]="userForm"
  [sections]="userSections"
  bgColor="light"
  [withSearch]="true"
  searchPlaceholder="Buscar usuario..."
  [(searchValue)]="searchText"
  (onSearch)="buscar($event)"
  (onSearchClear)="limpiar()"
/>

Ejemplo — contenido libre:

<lib-card-content title="Resumen" bgColor="#f5f5f0">
  <p>Cualquier contenido aquí</p>
</lib-card-content>

31. lib-button (Button)

Qué hace
Botón unificado de la librería con variantes de color y tamaños consistentes. Reemplaza los estilos de botones sueltos en modal-form y otros componentes.

Selector: lib-button

Inputs:

  • variant: 'primary' | 'secondary' | 'outline' = 'primary'
  • type: 'button' | 'submit' = 'button'
  • disabled: boolean = false
  • fullWidth: boolean = false
  • size: 'default' | 'compact' = 'default'default igual al botón de modal-form, compact más pequeño.

Outputs:

  • clicked: EventEmitter<MouseEvent>

Ejemplo rápido:

<lib-button variant="primary" (clicked)="onSubmit()">
  Guardar
</lib-button>

<lib-button variant="secondary" size="compact" (clicked)="onCancel()">
  Cancelar
</lib-button>

<lib-button variant="outline" [fullWidth]="true" size="compact">
  Acción secundaria
</lib-button>

32. lib-toggle-custom (ToggleCustom)

Qué hace Toggle (interruptor on/off) estilizado con label integrado. Implementa ControlValueAccessor para uso en formularios reactivos.

Selector: lib-toggle-custom

Inputs:

  • label: string = '' – Texto descriptivo que acompaña el toggle.

Uso standalone:

<lib-toggle-custom label="Recibir notificaciones" formControlName="notificar" />

Uso en lib-dynamic-form-fields:

{
  key: 'notificar',
  type: 'toggle',
  label: 'Recibir notificaciones',
}

Los campos toggle siempre ocupan la fila completa del formulario y nunca comparten fila con otros tipos de campo. Hasta 4 toggles consecutivos se distribuyen automáticamente en la misma fila (cada uno ocupa 1/4 del ancho).