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

ten-minds-ui-kit

v0.0.1

Published

Librería de componentes UI para proyectos Angular de Ten Minds

Downloads

106

Readme

@10mindssoftware/tm-ui-kit

Librería de componentes UI para Angular, construida con Tailwind CSS v4 y Lucide Icons.


Instalación

npm install @10mindssoftware/tm-ui-kit

Configuración inicial

1.- Instalar la sgte libreria lucide-angular npm i lucide-angular

1. Agregar los estilos de la librería

Importá los estilos de la librería en el styles.css de tu proyecto:

@import '@10mindssoftware/tm-ui-kit/styles/styles.css';

Customización de Estilos

La librería @10mindssoftware/tm-ui-kit ofrece tres niveles de personalización según el alcance que necesites.


Nivel 1 — Global: sobreescribir tokens CSS

Afecta todos los componentes que usen ese token en toda la app.

Agrega esto en el styles.css de tu proyecto:

:root {
  --tm-gray-900: #your-brand-color;
}

O directamente el token semántico:

:root {
  --color-tm-brand: #your-brand-color;
  --color-tm-primary: #your-text-color;
}

Tokens disponibles

| Token | Descripción | Default (light) | | -------------------------------- | --------------------------- | --------------- | | --color-tm-brand | Color principal de la marca | #141414 | | --color-tm-primary | Texto principal | #141414 | | --color-tm-secondary | Texto secundario | #737373 | | --color-tm-tertiary | Texto terciario | #A0A0A0 | | --color-tm-inverse | Texto sobre fondos oscuros | #FFFFFF | | --color-tm-canvas | Fondo general de la app | #FAFAFA | | --color-tm-surface | Fondo de tarjetas y paneles | #FFFFFF | | --color-tm-subtle | Fondo sutil | #F0F0F0 | | --color-tm-muted | Fondo atenuado | #E4E4E4 | | --color-tm-brand-hover-default | Hover del botón brand | #363636 | | --color-tm-brand-hover-subtle | Hover sutil del botón brand | #F0F0F0 | | --color-tm-default | Borde por defecto | #E4E4E4 | | --color-tm-strong | Borde fuerte | #C8C8C8 |


Nivel 2 — Scoped: cambiar un componente en una sección

Afecta solo los componentes dentro de un contenedor específico. Se usa CSS puro — no Tailwind.

/* styles.css del proyecto consumidor */
.mi-seccion tm-btn-primary button {
  background-color: #your-color !important;
  font-size: 1.25rem !important;
  border-radius: 999px !important;
}
<div class="mi-seccion">
  <tm-btn-primary>Solo este botón cambia</tm-btn-primary>
</div>

<tm-btn-primary>Este queda igual</tm-btn-primary>

⚠️ CSS puro únicamente. Tailwind no funciona aquí porque se compila en build time y las clases de la librería no están disponibles en el proyecto consumidor.


Nivel 3 — Puntual: un solo componente con customClass

Afecta únicamente el componente donde lo aplicas. Aquí sí puedes usar clases de Tailwind porque se compilan en el proyecto consumidor.

<!-- Tailwind funciona aquí -->
<tm-btn-primary customClass="!bg-orange-500 !text-black"> Botón personalizado </tm-btn-primary>

<!-- CSS también funciona con clase propia -->
<tm-btn-primary customClass="mi-boton-especial"> Botón personalizado </tm-btn-primary>
/* styles.css */
.mi-boton-especial {
  background-color: orange !important;
  font-size: 1.25rem !important;
}

ℹ️ El modificador ! de Tailwind es necesario para sobreescribir estilos ya definidos por el componente.


Resumen

| Método | Alcance | Tailwind | Cuándo usarlo | | -------------------------- | ------------- | -------- | ----------------------------------------- | | Token CSS en :root | Toda la app | ✗ | Cambiar la paleta de colores del proyecto | | CSS scoped con clase padre | Una sección | ✗ | Variante especial en una página o sección | | customClass input | Un componente | ✓ | Ajuste puntual en un solo componente |

2. Importar los componentes

Los componentes son standalone — solo importa los que necesites directamente en tu componente o módulo:

import { BtnPrimary, Chip, CheckboxButton } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [BtnPrimary, Chip, CheckboxButton],
})

3. Usar íconos

Los íconos se importan directamente desde lucide-angular como objetos. No se requiere ninguna configuración global en app.config.ts.

import { Download, Trash2, Check } from 'lucide-angular';

export class MiComponente {
  download = Download;
  trash = Trash2;
  check = Check;
}
<tm-btn-primary [iconLeft]="download">Exportar</tm-btn-primary>
<tm-chip [iconLeft]="check">Activo</tm-chip>

Componentes disponibles

| Componente | Selector | Descripción | | ---------------- | ------------------ | --------------------------------------- | | BtnPrimary | tm-btn-primary | Botón principal con múltiples variantes | | Chip | tm-chip | Etiqueta de estado o categoría | | CheckboxButton | tm-checkbox | Checkbox personalizado | | Toggle | tm-toggle | Switch on/off | | RadioButton | tm-radio-button | Botón de selección única | | InputTen | tm-input | Campo de texto | | Avatar | tm-avatar | Avatar con iniciales y estado | | SnackbarHost | tm-snackbar-host | Contenedor de notificaciones |


Dark Mode

La librería soporta dark mode mediante la clase .dark en el elemento raíz. Agrégala o quítala desde tu componente:

onThemeChange(mode: 'light' | 'dark') {
  if (mode === 'dark') {
    document.documentElement.classList.add('dark');
  } else {
    document.documentElement.classList.remove('dark');
  }
}

Componentes

Avatar

Componente de avatar de la librería ten-minds-beta. Soporta imagen, iniciales como fallback, múltiples tamaños e indicador de estado.


Importación

import { Avatar } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [Avatar],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ---------- | ---------------------- | ---------- | ---------------------------------------------------------- | | src | string | '' | URL de la imagen. Si está vacío, se muestran las iniciales | | initials | string | '' | Texto de iniciales, se muestra cuando no hay imagen | | alt | string | 'Avatar' | Texto alternativo para accesibilidad | | size | AvatarSize | 'md' | Tamaño del avatar | | status | AvatarStatus \| null | null | Indicador de estado visible sobre el avatar |

Tipos

type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
type AvatarStatus = 'online' | 'busy' | 'disconnect';

Tamaños de referencia

| Valor | Tamaño | | ----- | ------ | | xs | 28px | | sm | 40px | | md | 48px | | lg | 60px | | xl | 80px |


