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
importsdel 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
FilterItemdefine 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.
- Cada
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 (onullsi 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>– Emitetrueal confirmar yfalseal cancelar.confirmReason: EventEmitter<string | undefined>– Emite la razón seleccionada (oundefined).
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' }] },
],
}];
radioGroupyatLeastOneGroupson independientes entre sí. Se pueden usar en diferentesSectionConfigdel 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 incluiroptionscon{ 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 (onull).
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?: stringtype: string = 'text'options?: { code: string; name: string }[](modoselect)
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: stringconfirm: booleanconfirmLabel: stringitems: DialogItem[]– Lista de ítems con posibles hijos expandibles.
Outputs:
close: EventEmitter<boolean>–trueal confirmar,falseal 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é hacenlib-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
itemsLeftoitemsRight. 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 modoclickclickButtonIcon: string = ''— clase CSS del ícono en modoclickalwaysShowFilters: boolean = false— muestra los filtros permanentemente sin necesidad de toggleshowSecondaryButton: boolean = false— muestra un botón secundario al final de la fila del títulosecondaryButtonLabel: string = 'Exportar'secondaryButtonIcon: string = ''showButtonBack: boolean = false
Outputs:
filtersChange: Record<string, string | number | Date | null>applyFilters: voidclearFilters: voidfilterButtonClicked: void— emitido al hacer clic en el botónclickoactionsecondaryButtonClicked: voidclickButtonBack: 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: stringsubtitle?: stringvariant?: '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 | nullvalidateOnTabChange: boolean = false– Bloquea el cambio de tab si el formulario activo tiene campos inválidos.
Outputs:
tabChange: TabIdactiveTabChange: TabIdtabValidationFailed: 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 enAppComponent). - Inyectar
ToastServicedonde 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 buscaronSearchClear: 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
backgroundy--sl-form-surfacepara 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 = falsefullWidth: boolean = falsesize: 'default' | 'compact' = 'default'–defaultigual al botón demodal-form,compactmá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
togglesiempre 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).
