O que traz a Akira UI 3.1.0
Etiquetas em espanhol e em português europeu, badges na sidebar, coluna de ações fixa e a correção dos filtros de tabela no Inertia 3.
Boa parte da 3.1.0 da Akira UI é para aplicações cuja interface não está em inglês. Há um pacote de etiquetas novo em espanhol, o português passou a ser português europeu do princípio ao fim, e o menu do utilizador na sidebar deixou de mostrar “Settings” e “Log out” numa interface em português.
Para quem não conhece, a Akira UI é uma biblioteca de componentes React construída sobre os primitivos do shadcn. Além de botões, diálogos e tabelas, traz shells de aplicação (sidebar, cabeçalho, menu do utilizador), blocos prontos, etiquetas por língua e um adaptador para Inertia. A 3.1.0 é uma minor sem breaking changes, por isso quem está na 3.0.0 só tem de subir a versão. Saiu agora para que a 1.0.0 do Nos-Ferry/support pudesse depender de uma versão publicada e não do branch main-dist.
Etiquetas em espanhol e em português europeu
O pacote espanhol tem a mesma forma do francês e está escrito em espanhol de Espanha:
import { UiLocaleProvider } from '@akira-io/ui';
import { esLabels } from '@akira-io/ui/locales/es';
<UiLocaleProvider labels={esLabels}>
<App />
</UiLocaleProvider>;
O português, esse, andava inconsistente. Misturava grafias anteriores ao acordo, como “Seleccione”, com formas brasileiras e do acordo, como “Selecione” e “navegador”. Como o pacote se destina a Portugal e a Cabo Verde, todas as strings seguem agora uma só grafia europeia, a anterior ao acordo (“Seleccione”, “actual”, “acção”), e há um teste que rejeita as formas brasileiras e as do acordo.
O provider também chega agora a mais sítios. O EmptyState, o DangerZone, os formulários em overlay e o editor vão buscar-lhe as etiquetas, e o mesmo acontece com o texto para leitores de ecrã dos primitivos do shadcn: o “Close” do Dialog e do Sheet, o “Go to previous page” da Pagination, o “Toggle Sidebar”, o “Previous slide”. Até aqui, quem usava leitor de ecrã numa aplicação com ptLabels continuava a ouvir esses textos em inglês. Um teste de cobertura compara agora cada pacote com o português, chave a chave, para que uma etiqueta acrescentada a um não fique a faltar noutro.
A sidebar
Um item de navegação aceita agora badge e badgeLabel. O caso típico é uma fila de reembolsos, em que quem a gere quer ver quantos estão à espera sem abrir a página:
const mainNavItems: NavItem[] = [
{ title: 'Dashboard', href: '/dashboard', icon: LayoutGrid },
{
title: 'Refunds',
href: '/refunds',
icon: Receipt,
badge: openRefundsCount,
badgeLabel: `${openRefundsCount} refunds awaiting review`,
},
];
O NavMain mostra o número encostado à direita da linha. Zero, um valor vazio ou um booleano não mostram nada, e assim uma fila sem pendentes deixa a linha limpa. De 1 a 99 aparece o número, acima disso aparece 99+. Com a sidebar reduzida aos ícones, o badge passa a ser um ponto sobre o ícone e o valor exato vai para o tooltip. O badgeLabel existe por causa dos leitores de ecrã: um “7” sozinho não diz o que está a contar, por isso a etiqueta torna-se o nome acessível da linha e o número em si fica escondido das tecnologias de apoio.
O AppSidebarHeader ganhou um slot actions, que aparece no extremo direito a seguir ao botão de pesquisa e serve para um sino de notificações ou um menu do utilizador. O adaptador de Inertia também o encaminha:
<AppSidebarHeader
breadcrumbs={breadcrumbs}
linkComponent={Link}
onSearchClick={openCommandMenu}
actions={<NotificationBell />}
/>
Quanto ao menu do utilizador, as entradas vêm agora do locale provider. Quando uma aplicação precisa de outro texto, o userMenuLabels do AppSidebar sobrepõe-se ao provider.
Três correções
A mais grave partia os filtros de tabela no Inertia 3. O hook dos filtros passava only: current.only em todas as visitas, mesmo sem only definido. O Inertia 3 lê visit.only.length, e um undefined explícito sobrepunha-se ao valor por omissão do router, de modo que a visita rebentava antes de sair qualquer pedido. A correção cabe numa linha:
// src/inertia-table-filters.ts
router.visit(current.url, {
data: toQuery({ ...current.filters, ...changes }),
...(current.only ? { only: current.only } : {}),
// …
});
A segunda era o DatePicker com dois contentores: o popover e, lá dentro, o calendário com anel e sombra próprios. A variante nested-surface existe para tirar essa segunda superfície, mas reconhecia o pai pelo data-slot, e renomear um componente com slotName substitui o data-slot. O popover do DatePicker chama-se calendar-popover, e o ConfirmDialog, o FormDialog e mais alguns perdiam o reset pelo mesmo motivo. Os cards e os conteúdos de overlay escrevem agora um atributo data-surface à parte, e é esse que a variante procura:
/* theme.css */
@custom-variant nested-surface (
&:is(
[data-surface]:not([data-inset]) *,
[data-slot='sidebar'] *,
[data-slot='data-table'] *
)
);
O painel do floating sheet também recebeu o atributo. Um teste abre cada superfície marcada com um card lá dentro, e basta tirar o atributo a uma delas para esse teste falhar.
A terceira vê-se no macOS. O overscroll elástico mostra o fundo do elemento html, que ninguém pintava, e aparecia uma faixa de outra cor por cima da sidebar inset. O novo root-background.css, importado pelo theme.css, resolve isso:
:root {
background-color: var(--background);
}
:root:has([data-slot='sidebar-wrapper'] [data-variant='inset']) {
background-color: var(--sidebar);
}
Tabelas e campos de detalhe
A última coluna da data table, onde fica o menu da linha, mantém-se fixa quando a tabela faz scroll na horizontal. Num ecrã estreito, o menu fica à mão sem ir até ao fim da linha, e a sombra sobre as colunas escondidas só aparece quando há de facto alguma coisa por trás.
No bloco info field, um valor comprido, como um endereço de email, podia empurrar o botão de copiar para fora de uma coluna estreita. O botão passou para junto da etiqueta e o valor é cortado com reticências. Para manter o layout antigo, há copyPlacement="value".
Para terminar
Numa aplicação em português ou espanhol, é com esta versão que deixa de aparecer texto em inglês pelo meio. A lista completa está nas notas da release, o pacote está no npm e a documentação está na pasta docs do repositório.