Ejemplos

Con imagen

<tm-avatar src="https://ejemplo.com/foto.jpg" />
<tm-avatar src="https://ejemplo.com/foto.jpg" alt="Foto de Juan" />

Con iniciales (fallback sin imagen)

<tm-avatar initials="JP" /> <tm-avatar initials="AB" />

Si src está vacío e initials tiene valor, se muestran las iniciales sobre el fondo de marca.

Tamaños

<tm-avatar src="..." size="xs" />
<tm-avatar src="..." size="sm" />
<tm-avatar src="..." size="md" />
<tm-avatar src="..." size="lg" />
<tm-avatar src="..." size="xl" />

Indicador de estado

<tm-avatar src="..." status="online" />
<tm-avatar src="..." status="busy" />
<tm-avatar src="..." status="disconnect" />

Sin estado (por defecto)

<tm-avatar src="..." />
<!-- status es null por defecto, no se muestra el indicador -->

Combinaciones comunes

<!-- Avatar con iniciales y estado online -->
<tm-avatar initials="MG" status="online" />

<!-- Avatar grande con imagen y estado ocupado -->
<tm-avatar src="https://ejemplo.com/foto.jpg" alt="María García" size="lg" status="busy" />

<!-- Avatar pequeño desconectado -->
<tm-avatar src="https://ejemplo.com/foto.jpg" size="sm" status="disconnect" />

<!-- Avatar extra grande solo con iniciales -->
<tm-avatar initials="TM" size="xl" />

Notas

  • Si src tiene valor, se muestra la imagen. Si no, se recurre a las initials. Si tampoco hay iniciales, el avatar queda vacío con el fondo de marca.
  • El indicador de status escala automáticamente según el size del avatar y se posiciona en la esquina inferior derecha.
  • El indicador incluye role="status" y aria-label con el valor del estado para accesibilidad.

Componente BtnIcon

Componente de botón de ícono de la librería @10mindssoftware/tm-ui-kit. Versión cuadrada del botón principal, diseñado para acciones que se representan únicamente con un ícono. Soporta los mismos colores, variantes, tamaños y bordes redondeados que BtnPrimary.


Importación

import { BtnIcon } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [BtnIcon],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ----------- | ---------------- | ----------- | ------------------------------------------------------------------------ | | icon | LucideIconData | — | Requerido. Ícono a mostrar dentro del botón | | color | ButtonColor | 'primary' | Color del botón | | size | ButtonSize | 'md' | Tamaño del botón | | type | ButtonType | 'filled' | Variante visual | | rounded | ButtonRounded | 'default' | Forma del borde | | active | boolean | false | Aplica estado activo (brightness) | | disabled | boolean | false | Desactiva el botón | | ariaLabel | string | '' | Texto accesible del botón. Recomendado siempre que no haya texto visible |

Outputs

| Evento | Tipo | Descripción | | --------- | ------------ | --------------------------------------------------- | | clicked | MouseEvent | Se emite al hacer click (no emite si está disabled) |

Tipos

type ButtonColor = 'primary' | 'danger' | 'success' | 'warning';
type ButtonSize = 'lg' | 'md' | 'sm';
type ButtonType = 'filled' | 'outlined' | 'ghost';
type ButtonRounded = 'default' | 'full';

Tamaños de referencia

| Valor | Tamaño | Ícono | | ----- | ------ | ----- | | lg | 44px | 20px | | md | 40px | 18px | | sm | 36px | 16px |


Ejemplos

Uso básico

El prop icon es requerido. Siempre importa el ícono desde lucide-angular como objeto.

import { Trash2, Edit, Plus } from 'lucide-angular';

export class App {
  trash = Trash2;
  edit = Edit;
  plus = Plus;
}
<tm-icon-button [icon]="edit" ariaLabel="Editar" />

Colores

<tm-icon-button [icon]="edit" color="primary" ariaLabel="Editar" />
<tm-icon-button [icon]="trash" color="danger" ariaLabel="Eliminar" />
<tm-icon-button [icon]="plus" color="success" ariaLabel="Agregar" />
<tm-icon-button [icon]="edit" color="warning" ariaLabel="Advertencia" />

Variantes

<tm-icon-button [icon]="edit" type="filled" ariaLabel="Editar" />
<tm-icon-button [icon]="edit" type="outlined" ariaLabel="Editar" />
<tm-icon-button [icon]="edit" type="ghost" ariaLabel="Editar" />

Tamaños

<tm-icon-button [icon]="edit" size="lg" ariaLabel="Editar" />
<tm-icon-button [icon]="edit" size="md" ariaLabel="Editar" />
<tm-icon-button [icon]="edit" size="sm" ariaLabel="Editar" />

Bordes redondeados

<tm-icon-button [icon]="plus" rounded="default" ariaLabel="Agregar" />
<tm-icon-button [icon]="plus" rounded="full" ariaLabel="Agregar" />

Disabled

<tm-icon-button [icon]="trash" [disabled]="true" ariaLabel="Eliminar" />
<tm-icon-button
  [icon]="trash"
  color="danger"
  type="outlined"
  [disabled]="true"
  ariaLabel="Eliminar"
/>

Manejo de eventos

<tm-icon-button [icon]="trash" color="danger" ariaLabel="Eliminar" (clicked)="onEliminar($event)" />
onEliminar(event: MouseEvent) {
  console.log('Eliminando...', event);
}

Combinaciones comunes

<!-- Botón de acción flotante (FAB) -->
<tm-icon-button
  [icon]="plus"
  color="primary"
  size="lg"
  rounded="full"
  ariaLabel="Crear nuevo"
  (clicked)="onCreate($event)"
/>

<!-- Botón destructivo ghost -->
<tm-icon-button
  [icon]="trash"
  color="danger"
  type="ghost"
  size="sm"
  ariaLabel="Eliminar fila"
  (clicked)="onDelete($event)"
/>

<!-- Botón de edición outlined -->
<tm-icon-button
  [icon]="edit"
  color="primary"
  type="outlined"
  ariaLabel="Editar registro"
  (clicked)="onEdit($event)"
/>

Notas

  • El prop icon es requerido. El componente no renderiza nada sin él.
  • El evento clicked no se emite cuando disabled es true, no es necesario manejarlo manualmente.
  • Se recomienda proporcionar siempre un ariaLabel descriptivo ya que el botón no contiene texto visible, lo cual es importante para accesibilidad.
  • Los íconos deben importarse desde lucide-angular como objetos y asignarse a propiedades del componente. Pasar strings directamente no funciona.
  • El tamaño del ícono se ajusta automáticamente según el size del botón.

