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

@starterlib/ui

v0.8.0

Published

Bibliotheque de composants st-* du socle frontal starter, sur CDK et Aria.

Readme

@starterlib/ui

Composants st-* du socle frontal starter. Zoneless, signal-first, OnPush, autonomes. Ils consomment les jetons de @starterlib/tokens.

Installation

pnpm add @starterlib/ui @starterlib/tokens @starterlib/util

Les versions d'Angular, de @starterlib/tokens et de @starterlib/util sont des dependances de pair : c'est l'application qui les installe, et elles doivent etre identiques dans l'hote et dans chaque remote. Deux versions du socle dans le meme navigateur, ce sont deux jeux de jetons d'injection.

Onze points d'entree

Deux criteres, dans cet ordre.

  1. La dependance (ADR 0003) : un composant sort du tronc quand il traine un pair lourd, et le point d'entree ou il va se choisit par ce qu'il EST pour qui l'emploie.
  2. Le moment de peinture (ADR 0031, 0.8.0) : a dependance egale, ce que l'hote ne peint pas sort aussi. Un paquet partage en singleton part ENTIER — la federation annule l'elagage —, donc ce que la coquille n'affiche jamais lui coute plein tarif au premier ecran, et ne coute RIEN au remote qui l'affiche, puisque le tronc y est deja charge.

| Point d'entree | Contenu | Pairs lourds importes statiquement | | ---------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | | @starterlib/ui | le TRONC : noyau, icone, texte, actions, etats, retour, indicateurs, structure, transverses, st-code | aucun | | @starterlib/ui/saisie | les champs de formulaire, le calendrier, le televersement | aucun (des TYPES d'@angular/forms) | | @starterlib/ui/listes | liste, liste de description, table de donnees, pagination, tri, filtres | aucun | | @starterlib/ui/donnees | montant, date, date relative, nombre, valeur masquee, indicateur chiffre | aucun | | @starterlib/ui/libelles-en | le catalogue anglais | aucun | | @starterlib/ui/surfaces | ce qui se pose AU-DESSUS de la page : menu, dialogues, tiroirs, messages ephemeres | @angular/cdk/{a11y,dialog,keycodes,overlay,portal}, @angular/aria/menu | | @starterlib/ui/navigation | la navigation laterale | @angular/cdk/layout — et rien d'autre | | @starterlib/ui/onglets | les onglets et leurs panneaux | @angular/aria/tabs | | @starterlib/ui/selection | liste deroulante filtrante, choix multiple | @angular/aria/{combobox,listbox}, @angular/cdk/overlay | | @starterlib/ui/arbre | l'arborescence | @angular/aria/tree | | @starterlib/ui/formulaires | les champs qui LISENT leur saisie : montant, date, plage de dates | le code d'@angular/forms (transformedValue) |

import { StButton, StCard, StError } from '@starterlib/ui';
import { StFormField, StInput, StSelect } from '@starterlib/ui/saisie';
import { StDataTable, StPagination } from '@starterlib/ui/listes';
import { StMoney, StDate } from '@starterlib/ui/donnees';
import { StDialog, StToast } from '@starterlib/ui/surfaces';
import { StSidenav } from '@starterlib/ui/navigation';
import { StTabs } from '@starterlib/ui/onglets';
import { StCombobox, StMultiselect } from '@starterlib/ui/selection';
import { StTree } from '@starterlib/ui/arbre';
import { StAmountField, StDateField } from '@starterlib/ui/formulaires';

Les aretes internes admises, et elles seules : saisie, listes, donnees, surfaces, navigation et arbre importent le tronc ; formulaires et selection importent en plus saisie, parce qu'une liste deroulante et un champ de montant sont d'abord des CHAMPS. navigation atteint surfaces par import() seulement : le dialogue du tiroir ne pese pas sur le premier rendu.

Ce qui reste des anciens specificateurs

