Les nouveautés d'Akira UI 3.1.0
Libellés en espagnol, badges dans la sidebar, colonne d'actions fixe, et la correction des filtres de tableau qui cassaient sous Inertia 3.
La 1.0.0 de Nos-Ferry/support devait dépendre d’une version publiée d’Akira UI, et non de la branche main-dist. J’ai donc publié la 3.1.0, qui regroupe tout ce qui s’était accumulé depuis la 3.0.0. C’est une version mineure, sans rupture de compatibilité : il suffit de changer le numéro de version.
Pour ceux qui ne la connaissent pas, Akira UI est une bibliothèque de composants React construite sur les primitives de shadcn. En plus des boutons, boîtes de dialogue et tableaux habituels, elle fournit des shells d’application (sidebar, en-tête, menu utilisateur), des blocs prêts à l’emploi, des libellés par langue et un adaptateur Inertia.
La sidebar
Un élément de navigation accepte désormais un badge et un badgeLabel. Imaginez une file de remboursements : la personne qui la gère veut voir combien de demandes attendent sans ouvrir la page.
const mainNavItems: NavItem[] = [
{ title: 'Dashboard', href: '/dashboard', icon: LayoutGrid },
{
title: 'Refunds',
href: '/refunds',
icon: Receipt,
badge: openRefundsCount,
badgeLabel: `${openRefundsCount} refunds awaiting review`,
},
];
NavMain affiche le nombre aligné à droite de la ligne. Un zéro, une valeur vide ou un booléen n’affichent rien, si bien qu’une file vide n’encombre pas la ligne. De 1 à 99, le nombre apparaît, et au-delà vous voyez 99+. Quand la sidebar est réduite à ses icônes, le badge devient un point sur l’icône et le chiffre exact passe dans l’infobulle. badgeLabel sert aux lecteurs d’écran : un « 7 » tout seul ne dit pas ce qu’il compte, alors le libellé devient le nom accessible de la ligne et le nombre lui-même est masqué aux technologies d’assistance.
AppSidebarHeader reçoit un slot actions, affiché sur le bord droit après le bouton de recherche. C’est là que se place une cloche de notifications ou un menu utilisateur, et l’adaptateur Inertia le transmet aussi :
<AppSidebarHeader
breadcrumbs={breadcrumbs}
linkComponent={Link}
onSearchClick={openCommandMenu}
actions={<NotificationBell />}
/>
Le menu utilisateur d’AppSidebar affichait « Settings » et « Log out » en anglais, sauf si vous composiez la sidebar vous-même. Ces entrées viennent maintenant du locale provider, et le userMenuLabels d’AppSidebar les remplace quand une application a besoin d’un autre texte.
Trois corrections
La plus gênante cassait les filtres de tableau sous Inertia 3. Le hook des filtres passait only: current.only à chaque visite, même sans only défini. Inertia 3 lit visit.only.length : un undefined explicite écrasait la valeur par défaut du router, et la visite levait une erreur avant qu’aucune requête ne parte. La correction tient en une ligne :
// src/inertia-table-filters.ts
router.visit(current.url, {
data: toQuery({ ...current.filters, ...changes }),
...(current.only ? { only: current.only } : {}),
// …
});
La deuxième concernait le DatePicker, qui affichait deux conteneurs : le popover, et dedans le calendrier avec son propre contour et sa propre ombre. La variante nested-surface sert justement à retirer cette seconde surface, mais elle reconnaissait le parent à son data-slot. Or renommer un composant avec slotName remplace data-slot, et le popover du DatePicker s’appelle calendar-popover. ConfirmDialog, FormDialog et quelques autres perdaient le reset de la même façon. Les cards et les contenus d’overlay portent désormais un attribut data-surface distinct, et c’est lui que la variante cible :
/* theme.css */
@custom-variant nested-surface (
&:is(
[data-surface]:not([data-inset]) *,
[data-slot='sidebar'] *,
[data-slot='data-table'] *
)
);
Le panneau du floating sheet a reçu l’attribut lui aussi. Un test ouvre chaque surface marquée avec une card à l’intérieur : si l’une d’elles perd l’attribut, ce test échoue.
La troisième se voit sur macOS. Le rebond en fin de défilement révèle le fond de l’élément html, que rien ne peignait, et une bande d’une autre couleur apparaissait au-dessus de la sidebar inset. Un nouveau fichier root-background.css, importé par theme.css, s’en charge :
:root {
background-color: var(--background);
}
:root:has([data-slot='sidebar-wrapper'] [data-variant='inset']) {
background-color: var(--sidebar);
}
Libellés en espagnol et en portugais européen
Il y a un nouveau jeu de libellés en espagnol, rédigé en espagnol d’Espagne, avec la même structure que le français :
import { UiLocaleProvider } from '@akira-io/ui';
import { esLabels } from '@akira-io/ui/locales/es';
<UiLocaleProvider labels={esLabels}>
<App />
</UiLocaleProvider>;
Le portugais, lui, mélangeait des graphies d’avant la réforme orthographique, comme « Seleccione », avec des formes brésiliennes ou d’après la réforme, comme « Selecione » et « navegador ». Comme il vise le Portugal et le Cap-Vert, toutes les chaînes suivent maintenant une seule graphie européenne, celle d’avant la réforme (« Seleccione », « actual », « acção »), et un test rejette les formes brésiliennes et celles d’après la réforme.
Le provider va aussi plus loin. EmptyState, DangerZone, les formulaires en overlay et l’éditeur y prennent leurs libellés, tout comme le texte destiné aux lecteurs d’écran des primitives shadcn : le « Close » de Dialog et Sheet, le « Go to previous page » de Pagination, « Toggle Sidebar », « Previous slide ». Avec ptLabels, un lecteur d’écran les lisait encore en anglais. Un test de couverture compare désormais chaque langue au portugais, clé par clé, pour qu’un libellé ajouté d’un côté ne manque pas de l’autre.
Tableaux et champs de détail
La dernière colonne d’une data table, celle du menu de ligne, reste fixe pendant le défilement horizontal. Sur un écran étroit, on atteint le menu sans aller au bout de la ligne, et l’ombre sur les colonnes masquées n’apparaît que lorsqu’il y a vraiment quelque chose derrière.
Dans le bloc info field, une valeur longue comme une adresse e-mail pouvait pousser le bouton de copie hors d’une colonne étroite. Le bouton se trouve maintenant à côté du libellé, et la valeur se tronque avec des points de suspension. Pour retrouver l’ancienne disposition, il y a copyPlacement="value".
Pour finir
Cette version profite surtout aux applications multilingues et à la sidebar qu’elles partagent. Le détail complet se trouve dans les notes de version, le paquet est sur npm, et la documentation est dans le dossier docs du dépôt.