tm-button — Componente de Botón

Componente de botón de la librería @10mindssoftware/tm-ui-kit. Soporta múltiples colores, variantes, tamaños, bordes redondeados e íconos.


Instalación

Importa el componente en tu componente standalone:

import { BtnPrimary } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [BtnPrimary],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ------------- | ---------------- | ----------- | ---------------------- | | color | ButtonColor | 'primary' | Color del botón | | size | ButtonSize | 'md' | Tamaño del botón | | type | ButtonType | 'filled' | Variante visual | | rounded | ButtonRounded | 'default' | Forma del borde | | disabled | boolean | false | Desactiva el botón | | active | boolean | false | Aplica estado activo | | iconLeft | LucideIconData | — | Ícono a la izquierda | | iconRight | LucideIconData | — | Ícono a la derecha | | customClass | string | '' | Clases CSS adicionales |

Outputs

| Evento | Tipo | Descripción | | ----------- | ------------ | --------------------------------------------------- | | (clicked) | MouseEvent | Se emite al hacer click (no emite si está disabled) |

Tipos

type ButtonColor = 'primary' | 'danger' | 'success' | 'warning';
type ButtonSize = 'lg' | 'md' | 'sm';
type ButtonType = 'filled' | 'outlined' | 'ghost';
type ButtonRounded = 'default' | 'full';

Ejemplos

Uso básico

<tm-button>Guardar</tm-button>

Colores

<tm-button color="primary">Primary</tm-button>
<tm-button color="danger">Danger</tm-button>
<tm-button color="success">Success</tm-button>
<tm-button color="warning">Warning</tm-button>

Variantes

<tm-button type="filled">Filled</tm-button>
<tm-button type="outlined">Outlined</tm-button>
<tm-button type="ghost">Ghost</tm-button>

Tamaños

<tm-button size="lg">Large</tm-button>
<tm-button size="md">Medium</tm-button>
<tm-button size="sm">Small</tm-button>

Bordes redondeados

<tm-button rounded="default">Default</tm-button> <tm-button rounded="full">Pill</tm-button>

Disabled

<tm-button [disabled]="true">No disponible</tm-button>
<tm-button color="danger" type="outlined" [disabled]="true">Eliminar</tm-button>

Con íconos

Los íconos se importan desde lucide-angular como objetos y se asignan a propiedades del componente:

import { Download, Trash2, Check } from 'lucide-angular';

export class MiComponente {
  download = Download;
  trash = Trash2;
  check = Check;
}
<!-- Ícono izquierdo -->
<tm-button [iconLeft]="download">Exportar</tm-button>

<!-- Ícono derecho -->
<tm-button color="success" [iconRight]="check">Confirmar</tm-button>

<!-- Ambos íconos -->
<tm-button color="danger" type="outlined" [iconLeft]="trash" [iconRight]="check">
  Eliminar
</tm-button>

Manejo de eventos

<tm-button color="success" (clicked)="onGuardar($event)">Guardar</tm-button>
onGuardar(event: MouseEvent) {
  console.log('Guardando...', event);
}

Combinaciones comunes

<!-- Botón de acción principal -->
<tm-button color="primary" size="md" [iconLeft]="download">Exportar</tm-button>

<!-- Botón destructivo -->
<tm-button color="danger" type="outlined" size="md" [iconLeft]="trash">Eliminar</tm-button>

<!-- Botón pill -->
<tm-button color="primary" rounded="full" [iconLeft]="check">Confirmar</tm-button>

<!-- Botón pequeño ghost -->
<tm-button color="primary" type="ghost" size="sm">Ver más</tm-button>

Notas

  • El evento (clicked) no se emite cuando disabled es true.
  • Los íconos deben importarse desde lucide-angular como objetos. Pasar strings no funciona.
  • Usa customClass para agregar clases adicionales sin sobreescribir las base.

Componente Btn Theme

Componente de botón para alternar entre modo claro y oscuro. Cambia el icono según el modo actual y emite el nuevo modo al padre.


Instalación

import { BtnTheme } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [BtnTheme],
})

Uso básico

<lib-btn-theme [mode]="currentTheme" (modeChange)="onThemeChange($event)" />
import { ThemeMode } from '@10mindssoftware/tm-ui-kit';

currentTheme: ThemeMode = 'light';

onThemeChange(mode: ThemeMode) {
  this.currentTheme = mode;
  if (mode === 'dark') {
    document.documentElement.classList.add('dark');
  } else {
    document.documentElement.classList.remove('dark');
  }
}

Inputs y Outputs

| Input | Tipo | Default | Descripción | | ---------- | ----------- | --------- | ------------------------ | | mode | ThemeMode | 'light' | Modo actual del tema | | disabled | boolean | false | Desactiva la interacción |

| Output | Tipo | Descripción | | ------------ | ----------- | ---------------------------------- | | modeChange | ThemeMode | Emite el nuevo modo al hacer click |


Tipos

type ThemeMode = 'light' | 'dark';

Estados

Light (modo claro)

<lib-btn-theme mode="light" (modeChange)="onThemeChange($event)" />

Dark (modo oscuro)

<lib-btn-theme mode="dark" (modeChange)="onThemeChange($event)" />

Disabled

<lib-btn-theme [disabled]="true" />

Casos de uso reales

Toggle global en el navbar

<nav class="flex items-center justify-between px-6 py-4">
  <span>Mi App</span>
  <lib-btn-theme [mode]="currentTheme" (modeChange)="onThemeChange($event)" />
</nav>
currentTheme: ThemeMode = 'light';

onThemeChange(mode: ThemeMode) {
  this.currentTheme = mode;
  if (mode === 'dark') {
    document.documentElement.classList.add('dark');
  } else {
    document.documentElement.classList.remove('dark');
  }
}

Persistir en localStorage

currentTheme: ThemeMode = 'light';

ngOnInit() {
  const saved = localStorage.getItem('theme') as ThemeMode;
  if (saved) {
    this.currentTheme = saved;
    document.documentElement.classList.toggle('dark', saved === 'dark');
  }
}

onThemeChange(mode: ThemeMode) {
  this.currentTheme = mode;
  localStorage.setItem('theme', mode);
  document.documentElement.classList.toggle('dark', mode === 'dark');
}

Componente CardButton