@starterlib/ui/interactions survit, deprecie, comme baril de re-exports vers navigation, onglets, selection et arbre : un remote reste en 0.7.x recoit la MEME CLASSE que l'hote, et la migration se fait service par service. ⚠️ Ce qui s'importe du baril pese les quatre familles.

Le tronc, lui, ne re-exporte pas saisie, listes, donnees ni libelles-en : ces points d'entree importent le tronc, et un tronc qui les re-exporterait fermerait un cycle entre points d'entree que ng-packagr refuse. Monter en 0.8.0 demande donc de deplacer ces imports-la, et rien d'autre.

⚠️ Un paquet partage en federation ne s'elague pas : declare singleton, il est charge en entier des qu'un remote le reference. Le decoupage ne vise donc pas l'elagage, mais l'unite de CHARGEMENT — et le train de singletons : une application qui n'affiche ni menu, ni dialogue, ni onglets ne charge ni le CDK ni Aria, et n'a pas a se redeployer quand ils montent de version.

@angular/cdk, @angular/aria et @angular/forms sont des pairs optionnels : le tronc n'en importe que des TYPES. Ils deviennent obligatoires des le premier import d'un point d'entree secondaire qui les emploie, et leur absence se voit alors a la resolution, pas a l'execution. ⚠️ @angular/aria exige @angular/cdk a la version EXACTE : les deux montent ensemble.

Ce que chaque point d'entree importe a l'execution est verifie sur le paquet construit (pnpm paquets:check), au specificateur exact : navigation a droit a @angular/cdk/layout, et un @angular/cdk/overlay qui s'y glisserait echoue avant la publication. Une regle non outillee est une opinion.

⚠️ En federation, chaque point d'entree se partage SEPAREMENT. Ce sont onze specificateurs de module distincts : partager @starterlib/ui ne couvre aucun des dix autres. Omis de la configuration, chaque remote en embarque sa propre copie — et la regle singleton: true, strictVersion: true qui protege le tronc ne protege plus rien au-dessus. Le decoupage achete l'independance de CHARGEMENT, jamais celle de VERSION : les onze portent le numero de leur paquet.

// federation.config.mjs de l'hote ET de chaque remote
import { partageDuSocle } from '@starterlib/core/federation';

shared: { ...share({ ...ANGULAR_ET_RXJS, ...partageDuSocle('0.8') }) }

⚠️ Cette liste ne se recopie plus. Depuis la 0.8.0 elle est publiee par @starterlib/core/federation : partageDuSocle(train) rend les seize specificateurs du socle — les onze de ui, le baril deprecie, tokens, util, core et core/federation —, chacun en singleton: true, strictVersion: true, includeSecondaries: false. La raison n'est pas la commodite : une ligne oubliee n'est pas une erreur de construction, le specificateur se duplique simplement dans le remote, avec son etat. Passer de quatre a douze specificateurs ui en recopiant aurait multiplie par trois les occasions de cet oubli.

⚠️ Partager un point d'entree que personne n'importe coute zero octet : il n'entre dans aucune carte d'importation. La liste est donc exhaustive sans arbitrage — c'est l'IMPORT qui coute, jamais le partage.

Voir docs/adr/0003-points-d-entree-decoupes-par-dependance.md, docs/adr/0004-le-tronc-est-dimensionne-par-le-premier-ecran-de-l-hote.md, docs/recettes/federation.md, et l'ADR 0031 du socle backend.

Configuration — une fois, dans l'hote

import { provideStarterUi, LIBELLES_FR } from '@starterlib/ui';

export const appConfig: ApplicationConfig = {
  providers: [
    provideStarterUi({
      cheminDuSprite: '/ui/socle/assets/icones/sprite.svg',
      locale, // Signal<string> : les formats suivent la langue a chaud
      libelles, // Signal<LibellesUi> : LIBELLES_FR, LIBELLES_EN, ou le votre
      fuseau: 'Europe/Paris',
    }),
  ],
};

