@heroelc/fsociety
v0.19.0
Published
Angular component library with design system tokens, mixins and UI components
Maintainers
Readme
fsociety
Angular component library · Design system con tokens, mixins y componentes UI
📖 La documentación de cada componente — props, ejemplos y playground interactivo — vive en el Storybook. Este README cubre lo que hay que hacer una sola vez: instalar y configurar.
Instalación
npm install @heroelc/fsocietyPrerrequisitos
- Angular 19+
- Node 18+
- SCSS habilitado en el proyecto
Setup rápido
1. Cargar los estilos en styles.scss
// src/styles.scss de tu app Angular
@use '@heroelc/fsociety/styles';Esa línea es todo lo que necesitás. Emite:
- La paleta completa como CSS custom properties (
--fs-primary-base,--fs-primary-hover, …) en:root. - La capa semántica (
--fs-color-surface,--fs-color-text-primary,--fs-color-border, …), que es la que hace que los componentes tengan color y que responden al tema activo. - La utilidad
.fs-icon, que todos los iconos de la librería usan víamask-image. - Las clases utilitarias (
flex-center,pl-6,truncate, …).
No alcanza con importar solo
styles/tokens. La capa semántica y.fs-iconviven enstyles/global, y 17 stylesheets de componentes dependen de ellas. Sin eso los componentes se renderizan sin fondo, sin bordes y con los iconos invisibles.
Si preferís control granular, los entry points son:
| Entry point | Qué trae |
|---|---|
| @heroelc/fsociety/styles | todo lo de abajo |
| @heroelc/fsociety/styles/tokens | paleta, radios, espaciados, tipografía |
| @heroelc/fsociety/styles/global | capa semántica --fs-color-*, .fs-icon, box-sizing |
| @heroelc/fsociety/styles/mixins | mixins SCSS + clases utilitarias |
| @heroelc/fsociety/styles/control-size | escala de tamaño de los controles (no emite CSS) |
| @heroelc/fsociety/styles/overlay | solo el mixin popover-surface (no emite CSS) |
2. Elegir el tema
Los componentes siguen el atributo data-theme en la raíz del documento:
<html data-theme="dark">Sin el atributo, se usa el tema claro. La librería no mira prefers-color-scheme, a propósito: el tema lo decide la app, en un solo lugar, y las dos capas de tokens — la de marca y la semántica — siempre coinciden.
Para seguir al sistema operativo, la app lo pide y además decide cuándo:
const dark = matchMedia('(prefers-color-scheme: dark)');
const apply = () =>
(document.documentElement.dataset['theme'] = dark.matches ? 'dark' : 'light');
apply();
dark.addEventListener('change', apply);3. Cargar las tipografías
La librería nombra tipografías pero no las incluye. No hay ningún @font-face adentro del paquete, así que si no las cargás vos, todo cae al fallback de la stack y nadie avisa:
| Dónde | Qué pide |
|---|---|
| body (en styles/global) | Plus Jakarta Sans |
| --fs-font-sans | Inter |
| --fs-font-mono | JetBrains Mono |
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Inter:wght@400;500;600&display=swap"
rel="stylesheet"
>O self-hosteadas, o las que quieras: pisá --fs-font-sans y la stack cambia entera.
4. Importar componentes
Los componentes son standalone — se importan directo en el imports del componente:
import { FsButtonComponent } from '@heroelc/fsociety';
@Component({
standalone: true,
imports: [FsButtonComponent],
template: `<fs-button variant="primary">Guardar</fs-button>`
})
export class MyComponent {}Componentes
Cada link abre el playground con los props documentados y editables.
Formulario
| | | |
|---|---|---|
| fs-input | campo de texto | password, search, clear, estados |
| fs-textarea | texto multilínea | autogrow, contador |
| fs-number-input | numérico con steppers | min/max, prefijo y sufijo |
| fs-select | selección simple | búsqueda, íconos, descripciones |
| fs-multi-select | selección múltiple | chips, máximo |
| fs-date-picker | fecha | calendario, locale, min/max |
| fs-date-range-picker | rango de fechas | presets, span máximo |
| fs-otp | código de verificación | pegado inteligente |
| fs-slider | valor en un rango | marcas, valor visible |
| fs-rating | puntuación | medias estrellas |
| fs-file-upload | carga de archivos | drag & drop, validación |
| fs-checkbox | casilla | indeterminado |
| fs-radio-group | opción única | descripciones por opción |
| fs-switch | interruptor | |
| fs-segmented | control segmentado | íconos |
| fs-hint, fs-field | ayuda y wrapper de campo | tonos |
Todos implementan ControlValueAccessor: andan con [(ngModel)] y con formControlName.
Acción y estado
| | | |
|---|---|---|
| fs-button | botón | 6 variantes, loading, icon-only |
| fs-badge | etiqueta | color custom, removible |
| fs-alert | mensaje en bloque | tonos, cerrable |
| FsToastService | notificaciones | stack, autodismiss |
| fs-tooltip | tooltip | 4 lados |
| fs-empty-state | estado vacío | 3 tamaños, tono de error |
| fs-skeleton | placeholder de carga | variantes |
| fs-spinner | spinner | 3 tamaños |
| fs-progress | barra de progreso | indeterminado |
Layout y navegación
| | | |
|---|---|---|
| fs-tabs | pestañas | indicador animado |
| fs-steps | pasos | horizontal y vertical |
| fs-accordion | acordeón | single y multiple |
| fs-divider | separador | con label o ícono |
| fs-card, fs-row-card, fs-stat-card | superficies | tonos, métricas |
| fs-carousel | carrusel | autoplay, loop |
| fs-breadcrumbs | migas de pan | colapso automático |
Datos
| | | |
|---|---|---|
| fs-table | tabla | orden, filtros por columna, densidad, vista mobile en tarjetas |
Overlays
| | | |
|---|---|---|
| fs-modal | modal | <dialog> nativo |
| fs-drawer | panel lateral | 4 lados |
| fs-menu | menú de acciones | teclado completo, separadores |
| [fsAnchoredPopover] | directiva | ancla un panel al top layer |
[fsAnchoredPopover]es la pieza sobre la que se apoyanfs-select,fs-multi-select,fs-date-pickeryfs-menu.position: fixedno alcanza para escapar de un contenedor: cualquier ancestro contransform,filter,backdrop-filter,containowill-changese vuelve el bloque contenedor y recorta el panel. La directiva usa la Popover API, que pinta en el top layer y no puede ser recortado por ningúnoverflow. Su docblock en el.d.tstiene la explicación completa.
Compositions
Componentes acoplados a un dominio, no primitivas.
| | |
|---|---|
| fs-experience-card | experiencia laboral |
| fs-profile-card | perfil con stats y links |
Foundations
Páginas del Storybook, no componentes: Branding (probá colores de marca en vivo y copiá el snippet), Tokens y Mixins.
Sistema de tokens
--fs-{color}-muted // 50 — badge bg, chip, alert sutil
--fs-{color}-subtle // 100 — ghost hover bg
--fs-{color}-tint // 200 — selected bg, focus fill
--fs-{color}-light // 300 — borders sobre fondos claros
--fs-{color}-soft // 400 — íconos, disabled
--fs-{color}-base // 500 — color principal
--fs-{color}-hover // 600 — hover en solid buttons
--fs-{color}-active // 700 — pressed
--fs-{color}-emphasis // 800 — texto sobre mismo color
--fs-{color}-contrast // 900 — texto dark sobre tint/mutedColores: primary · secondary · tertiary · neutral · success · warning · danger
Capa semántica
Encima de la paleta hay tokens que describen rol, no color, y son los que consumen los componentes. Son los que cambian con data-theme:
--fs-color-bg // fondo de página
--fs-color-surface // superficie elevada (cards, campos, menús)
--fs-color-surface-alt // superficie secundaria (hover de filas)
--fs-color-text-primary // texto principal
--fs-color-text-secondary // texto secundario
--fs-color-text-placeholder // placeholders
--fs-color-border // bordes
--fs-color-border-field // bordes de campos de formulario
--fs-color-border-strong // bordes en hover
--fs-color-primary // color de marca activo
--fs-color-error · --fs-color-success · --fs-color-warning
--fs-color-shadow-pop // sombra de menús y popoversCambiar la marca
@use '@heroelc/fsociety/styles' with (
$fs-primary-hex: #7c3aed,
$fs-secondary-hex: #0891b2,
$fs-tertiary-hex: #0d9488,
);Sass recalcula las diez paradas de cada escala en build time. Las familias configurables son $fs-primary-hex, $fs-secondary-hex, $fs-tertiary-hex, $fs-neutral-hex, $fs-success-hex, $fs-warning-hex y $fs-danger-hex.
Probá colores en vivo antes de decidir: la página Foundations → Branding del Storybook recalcula el sistema entero al instante y te da este mismo snippet listo para copiar.
Tamaño de los controles
Todos los controles de formulario comparten una sola escala de alto, y el botón también. Un fs-button y un fs-input con el mismo size miden exactamente lo mismo, así que quedan parejos al ponerlos uno al lado del otro.
| size | Alto | Fuente |
|---|---|---|
| sm | 32px | 13px |
| md (default) | 40px | 14px |
| lg | 48px | 16px |
Lo aceptan fs-button, fs-input, fs-select, fs-multi-select, fs-textarea, fs-number-input, fs-date-picker, fs-date-range-picker, fs-checkbox y fs-radio-group.
Para construir un control propio que alinee con los de la librería:
@use '@heroelc/fsociety/styles/control-size' as size;
@include size.scale('.mi-control');
.mi-control__shell {
height: var(--fs-control-h);
padding: 0 var(--fs-control-pad-x);
font-size: var(--fs-control-font);
}El mixin emite las custom properties --fs-control-* por data-size, así que el componente tiene que bindear [attr.data-size]="size" en su raíz.
lgusa 16px de fuente y no 15 a propósito: Safari en iOS hace zoom al enfocar un input con menos de 16px.
Todo componente que lea
--fs-control-*tiene que incluirscale()sobre su propia raíz. Las custom properties heredan, así que sin eso un control anidado dentro de otro tomaría la escala del padre.
Redondeo por componente
El input corners elige qué esquinas van redondeadas. Sirve para apoyar un componente contra otro sin que quede una esquina redonda adentro de otra:
<fs-card corners="top">
<fs-input corners="bottom"></fs-input>
</fs-card>FsCorners es 'all' | 'none' | 'top' | 'bottom' | 'start' | 'end'.
startyendson lógicas, noleft/right: siguen la dirección de escritura, así que en RTL se dan vuelta solas.
La custom property de radio de cada componente cambia cuánto redondea:
<fs-input style="--fs-input-radius: 0"></fs-input>
<fs-card style="--fs-card-radius: 16px"></fs-card>Acepta el shorthand entero de border-radius, pero solo con corners="all": los otros presets apagan esquinas puntuales con longhands y pisarían el shorthand.
Mixins y utilidades
@use '@heroelc/fsociety/styles/mixins' as m;
.mi-componente {
@include m.flex-center;
@include m.px(4); // padding-left + right: 16px
@include m.stack(16px); // flex-col + gap
@include m.truncate;
@include m.respond-to('md') {
@include m.flex-between;
}
}O con clases utilitarias directamente en el HTML:
<div class="flex-between px-6 py-4 gap-4">
<span class="truncate-2 text-sm font-medium">...</span>
<span class="uppercase-label">Frontend Developer</span>
</div>Breakpoints: sm 640px · md 768px · lg 1024px · xl 1280px · xxl 1536px
Contribuir
El código vive en github.com/HeroelC/fsociety. Ahí está el detalle de cómo levantar el proyecto, correr Storybook y publicar.
Licencia
MIT © Heroel Carpinetti