Componente de botón de carrito de compras de la librería @10mindssoftware/tm-ui-kit. Muestra un ícono de carrito con un badge numérico opcional según la cantidad de ítems.


Importación

import { CardButton } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [CardButton],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ----------- | --------- | ---------------------- | -------------------------------------------------------------------------------------- | | count | number | 0 | Cantidad de ítems en el carrito. Si es 0, no se muestra el badge | | disabled | boolean | false | Desactiva el botón | | ariaLabel | string | 'Carrito de compras' | Texto accesible del botón. Se complementa automáticamente con la cantidad si hay ítems |

Outputs

| Evento | Tipo | Descripción | | --------- | ------ | --------------------------------------------------- | | clicked | void | Se emite al hacer click (no emite si está disabled) |


Ejemplos

Uso básico

<tm-card-button />

Con ítems en el carrito

<tm-card-button [count]="3" /> <tm-card-button [count]="9" />

Cuando count supera 9, el badge muestra 9+ en lugar del número exacto.

<tm-card-button [count]="15" />
<!-- Badge muestra: 9+ -->

Deshabilitado

<tm-card-button [disabled]="true" /> <tm-card-button [count]="4" [disabled]="true" />

Manejo de eventos

<tm-card-button [count]="itemCount" (clicked)="onCartClick()" />
itemCount = 2;

onCartClick() {
  console.log('Abriendo carrito...');
}

Con aria-label personalizado

<tm-card-button ariaLabel="Ver mi pedido" [count]="2" />
<!-- aria-label resultante: "Ver mi pedido, 2 items" -->

Combinaciones comunes

<!-- Carrito vacío -->
<tm-card-button (clicked)="abrirCarrito()" />

<!-- Carrito con items -->
<tm-card-button [count]="totalItems" (clicked)="abrirCarrito()" />

<!-- Carrito deshabilitado durante carga -->
<tm-card-button [count]="totalItems" [disabled]="cargando" (clicked)="abrirCarrito()" />

Notas

  • El badge solo es visible cuando count es mayor a 0.
  • Cuando count supera 9, el badge muestra 9+ para evitar desbordamiento visual.
  • El evento clicked no se emite cuando disabled es true, no es necesario manejarlo manualmente.
  • El aria-label se construye dinámicamente: si hay ítems, añade la cantidad al texto base (ej. "Carrito de compras, 3 items"). El badge tiene aria-hidden="true" para evitar duplicados en lectores de pantalla.
  • El ícono del carrito es fijo (ShoppingCart de lucide-angular) y no es configurable.

Componente Checkbox

Componente de selección para formularios. Permite marcar o desmarcar una opción individual. Semánticamente correcto y accesible.


Instalación

import { CheckboxButton } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [CheckboxButton],
})

Uso básico

<tm-checkbox-button [checked]="isChecked" (changed)="isChecked = $event" />

API

Inputs

| Input | Tipo | Default | Descripción | | ---------- | --------- | ------------- | ----------------------------------------- | | checked | boolean | false | Estado actual del checkbox | | disabled | boolean | false | Desactiva la interacción | | label | string | — | Texto descriptivo al lado del checkbox | | id | string | auto-generado | ID del input para asociar labels externos |

Outputs

| Output | Tipo | Descripción | | ----------- | --------- | ------------------------------------ | | (changed) | boolean | Emite el nuevo estado al hacer click |


Estados

<!-- Desmarcado -->
<tm-checkbox-button [checked]="false" (changed)="isChecked = $event" />

<!-- Marcado -->
<tm-checkbox-button [checked]="true" (changed)="isChecked = $event" />

<!-- Disabled desmarcado -->
<tm-checkbox-button [checked]="false" [disabled]="true" />

<!-- Disabled marcado -->
<tm-checkbox-button [checked]="true" [disabled]="true" />

Con label

<tm-checkbox-button
  [checked]="isChecked"
  label="Aceptar términos y condiciones"
  (changed)="isChecked = $event"
/>

Manejo del estado

El checkbox no guarda estado internamente. El padre es responsable de actualizar el valor:

isChecked = false;

onChanged(value: boolean) {
  this.isChecked = value;
}
<tm-checkbox-button [checked]="isChecked" (changed)="onChanged($event)" />

Casos de uso reales

Aceptar términos

<tm-checkbox-button
  [checked]="aceptaTerminos"
  label="Acepto los términos y condiciones"
  (changed)="aceptaTerminos = $event"
/>

<tm-button [disabled]="!aceptaTerminos" (clicked)="continuar()"> Continuar </tm-button>

Lista de permisos

@for (permiso of permisos; track permiso.id) {
<tm-checkbox-button
  [checked]="permiso.activo"
  [label]="permiso.nombre"
  (changed)="togglePermiso(permiso.id, $event)"
/>
}
togglePermiso(id: string, value: boolean) {
  const permiso = this.permisos.find(p => p.id === id);
  if (permiso) permiso.activo = value;
}

Con disabled según permisos

<tm-checkbox-button
  [checked]="opcion.activa"
  [disabled]="!tienePermisos"
  [label]="opcion.nombre"
  (changed)="opcion.activa = $event"
/>

Componente de Chip

Componente para mostrar estados, etiquetas o valores visuales. Puede ser estático o clickeable.


Instalación

import { Chip } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [Chip],
})

Uso básico

<tm-chip status="success">Activo</tm-chip>

Status (colores)

| Status | Uso recomendado | | --------- | --------------------------------- | | success | Activo, completado, aprobado | | warning | Pendiente, por vencer, precaución | | danger | Inactivo, error, rechazado | | info | Informativo, en proceso | | indigo | Categorías, etiquetas neutras | | brand | Destacado, principal |

<tm-chip status="success">Activo</tm-chip>
<tm-chip status="warning">Pendiente</tm-chip>
<tm-chip status="danger">Inactivo</tm-chip>
<tm-chip status="info">En proceso</tm-chip>
<tm-chip status="indigo">Categoría</tm-chip>
<tm-chip status="brand">Destacado</tm-chip>

Type (estilo visual)

| Type | Descripción | | ---------- | --------------------------------------- | | filled | Fondo sólido con texto blanco | | subtle | Fondo suave con texto del color | | outlined | Sin fondo, solo borde y texto del color |

<tm-chip status="success" type="filled">Filled</tm-chip>
<tm-chip status="success" type="subtle">Subtle</tm-chip>
<tm-chip status="success" type="outlined">Outlined</tm-chip>

Rounded (forma)