⚠️ Dans l'hote uniquement. Un remote qui la rappellerait poserait un second jeu de valeurs dans son injecteur de route : deux locales, deux dictionnaires, et la moitie de l'ecran resterait dans l'ancienne langue apres une bascule.

Sans configuration, les composants prennent LOCALE_ID et le francais. C'est un depannage, pas une i18n : une application bilingue doit fournir des signaux, sinon la bascule de langue ne touche pas les composants du socle.

Sprite d'icones — a cabler avant le premier rendu

st-icon lit un sprite SVG servi en meme origine. Le paquet livre l'actif, l'application le sert et en donne le chemin. Aucun chemin par defaut : une reference use qui ne resout pas ne leve rien, et toutes les icones resteraient vides en silence.

angular.json, cible build :

"assets": [
  {
    "glob": "sprite.svg",
    "input": "node_modules/@starterlib/ui/assets/icones",
    "output": "assets/icones",
  },
]

app.config.ts :

import { fournirCheminDuSprite } from '@starterlib/ui';

export const appConfig: ApplicationConfig = {
  providers: [fournirCheminDuSprite('/ui/socle/assets/icones/sprite.svg')],
};

Le prefixe est celui sous lequel l'interface est servie (/ui/<interface>/). Un chemin empreinte (sprite.<hash>.svg) donne un cache immuable.

Feuille de jetons

Les composants ne portent aucune couleur en dur : ils lisent les variables CSS de @starterlib/tokens. Sans la feuille, tout s'affiche sans style.

@import '@starterlib/tokens/styles/starter-tokens.css';

Ce qui est livre

Vague 1 : etats (st-spinner, st-skeleton, st-empty, st-error, st-offline-banner, st-progress, st-state), texte (st-text, st-heading), donnees (st-money, st-date, st-relative-time, st-masked, st-count — passes sous ui/donnees en 0.8.0 ; st-code reste au tronc), actions (st-button, st-icon-button, st-link, st-button-group), indicateurs (st-badge, st-status-pill, st-tag, st-avatar), iconographie (st-icon). st-menu est passe sous ui/surfaces.

Vague 2 :

  • Tronc — structure (st-app-shell, st-header, st-skip-link, st-page-title, st-breadcrumb, st-section, st-card, st-divider), retour (st-banner, st-inline-message), transverses (st-theme-toggle, st-lang-switch, st-copy-button, st-timer, st-logo).
  • ui/surfacesStDialog (dialogue, tiroir, feuille inferieure), StConfirmDialog, StToast, st-idle-warning, stTooltip, st-popover.
  • ui/ongletsst-tabs, st-tab-panel, stTabContent ; ui/navigationst-sidenav, stSidenavToggle (tous trois sous ui/interactions avant la 0.8.0).

Vague 3 — la saisie, sur Signal Forms :

  • ui/saisie (le tronc avant la 0.8.0) — st-form-field, st-input, st-textarea, st-fieldset, st-checkbox, st-radio-group, st-switch, st-error-summary, st-password-field, st-otp-field, st-search-field, st-iban-field, st-phone-field, st-select (natif), st-file-upload, st-calendar ; messages d'erreur traduits et fonctions de schema (erreurIban, erreurTelephone, erreurDate, erreurPlageDeDates, erreursDeFichiers).
  • ui/selectionst-combobox, st-multiselect.
  • ui/formulairesst-amount-field, st-date-field, st-date-range.

Un champ s'emploie avec un formulaire, par [formField], ou seul, par [(value)]. Les regles d'un schema sont des fonctions PURES du socle, a brancher par validate : les fournir toutes faites importerait le code d'@angular/forms a l'execution dans ui/saisie.

readonly virement = form(this.modele, (chemin) => {
  required(chemin.beneficiaire);
  validate(chemin.iban, ({ value }) => erreurIban(value()));
  validate(chemin.execution, ({ value }) => erreurDate(value(), { min: aujourdHui }));
});

