@trismegisto/primitives
v2.0.1
Published
Hermes — comportamento e lógica sem framework (foco, tema, i18n, geometria, classes).
Readme
@trismegisto/primitives
Comportamento e lógica do Hermes sem framework: stores de estado (tema, toast, abas, workspace, data
grid, árvore, kanban…), teclado e foco, posicionamento de menus e popovers, datas, máscaras, atalhos e os
catálogos de texto (pt-BR embutido, en/es à parte) com formatMessage/pluralMessage.
Na cadeia de camadas (tokens ← icons ← primitives ← core ← angular ← maps · charts · spine) é onde mora
toda regra de comportamento. O @trismegisto/angular só liga inputs e outputs a estas funções; um wrapper para
outro framework faria o mesmo.
Instalação
npm install @trismegisto/primitives @trismegisto/icons @trismegisto/tokens@trismegisto/icons e @trismegisto/tokens são peerDependencies. Num app Angular, instale os cinco pacotes base
juntos e na mesma versão (ver @trismegisto/angular).
Pontos de entrada
| Import | Conteúdo |
| --- | --- |
| @trismegisto/primitives | Tudo abaixo, mais a reexportação de @trismegisto/icons (registro e desenho de ícones) e de HERMES_FAMILIES/HermesFamily/HermesThemeName do @trismegisto/tokens |
| @trismegisto/primitives/messages/en | HERMES_MESSAGES_EN |
| @trismegisto/primitives/messages/es | HERMES_MESSAGES_ES |
Só o catálogo pt-BR (HERMES_MESSAGES_PT_BR) está na entrada principal. en e es ficam em entradas próprias
para não pesarem no bundle de quem não usa; o @trismegisto/angular os baixa sob demanda no primeiro
setLocale.
Quando usar direto
Num app Angular, quase nunca: use @trismegisto/angular, que já envolve estas funções em serviços, signals e
componentes. O uso direto faz sentido para:
- Funções utilitárias que o app chama em validadores ou formatação:
applyMask,unmask,isMaskComplete(máscarascpf/cnpj/cep/phoneou padrão),toIsoDate,formatDisplayDate,displayDatePattern,addDays,formatMessage,pluralMessage. - Overlay que o app move para o
<body>: chamecopyThemeScope(origem, nó)para o nó levardata-theme,data-family,data-densityedata-fontdo contexto (sem isso ele volta ao tema padrão). - Wrapper para outro framework: os stores (
createThemeStore,createToastStore,createShortcutRegistry,createWorkspaceStore…) e os montadores de classe CSS (buttonClass,iconButtonClass…) que geram as classeshm-*do@trismegisto/core.
Exemplo sem framework: tema
import { createThemeStore, themeHostProps, DEFAULT_THEME_CONFIG } from '@trismegisto/primitives';
const store = createThemeStore(
{ ...DEFAULT_THEME_CONFIG, storagePrefix: 'meuapp' },
{ storage: localStorage, prefersDark: () => matchMedia('(prefers-color-scheme: dark)').matches },
);
function apply(root: HTMLElement) {
const { attributes, styles } = themeHostProps(store.getState());
for (const [name, value] of Object.entries(attributes)) root.setAttribute(name, value);
for (const [name, value] of Object.entries(styles)) root.style.setProperty(name, value);
}
apply(document.body);
store.subscribe(() => apply(document.body));
store.setMode('system'); // 'light' | 'dark' | 'system'
store.setDensity('compact');themeHostProps devolve os atributos data-theme/data-family/data-density/data-font e as custom
properties de cor da família. É exatamente o que a diretiva hermesTheme do Angular aplica. As escolhas
ficam salvas no storage com o prefixo (<prefixo>_theme, <prefixo>_theme_family, <prefixo>_density…).
Exemplo: textos
import { HERMES_MESSAGES_PT_BR, formatMessage, pluralMessage } from '@trismegisto/primitives';
formatMessage('Remover {label}', { label: 'Arquivo.pdf' });
pluralMessage({ one: '{count} item', other: '{count} itens' }, 3, 'pt-BR');Texto com variável é sempre template nomeado ({nome}) e contagem é PluralMessage com
Intl.PluralRules: nunca prefixo + concatenação nem if (n === 1).
Mais
- Regras de camadas e de i18n:
CLAUDE.md§5 e §6 edocs/architecture. - Páginas "Tema" e "Idiomas" do site de documentação (
docs/website, rotas/pages/theminge/pages/i18n).
Desenvolvimento do pacote
npm test (Vitest) e npm run build (compila para dist/).