| Rounded | Uso recomendado | | --------- | ---------------------------- | | default | Estados, badges informativos | | full | Filtros, tags interactivos |

<tm-chip status="info" rounded="default">Estado</tm-chip>
<tm-chip status="info" rounded="full">Etiqueta</tm-chip>

Íconos

Los íconos se importan desde lucide-angular como objetos:

import { Check, TriangleAlert, X } from 'lucide-angular';

export class MiComponente {
  check = Check;
  alert = TriangleAlert;
  x = X;
}
<!-- Ícono izquierdo -->
<tm-chip status="success" [iconLeft]="check">Activo</tm-chip>

<!-- Ícono derecho -->
<tm-chip status="info" [iconRight]="x">Etiqueta</tm-chip>

<!-- Ambos íconos -->
<tm-chip status="warning" [iconLeft]="alert" [iconRight]="x">Advertencia</tm-chip>

Clickeable

Por defecto el chip es estático. Para hacerlo interactivo usa [clickable]="true" y escucha el evento (clicked):

<tm-chip
  status="danger"
  type="filled"
  rounded="full"
  [iconLeft]="x"
  [clickable]="true"
  (clicked)="onDesactivar()"
>
  Desactivar
</tm-chip>
onDesactivar() {
  console.log('chip clickeado');
}

Si clickable es false (default), el chip no emite eventos ni muestra cursor pointer.


API

Inputs

| Input | Tipo | Default | Descripción | | ----------- | ---------------- | ----------- | ------------------------------- | | status | ChipStatus | 'brand' | Color del chip | | type | ChipType | 'filled' | Estilo visual | | rounded | ChipRounded | 'default' | Forma del borde | | iconLeft | LucideIconData | — | Ícono a la izquierda | | iconRight | LucideIconData | — | Ícono a la derecha | | clickable | boolean | false | Habilita click y cursor pointer |

Outputs

| Output | Tipo | Descripción | | ----------- | ------ | --------------------------------------------- | | (clicked) | void | Se emite al hacer click si clickable="true" |

Tipos

type ChipStatus = 'success' | 'warning' | 'indigo' | 'danger' | 'info' | 'brand';
type ChipType = 'filled' | 'subtle' | 'outlined';
type ChipRounded = 'default' | 'full';

Casos de uso reales

<!-- Estado de un producto -->
<tm-chip status="success" type="subtle" rounded="full" [iconLeft]="check"> Activo </tm-chip>

<!-- Licencia por vencer -->
<tm-chip status="warning" type="filled" rounded="default" [iconLeft]="alert"> Por vencer </tm-chip>

<!-- Filtro clickeable -->
<tm-chip status="indigo" type="outlined" rounded="full" [clickable]="true" (clicked)="filtrar()">
  Electrónica
</tm-chip>

<!-- Notificación de error -->
<tm-chip status="danger" type="subtle" rounded="default" [iconLeft]="x"> Pago rechazado </tm-chip>

Componente CloseDialog

Componente de botón de cierre de la librería @10mindssoftware/tm-ui-kit. Diseñado para cerrar diálogos, modales o paneles. Muestra un ícono de X con fondo circular al hacer hover.


Importación

import { CloseDialog } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [CloseDialog],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ----------- | --------- | ---------- | ------------------------- | | disabled | boolean | false | Desactiva el botón | | ariaLabel | string | 'Cerrar' | Texto accesible del botón |

Outputs

| Evento | Tipo | Descripción | | -------- | ------ | --------------------------------------------------- | | closed | void | Se emite al hacer click (no emite si está disabled) |


Ejemplos

Uso básico

<tm-close-dialog (closed)="onClose()" />

Deshabilitado

<tm-close-dialog [disabled]="true" />

Con aria-label personalizado

<tm-close-dialog ariaLabel="Cerrar modal de confirmación" (closed)="onClose()" />

Combinaciones comunes

<!-- En la cabecera de un modal -->
<div class="flex items-center justify-between">
  <h2>Título del modal</h2>
  <tm-close-dialog (closed)="cerrarModal()" />
</div>

<!-- Deshabilitado durante procesamiento -->
<tm-close-dialog [disabled]="procesando" (closed)="cerrarModal()" />
procesando = false;

cerrarModal() {
  console.log('Cerrando modal...');
}

Notas

  • El evento closed no se emite cuando disabled es true, no es necesario manejarlo manualmente.
  • El ícono de cierre es fijo (X de lucide-angular) y no es configurable.
  • El botón tiene forma circular y aplica un fondo sutil (hover:bg-tm-subtle) al pasar el cursor, sin afectar el layout del contenedor.

Componente InputTen

Componente de campo de texto de la librería @10mindssoftware/tm-ui-kit. Soporta múltiples tipos de input, tamaños, íconos, estados de error, hints y labels.


Uso

Importa el componente en tu módulo o componente standalone:

import { InputTen } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [InputTen],
})

API

Inputs

| Prop | Tipo | Default | Descripción | | ------------- | ---------------- | --------------- | ------------------------------------------------------------ | | value | string | '' | Valor del input (two-way binding con model) | | size | InputSize | 'md' | Tamaño del input | | type | InputType | 'text' | Tipo de input nativo | | placeholder | string | 'placeholder' | Texto de placeholder | | label | string | '' | Etiqueta visible sobre el input | | hint | string | '' | Texto de ayuda debajo del input (no se muestra si hay error) | | disabled | boolean | false | Desactiva el input | | required | boolean | false | Marca el campo como requerido (agrega * al label) | | error | string | '' | Mensaje de error (activa el estado visual de error) | | iconLeft | LucideIconData | — | Ícono a la izquierda del input | | iconRight | LucideIconData | — | Ícono a la derecha del input |

Outputs

| Evento | Tipo | Descripción | | --------- | ------------ | --------------------------------------- | | focused | FocusEvent | Se emite cuando el input recibe el foco | | blurred | FocusEvent | Se emite cuando el input pierde el foco |

Tipos

type InputSize = 'sm' | 'md';
type InputType = 'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url';

Ejemplos

Uso básico

<tm-input placeholder="Escribe algo..." />

Con label y hint

<tm-input
  label="Correo electrónico"
  placeholder="[email protected]"
  hint="Nunca compartiremos tu correo."
/>

Campo requerido

<tm-input label="Nombre completo" placeholder="Juan Pérez" [required]="true" />

Tamaños

<tm-input size="md" placeholder="Medium (default)" /> <tm-input size="sm" placeholder="Small" />