Vague 4 — listes et tableaux, au contrat du backend (curseur vers l'avant, sans total ni tri serveur) :

  • ui/listes (le tronc avant la 0.8.0) — st-data-table (stCellule, stTableauVide, stActionsDeTableau), st-sort-header, st-pagination, st-list (stElementDeListe), st-description-list (stDescription), st-filter-bar, st-filter-chip.
  • ui/arbrest-tree.
  • @starterlib/coreNavigationParCurseur ; @starterlib/utilPageParCurseur<T>.
readonly navigation = new NavigationParCurseur();
readonly page = httpResource<PageParCurseur<Expedition>>(() => ({
  url: '/api/v1/expeditions',
  params: this.navigation.parametres(),
}));
<st-data-table
  #tableau
  legende="Expeditions"
  cle="id"
  [colonnes]="colonnes"
  [lignes]="page.value()?.content ?? []"
  [chargement]="page.isLoading()"
>
  <ng-template stCellule="reference" [stCelluleDe]="page.value()?.content" let-ligne>
    <a [routerLink]="['/expeditions', ligne.id]">{{ ligne.reference }}</a>
  </ng-template>
</st-data-table>
<st-pagination
  [cible]="tableau"
  [numero]="navigation.numeroDePage()"
  [precedenteDisponible]="navigation.precedenteDisponible()"
  [suivanteDisponible]="page.value()?.hasMore ?? false"
  [chargement]="page.isLoading()"
  (precedente)="navigation.precedente()"
  (suivante)="navigation.suivante(page.value())"
/>

Phase 0 de la coquille (plan de la phase 2 des interfaces, lots S05, S13, S14, S17) — ce que la coquille et les remotes assemblent :

  • Tronc, structurest-app-shell (emplacement bannieres, hauteur de l'en-tete mesuree et posee sur <html> pour scroll-padding, impression, zone sure), st-footer (mentions, version, statut), stNavLink (routerLink + aria-current="page", icone et pastille), st-page-header (fil, h1, actions, onglets), st-route-progress (barre fine, rien avant 200 ms), st-auth-shell (gabarit pleine page), st-stepper (ol, aria-current="step"), st-settings-row (groupe nomme et decrit).
  • Tronc, actions et donneesst-form-actions (barre collee en bas, jamais fixee), st-stat (tendance par forme et texte).
  • ui/surfacesst-toolbar (une action principale, les secondaires repliees dans un menu « Plus » sous md).
  • st-iconsprite et nomMetier pour les icones d'un remote (docs/recettes/sprite-d-icones.md, section 7) ; st-progress prend une epaisseur fine.
  • Feuilles — chaque :hover sous @media (hover: hover), les points de rupture lus dans le partiel _ruptures.scss de @starterlib/tokens (@include st.depuis('lg')), gardes dans styles/gardes-de-feuille.spec.ts.

Inventaire et regles de la suite : docs/plan-librairie.md et les audits de vague (docs/audit-vague-2-…, -3-…, -4-2026-09-17.md) du depot.

Ce que le banc en vrai navigateur verifie

Le depot mesure ses composants dans Chromium (pnpm test:navigateur), parce que jsdom ne calcule ni mise en page ni cascade :

  • contraste reel de chaque texte, dans les DEUX themes ;
  • taille de chaque cible de pointage (24 px au moins, WCAG 2.5.8) ;
  • anneau de focus a chaque arret de tabulation, au VRAI clavier, et son contraste contre ce qui l'entoure ;
  • encre de chaque icone, lue par le moteur de rendu, dans une zone sure commune.

Voir docs/audit-design-2026-09-17.md pour ce que ces mesures ont corrige.

Regles tenues par les composants

  • Un statut se lit par une icone et un texte, jamais par la couleur seule.
  • Aucun acces a window ni document hors afterNextRender : le rendu serveur reste possible sans reecriture.
  • Aucun style en ligne : la politique de securite du contenu a nonce l'interdit.
  • Aucun stockage navigateur.