@luisvelito/angular
v1.0.4
Published
Angular 17 components for the design system
Readme
@luisvelito/angular
Sistema de diseño completo construido con Angular 20, TypeScript y Tailwind CSS. Componentes standalone con soporte completo para formularios reactivos y template-driven forms.
🎨 Características
- ✅ Componentes standalone: No requiere módulos, 100% standalone
- 🎯 Angular 20: Utiliza las últimas características de Angular
- 🎨 Tailwind CSS: Estilos utilitarios con preset personalizado
- 🌓 Dark Mode: Soporte completo para modo oscuro
- ♿ Accesible: Cumple con los estándares WCAG
- 📋 Forms: ControlValueAccessor en todos los componentes de formulario
- 🔥 Flowbite aesthetic: Diseño moderno y limpio
- 📦 Tree-shakeable: Solo importa lo que necesitas
📦 Instalación
npm install @luisvelito/angular @luisvelito/tokens
# o
yarn add @luisvelito/angular @luisvelito/tokens
# o
pnpm add @luisvelito/angular @luisvelito/tokensDependencias peer requeridas
npm install @angular/core @angular/common @angular/forms tailwindcss⚙️ Configuración
1. Configurar Tailwind CSS
Crea o actualiza tu tailwind.config.js:
// tailwind.config.js
module.exports = {
presets: [
require('@luisvelito/tokens/tailwind-preset')
],
content: [
'./src/**/*.{html,ts}',
'./node_modules/@luisvelito/angular/**/*.{html,ts,js}',
],
darkMode: 'class',
// ... resto de tu configuración
}2. Configurar PostCSS
Crea postcss.config.js en la raíz de tu proyecto:
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};3. Importar estilos CSS
En tu src/styles.css:
/* src/styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Importar tokens del design system */
@import "@luisvelito/tokens/tokens.css";4. Usar los componentes
Los componentes son standalone, así que puedes importarlos directamente:
// app.component.ts
import { Component } from '@angular/core';
import { ButtonComponent, InputComponent, CheckboxComponent } from '@luisvelito/angular';
@Component({
selector: 'app-root',
standalone: true,
imports: [ButtonComponent, InputComponent, CheckboxComponent],
template: `
<ui-button variant="primary">Click Me</ui-button>
<ui-input placeholder="Enter text..." [(ngModel)]="value"></ui-input>
<ds-checkbox label="Accept terms" [(ngModel)]="accepted"></ds-checkbox>
`
})
export class AppComponent {
value = '';
accepted = false;
}🧩 Componentes Disponibles
⚛️ Atoms (Componentes Básicos)
Button (ui-button)
import { ButtonComponent } from '@luisvelito/angular';
@Component({
imports: [ButtonComponent],
template: `
<ui-button variant="primary" size="md">Primary</ui-button>
<ui-button variant="secondary" [loading]="true">Loading</ui-button>
<ui-button variant="destructive" [disabled]="true">Disabled</ui-button>
`
})Props:
variant:'primary' | 'secondary' | 'ghost' | 'outline' | 'destructive' | 'link'size:'sm' | 'md' | 'lg' | 'icon'loading:booleandisabled:booleanfullWidth:booleantype:'button' | 'submit' | 'reset'
Input (ui-input)
Componente de input con validación, loading, y ControlValueAccessor.
import { InputComponent } from '@luisvelito/angular';
import { FormsModule } from '@angular/forms';
@Component({
imports: [InputComponent, FormsModule],
template: `
<!-- Basic -->
<ui-input placeholder="Enter text..." [(ngModel)]="value"></ui-input>
<!-- Con validación -->
<ui-input
type="email"
placeholder="Email"
[(ngModel)]="email"
[validation]="[{ type: 'email', message: 'Invalid email' }]"
[validateOnBlur]="true"
(validationChange)="onValidate($event)"
></ui-input>
<!-- Con loading -->
<ui-input
placeholder="Loading..."
[(ngModel)]="value"
[loading]="true"
></ui-input>
<!-- Clearable con debounce -->
<ui-input
placeholder="Search..."
[(ngModel)]="search"
[clearable]="true"
[debounceMs]="300"
></ui-input>
`
})Props:
type:string- Tipo de input HTMLplaceholder:stringdisabled:booleaninvalid:booleanerror:stringfullWidth:booleanloading:booleanclearable:booleanvalidation:ValidationRule[]validateOnChange:booleanvalidateOnBlur:booleandebounceMs:numberleftIcon:booleanrightIcon:boolean
Outputs:
(validationChange): Emite{isValid: boolean, errors: string[]}
Textarea (ds-textarea)
Textarea con auto-resize y ControlValueAccessor.
import { TextareaComponent } from '@luisvelito/angular';
import { FormsModule } from '@angular/forms';
@Component({
imports: [TextareaComponent, FormsModule],
template: `
<!-- Basic -->
<ds-textarea
placeholder="Enter message..."
[(ngModel)]="message"
></ds-textarea>
<!-- Auto-resize -->
<ds-textarea
placeholder="Auto-resize textarea"
[(ngModel)]="message"
[autoResize]="true"
[minRows]="2"
[maxRows]="6"
></ds-textarea>
<!-- Non-resizable -->
<ds-textarea
placeholder="Fixed size"
[(ngModel)]="message"
[resizable]="false"
></ds-textarea>
`
})Props:
placeholder:stringdisabled:booleanreadonly:booleaninvalid:booleanerror:stringfullWidth:booleanrows:numbercols:numbermaxlength:numberautoResize:booleanminRows:numbermaxRows:numberresizable:boolean
Select (ds-select)
Select nativo mejorado con ControlValueAccessor.
import { SelectComponent, SelectOption } from '@luisvelito/angular';
import { FormsModule } from '@angular/forms';
@Component({
imports: [SelectComponent, FormsModule],
template: `
<ds-select
placeholder="Choose option..."
[options]="options"
[(ngModel)]="selected"
></ds-select>
`
})
export class MyComponent {
options: SelectOption[] = [
{ label: 'Option 1', value: '1' },
{ label: 'Option 2', value: '2' },
{ label: 'Disabled', value: '3', disabled: true },
];
selected = '';
}Props:
options:SelectOption[]- Array de{ label, value, disabled? }placeholder:stringdisabled:booleaninvalid:booleanerror:stringfullWidth:boolean
Checkbox (ds-checkbox)
Checkbox con soporte para estado indeterminado y ControlValueAccessor.
import { CheckboxComponent } from '@luisvelito/angular';
import { FormsModule } from '@angular/forms';
@Component({
imports: [CheckboxComponent, FormsModule],
template: `
<!-- Basic -->
<ds-checkbox
label="Accept terms"
[(ngModel)]="accepted"
></ds-checkbox>
<!-- Indeterminate (Select All) -->
<ds-checkbox
label="Select All"
[(ngModel)]="allSelected"
[indeterminate]="someSelected"
(ngModelChange)="handleSelectAll($event)"
></ds-checkbox>
<!-- Disabled -->
<ds-checkbox
label="Disabled"
[disabled]="true"
></ds-checkbox>
<!-- Inline -->
<ds-checkbox
label="Option 1"
[inline]="true"
[(ngModel)]="option1"
></ds-checkbox>
`
})Props:
label:stringdisabled:booleaninvalid:booleaninline:booleanindeterminate:boolean
📋 Integración con Formularios
Todos los componentes de formulario implementan ControlValueAccessor, por lo que funcionan con:
Template-driven Forms
import { FormsModule } from '@angular/forms';
import { InputComponent, CheckboxComponent } from '@luisvelito/angular';
@Component({
imports: [FormsModule, InputComponent, CheckboxComponent],
template: `
<form #form="ngForm">
<ui-input
name="email"
[(ngModel)]="user.email"
required
email
></ui-input>
<ds-checkbox
name="terms"
label="I agree"
[(ngModel)]="user.terms"
required
></ds-checkbox>
<button [disabled]="!form.valid">Submit</button>
</form>
`
})
export class MyComponent {
user = { email: '', terms: false };
}Reactive Forms
import { ReactiveFormsModule, FormBuilder, Validators } from '@angular/forms';
import { InputComponent, CheckboxComponent } from '@luisvelito/angular';
@Component({
imports: [ReactiveFormsModule, InputComponent, CheckboxComponent],
template: `
<form [formGroup]="form">
<ui-input
formControlName="email"
placeholder="Email"
></ui-input>
<ds-checkbox
formControlName="terms"
label="I agree to terms"
></ds-checkbox>
<button [disabled]="!form.valid">Submit</button>
</form>
`
})
export class MyComponent {
form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
terms: [false, Validators.requiredTrue]
});
constructor(private fb: FormBuilder) {}
}🚀 Desarrollo en el Monorepo
Si estás trabajando en el monorepo:
# Iniciar demo de Angular
npx nx serve angular-demo
# http://localhost:4202
# Compilar paquete Angular
npx nx build angular📤 Publicación a NPM
El paquete exporta componentes standalone listos para publicar:
{
"name": "@luisvelito/angular",
"version": "1.0.0",
"peerDependencies": {
"@angular/common": "^20.0.0",
"@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0",
"@luisvelito/tokens": "^1.0.0",
"tailwindcss": "^3.0.0"
}
}🎨 Personalización
Los componentes utilizan los tokens de @luisvelito/tokens. Para personalizar:
/* Tu styles.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "@luisvelito/tokens/tokens.css";
/* Sobrescribe tokens */
@layer base {
:root {
--primary: 220 90% 55%; /* Nuevo color primario */
}
}🐛 Troubleshooting
Error: "Cannot find module '@luisvelito/tokens'"
Asegúrate de haber instalado @luisvelito/tokens:
npm install @luisvelito/tokensLos estilos no se aplican
- Verifica que tengas el preset en
tailwind.config.js - Verifica que importes
@luisvelito/tokens/tokens.cssen tustyles.css - Verifica que el
contentincluyanode_modules/@luisvelito/angular/**/*.{html,ts,js}
Error de PostCSS
Asegúrate de tener postcss.config.js con Tailwind configurado.
📝 Licencia
MIT
🤝 Contribuir
Ve el README principal del monorepo para instrucciones de contribución.
📞 Soporte
Si encuentras algún problema o tienes preguntas, abre un issue en el repositorio.