Tipos de input

<tm-input type="text" placeholder="Texto" />
<tm-input type="email" placeholder="Correo" />
<tm-input type="password" placeholder="Contraseña" />
<tm-input type="number" placeholder="Número" />
<tm-input type="search" placeholder="Buscar..." />
<tm-input type="tel" placeholder="Teléfono" />
<tm-input type="url" placeholder="https://..." />

Estado deshabilitado

<tm-input [disabled]="true" placeholder="No disponible" />
<tm-input [disabled]="true" label="Usuario" placeholder="admin" />

Estado de error

<tm-input
  label="Correo electrónico"
  placeholder="[email protected]"
  error="El correo ingresado no es válido."
/>

Cuando error tiene valor, el hint queda oculto y el borde cambia a rojo.

Con íconos

Los íconos se pasan como objetos LucideIconData, no como strings.

// app.ts
import { Mail, Lock, Search, Eye } from 'lucide-angular';

export class App {
  mail = Mail;
  lock = Lock;
  search = Search;
  eye = Eye;
}
<!-- Ícono izquierdo -->
<tm-input [iconLeft]="mail" placeholder="Correo electrónico" />

<!-- Ícono derecho -->
<tm-input [iconRight]="eye" type="password" placeholder="Contraseña" />

<!-- Ambos íconos -->
<tm-input [iconLeft]="search" [iconRight]="eye" placeholder="Buscar..." />

Two-way binding

<tm-input [(value)]="correo" placeholder="Correo electrónico" />
<p>Valor actual: {{ correo }}</p>
correo = '';

Manejo de eventos de foco

<tm-input placeholder="Nombre" (focused)="onFocus($event)" (blurred)="onBlur($event)" />
onFocus(event: FocusEvent) {
  console.log('Input enfocado', event);
}

onBlur(event: FocusEvent) {
  console.log('Input desenfocado', event);
}

Combinaciones comunes

<!-- Campo de búsqueda -->
<tm-input type="search" size="sm" [iconLeft]="search" placeholder="Buscar usuarios..." />

<!-- Campo de contraseña con label y error -->
<tm-input
  type="password"
  label="Contraseña"
  placeholder="Mínimo 8 caracteres"
  [iconLeft]="lock"
  error="La contraseña es demasiado corta."
/>

<!-- Campo de email requerido con hint -->
<tm-input
  type="email"
  label="Correo electrónico"
  placeholder="[email protected]"
  [iconLeft]="mail"
  hint="Te enviaremos un enlace de confirmación."
  [required]="true"
  [(value)]="email"
/>

Notas

  • El prop value usa model() de Angular Signals, lo que permite two-way binding con la sintaxis [(value)].
  • Cuando error tiene contenido, el hint no se muestra, independientemente de su valor.
  • El estado visual del wrapper cambia automáticamente entre default, active, error y disabled sin configuración adicional.
  • Los íconos deben importarse desde lucide-angular como objetos y asignarse a propiedades del componente. Pasar strings directamente no funciona.
  • No se requiere ninguna configuración global de íconos en app.config.ts.

Componente de Menú

Componente de menú desplegable flexible para Angular. Soporta cualquier trigger personalizado (avatar, botón, ícono de 3 puntos, etc.) y contenido variable dentro del panel.


Instalación

Importa TmMenu en tu componente:

import { TmMenu } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [TmMenu],
})
export class MiComponente {}

TmMenu ya incluye MenuComponent, MenuTriggerDirective y MenuItem — no necesitas importarlos por separado.


Uso básico

<tm-menu placement="bottom-end" triggerOn="click">
  <ng-template tmMenuTrigger>
    <button>Abrir menú</button>
  </ng-template>

  <tm-menu-item label="Mi perfil" [icon]="userIcon" />
  <tm-menu-item label="Configuración" [icon]="settingsIcon" />
  <tm-menu-item label="Cerrar sesión" [danger]="true" [divider]="true" />
</tm-menu>

Inputs de tm-menu

| Input | Tipo | Default | Descripción | | ----------- | ------------------------------------------------------------ | -------------- | ----------------------- | | placement | 'bottom-start' \| 'bottom-end' \| 'top-start' \| 'top-end' | 'bottom-end' | Posición del panel | | triggerOn | 'click' \| 'hover' \| 'both' | 'click' | Cómo se dispara el menú |

Outputs de tm-menu

| Output | Descripción | | ---------- | --------------------------------- | | (opened) | Se emite cuando el menú se abre | | (closed) | Se emite cuando el menú se cierra |


Inputs de tm-menu-item

| Input | Tipo | Default | Descripción | | ---------- | ---------------- | --------- | ----------------------------- | | label | string | requerido | Texto del ítem | | icon | LucideIconData | — | Ícono a la izquierda | | danger | boolean | false | Estilo de color rojo | | divider | boolean | false | Muestra línea divisora encima | | disabled | boolean | false | Deshabilita el ítem |

Outputs de tm-menu-item

| Output | Descripción | | ------------ | -------------------------------------------- | | (selected) | Se emite al hacer click (respeta disabled) |


Ícono dinámico de abierto/cerrado

Para mostrar un chevron que cambia según el estado del menú, usa los outputs (opened) y (closed) junto con un signal en tu componente:

En tu .ts:

import { signal } from '@angular/core';
import { ChevronDown, ChevronUp } from 'lucide-angular';

isMenuOpen = signal(false);
chevronDown = ChevronDown;
chevronUp = ChevronUp;

En tu .html:

<tm-menu placement="bottom-end" (opened)="isMenuOpen.set(true)" (closed)="isMenuOpen.set(false)">
  <ng-template tmMenuTrigger>
    <div class="flex items-center gap-2">
      <span>Jhon Doe</span>
      <lucide-icon [img]="isMenuOpen() ? chevronUp : chevronDown" [size]="16" />
    </div>
  </ng-template>

  <tm-menu-item label="Mi perfil" [icon]="userIcon" />
  <tm-menu-item label="Cerrar sesión" [danger]="true" />
</tm-menu>

Si tienes múltiples menús en el mismo componente, crea un signal separado para cada uno: isMenu1Open, isMenu2Open, etc.


Menú con header de perfil (caso mobile/especial)

Usa el slot menuHeader para agregar contenido encima de los ítems, como el avatar y nombre del usuario:

<tm-menu placement="bottom-start">
  <ng-template tmMenuTrigger>
    <img src="avatar.png" class="rounded-full w-10 h-10" />
  </ng-template>

  <!-- Header opcional -->
  <div menuHeader class="px-3 py-3 flex items-center gap-3 border-b border-tm-subtle w-full">
    <img src="avatar.png" class="rounded-full w-10 h-10" />
    <div>
      <p class="font-medium text-sm">Jhon Doe</p>
      <p class="text-xs text-tm-secondary">Super Admin</p>
    </div>
  </div>

  <tm-menu-item label="Mi perfil" [icon]="userIcon" />
  <tm-menu-item label="Cerrar sesión" [danger]="true" [divider]="true" />
</tm-menu>

Menú de acciones en tabla (ícono de 3 puntos)

<tm-menu placement="bottom-end">
  <ng-template tmMenuTrigger>
    <lucide-icon [img]="dotsIcon" [size]="16" />
  </ng-template>

  <tm-menu-item label="Editar" [icon]="editIcon" />
  <tm-menu-item label="Eliminar" [icon]="trashIcon" [danger]="true" [divider]="true" />
</tm-menu>

Divider

El divider muestra una línea separadora encima del ítem. Úsalo en el primer ítem de una sección secundaria, como "Cerrar sesión":

<tm-menu-item label="Cerrar sesión" [danger]="true" [divider]="true" />

Componente de Radio Button

Componente de selección única para formularios. Se usa en grupos donde solo una opción puede estar seleccionada a la vez.


Instalación

import { RadioButton } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [RadioButton],
})

Uso básico

<tm-radio-button
  value="opcion1"
  name="mi-grupo"
  [checked]="selected === 'opcion1'"
  (changed)="selected = $event"
/>

API

Inputs

| Input | Tipo | Default | Descripción | | ---------- | --------- | --------------- | ------------------------------------------------------- | | value | string | requerido | Valor que emite cuando se selecciona | | name | string | 'radio-group' | Nombre del grupo, debe ser igual en todos los del grupo | | checked | boolean | false | Estado actual del radio | | disabled | boolean | false | Desactiva la interacción | | label | string | — | Texto descriptivo al lado del radio | | id | string | auto-generado | ID del input para asociar labels externos |

Outputs

| Output | Tipo | Descripción | | ----------- | -------- | --------------------------------------- | | (changed) | string | Emite el value del radio seleccionado |


Estados

<!-- Sin seleccionar -->
<tm-radio-button value="opcion1" name="grupo" [checked]="false" (changed)="onChanged($event)" />

<!-- Seleccionado -->
<tm-radio-button value="opcion1" name="grupo" [checked]="true" (changed)="onChanged($event)" />

<!-- Disabled desmarcado -->
<tm-radio-button value="opcion1" name="grupo" [checked]="false" [disabled]="true" />

<!-- Disabled marcado -->
<tm-radio-button value="opcion1" name="grupo" [checked]="true" [disabled]="true" />

Uso en grupo

El name debe ser el mismo en todos los radio del grupo. El padre controla cuál está seleccionado comparando value con el valor actual:

selected = 'mensual';

onChanged(value: string) {
  this.selected = value;
}
<div class="flex flex-col gap-3">
  <tm-radio-button
    value="mensual"
    name="plan"
    label="Mensual"
    [checked]="selected === 'mensual'"
    (changed)="onChanged($event)"
  />
  <tm-radio-button
    value="anual"
    name="plan"
    label="Anual"
    [checked]="selected === 'anual'"
    (changed)="onChanged($event)"
  />
  <tm-radio-button
    value="lifetime"
    name="plan"
    label="De por vida"
    [checked]="selected === 'lifetime'"
    (changed)="onChanged($event)"
  />
</div>

Casos de uso reales

Selección de plan

<div class="flex flex-col gap-3">
  @for (plan of planes; track plan.id) {
  <tm-radio-button
    [value]="plan.id"
    name="planes"
    [label]="plan.nombre"
    [checked]="selectedPlan === plan.id"
    (changed)="selectedPlan = $event"
  />
  }
</div>

Con opción desactivada

<tm-radio-button
  value="premium"
  name="plan"
  label="Premium (próximamente)"
  [checked]="false"
  [disabled]="true"
/>

Selección de rol en formulario

<div class="flex flex-col gap-3">
  <tm-radio-button
    value="admin"
    name="rol"
    label="Administrador"
    [checked]="rol === 'admin'"
    (changed)="rol = $event"
  />
  <tm-radio-button
    value="editor"
    name="rol"
    label="Editor"
    [checked]="rol === 'editor'"
    (changed)="rol = $event"
  />
  <tm-radio-button
    value="viewer"
    name="rol"
    label="Solo lectura"
    [checked]="rol === 'viewer'"
    (changed)="rol = $event"
  />
</div>
rol = 'viewer';

Componente de Select

Combobox con búsqueda integrada, soporte para avatar, ícono y grupos de opciones. Usa CDK Overlay para funcionar correctamente dentro de modales y tablas.


Instalación

Importa TmSelect en tu componente:

import { TmSelect } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [TmSelect],
})
export class MiComponente {}

Uso básico

<div class="w-[273px]">
  <tm-select
    label="Asignar a"
    placeholder="Selecciona una persona"
    [options]="myOptions"
    (changed)="onSelect($event)"
  />
</div>
import { SelectOption } from '@10mindssoftware/tm-ui-kit';

myOptions: SelectOption[] = [
  { value: 1, label: 'Ana García' },
  { value: 2, label: 'Luis Pérez' },
  { value: 3, label: 'Sin asignar', disabled: true },
];

onSelect(option: SelectOption | null) {
  console.log('value:', option?.value); // el ID que mandas al backend
}

El select ocupa el 100% del contenedor padre. Define el ancho desde afuera con un div wrapper.


API de inputs

| Input | Tipo | Default | Descripción | | ------------- | ---------------- | ------------------ | ----------------------------- | | options | SelectOption[] | [] | Lista de opciones | | placeholder | string | 'Seleccionar...' | Texto cuando no hay selección | | size | 'sm' \| 'md' | 'md' | Tamaño del campo | | label | string | '' | Etiqueta encima del campo | | disabled | boolean | false | Deshabilita el select | | error | string | '' | Mensaje de error |

API de outputs

| Output | Tipo | Descripción | | ----------- | ---------------------- | --------------------------------- | | (changed) | SelectOption \| null | Se emite al seleccionar o limpiar |

Model

| Model | Tipo | Descripción | | ------- | -------------------------- | ---------------------------------------------- | | value | string \| number \| null | Valor seleccionado (bindeable con [(value)]) |


Ejemplo con avatar e ícono

Cada opción puede tener un avatar (imagen) o un icon (Lucide). Si tiene ambos, el avatar tiene prioridad.

import { User, Package } from 'lucide-angular';

myOptions: SelectOption[] = [
  { value: 1, label: 'Ana García', avatar: 'https://ejemplo.com/ana.jpg' },
  { value: 2, label: 'Luis Pérez', icon: User },
  { value: 3, label: 'Sin asignar', disabled: true },
];
<div class="w-[273px]">
  <tm-select
    label="Responsable"
    placeholder="Selecciona una persona"
    [options]="myOptions"
    (changed)="onSelect($event)"
  />
</div>

Ejemplo con grupos

Agrega la propiedad group a cada opción para agruparlas con un encabezado:

myOptions: SelectOption[] = [
  { value: 1, label: 'Ana García', avatar: 'https://...', group: 'Equipo A' },
  { value: 2, label: 'Luis Pérez', icon: User,            group: 'Equipo A' },
  { value: 3, label: 'Sin asignar',                       group: 'Equipo B', disabled: true },
];

Las opciones sin group se muestran sin encabezado.


Ejemplo con error y disabled

<div class="w-[273px] flex flex-col gap-4">
  <!-- Con error -->
  <tm-select
    label="Asignar a"
    [options]="myOptions"
    error="Este campo es requerido"
    (changed)="onSelect($event)"
  />

  <!-- Deshabilitado -->
  <tm-select label="Asignar a" [options]="myOptions" [disabled]="true" />
</div>

Obtener el valor para el backend

El value de cada opción es el ID que usas para mandar al backend:

onSelect(option: SelectOption | null) {
  const payload = {
    asignado_a: option?.value ?? null
  };
  this.api.post('/tarea', payload).subscribe();
}

Interface SelectOption

export interface SelectOption {
  value: string | number;
  label: string;
  avatar?: string;
  icon?: LucideIconData;
  group?: string;
  disabled?: boolean;
}

Componente SnackbarService

Sistema de notificaciones globales para mostrar feedback visual al usuario.

Configuración (una sola vez)

app.html:

<snackbar-host /> <router-outlet />

app.ts:

import { SnackbarHost } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [SnackbarHost],
})

Uso

import { SnackbarService } from '@10mindssoftware/tm-ui-kit';

export class MiComponente {
  snackbar = inject(SnackbarService);

  async onGuardar() {
    try {
      await this.service.guardar(data);
      this.snackbar.alert('success', 'Guardado', 'Los cambios fueron guardados correctamente');
    } catch {
      this.snackbar.alert('error', 'Error', 'No pudimos guardar los cambios');
    }
  }
}

Métodos

| Método | Descripción | | --------------------------------------------------------- | -------------------------------- | | alert(color, title, description?, duration?, position?) | Desaparece automáticamente | | notify(color, title, description?, position?) | El usuario la cierra manualmente |

Parámetros

| Parámetro | Tipo | Default | Valores | | ------------- | ------------------ | ----------- | -------------------------------------------------------------------------------- | | color | SnackbarColor | — | success error warning info | | title | string | — | — | | description | string | undefined | — | | duration | number | 5000 | Milisegundos | | position | SnackbarPosition | top-right | top-left top-center top-right bottom-left bottom-center bottom-right |

Ejemplos

// Mínimo
this.snackbar.alert('success', 'Guardado');

// Con descripción
this.snackbar.alert('error', 'Error de pago', 'No pudimos procesar tu método de pago');

// Con duración personalizada
this.snackbar.alert('warning', 'Licencia por expirar', 'Expira en 7 días', 2000);

// Con posición personalizada
this.snackbar.alert('info', 'Nueva versión', 'Yana 2.0 disponible', 5000, 'bottom-center');

// Notificación persistente
this.snackbar.notify('success', 'Compra exitosa', 'Tu licencia fue activada');

// Notificación con posición
this.snackbar.notify('error', 'Sin conexión', undefined, 'bottom-right');

Componente Toggle

Componente de interruptor para activar o desactivar estados. Emite el nuevo valor al padre para que maneje la lógica correspondiente.


Instalación

import { Toggle } from '@10mindssoftware/tm-ui-kit';

@Component({
  imports: [Toggle],
})

Uso básico

<tm-toggle [value]="isActive" (changed)="isActive = $event" />

API

Inputs

| Input | Tipo | Default | Descripción | | ---------- | --------- | ------- | ------------------------ | | value | boolean | false | Estado actual del toggle | | disabled | boolean | false | Desactiva la interacción |

Outputs

| Output | Tipo | Descripción | | ----------- | --------- | ------------------------------------ | | (changed) | boolean | Emite el nuevo estado al hacer click |


Estados

<!-- Apagado -->
<tm-toggle [value]="false" (changed)="onChanged($event)" />

<!-- Encendido -->
<tm-toggle [value]="true" (changed)="onChanged($event)" />

<!-- Disabled apagado -->
<tm-toggle [value]="false" [disabled]="true" />

<!-- Disabled encendido -->
<tm-toggle [value]="true" [disabled]="true" />

Manejo del estado

El toggle no guarda estado internamente. El padre es responsable de actualizar el valor:

isActive = false;

onChanged(value: boolean) {
  this.isActive = value;
}
<tm-toggle [value]="isActive" (changed)="onChanged($event)" />

O de forma inline:

<tm-toggle [value]="isActive" (changed)="isActive = $event" />

Casos de uso reales

Activar notificaciones

<div class="flex items-center gap-3">
  <tm-toggle [value]="notificaciones" (changed)="notificaciones = $event" />
  <span>Notificaciones</span>
</div>

@if (notificaciones) {
<p>Recibirás notificaciones de nuevos eventos.</p>
} @else {
<p>Las notificaciones están desactivadas.</p>
}

Activar/desactivar un producto

<div class="flex items-center gap-3">
  <tm-toggle [value]="producto.activo" (changed)="toggleProducto($event)" />
  <span>{{ producto.activo ? 'Activo' : 'Inactivo' }}</span>
</div>
toggleProducto(value: boolean) {
  this.producto.activo = value;
  this.productoService.actualizarEstado(this.producto.id, value);
}

Con disabled según permisos

<tm-toggle
  [value]="configuracion.habilitado"
  [disabled]="!tienePermisos"
  (changed)="configuracion.habilitado = $event"
/>