germinastack-ui-components
v1.0.6
Published
Componentes HTML, CSS e JavaScript vanilla para interfaces GerminaStack.
Downloads
688
Maintainers
Readme
GerminaStack UI Components
Kit de componentes em HTML, CSS e JavaScript vanilla. Sem framework; o Rollup gera os arquivos públicos em dist/.
Começando agora? Leia o guia para iniciantes. Antes de produção, leia o guia de segurança.
Instalação
npm install germinastack-ui-componentsBundler
import "germinastack-ui-components/styles.css";
import { Button, Card, ui } from "germinastack-ui-components";
document.body.append(Card("Conteúdo"), Button({ label: "Continuar" }));
ui.showToast({ title: "Pronto", message: "Kit carregado." });O runtime é exposto como window.GerminaStackUI. Para markup inserido depois do carregamento, inicialize apenas o novo escopo:
window.GerminaStackUI.init(document.querySelector("#nova-area"));HTML sem bundler
Depois de copiar os arquivos para uma pasta pública, use os caminhos públicos — nunca node_modules diretamente:
<link rel="stylesheet" href="/static/vendor/germinastack/css/germinastack.css" />
<script src="/static/vendor/germinastack/js/germinastack.js" defer></script>O runtime fica em window.GerminaStackUI; os exemplos Button e Card ficam em window.GerminaStack.
Projeto estático com postinstall
Instale o pacote e coloque este script no package.json do projeto consumidor:
{
"scripts": {
"postinstall": "node ./node_modules/germinastack-ui-components/scripts/copy-to-static.mjs ./static/vendor/germinastack"
}
}Depois de npm install ou npm update, os arquivos vão para static/vendor/germinastack. O CSS já encontra a fonte em fonts/ nessa mesma pasta.
Uso mínimo
<main class="gs-page">
<section class="gs-card">
<h1>Título</h1>
<button class="gs-btn gs-btn-primary" type="button">Continuar</button>
</section>
</main>O único stylesheet, germinastack.css, inclui contratos e aparência padrão. Para personalizar, sobrescreva os tokens --gs-* após o import.
Leitura confortável
O modo opt-in gs-readable usa a fonte local OpenDyslexic e espaçamento maior para conteúdos longos:
<article class="gs-readable" data-gs-letter-spacing="wide">
<h2>Conteúdo para leitura</h2>
<p>O espaçamento pode ser normal ou wide.</p>
</article>A fonte e sua licença acompanham o pacote; não há requisição a CDN.
Temas de produto opcionais
Importe o tema depois do stylesheet base e escolha os atributos no elemento <html>:
import "germinastack-ui-components/styles.css";
import "germinastack-ui-components/themes.css";
document.documentElement.dataset.tema = "dark";
document.documentElement.dataset.fonte = "open_dyslexic";
document.documentElement.dataset.espacamento = "grande";
document.documentElement.dataset.tamanho = "grande";Temas disponíveis: normal, dark, high_contrast, black_yellow e yellow_black. Fontes: normal, arial, verdana, lexend, atkinson_hyperlegible e open_dyslexic. Espaçamento (data-espacamento): normal, pequeno e grande — ajusta letter-spacing/word-spacing do texto corrido. Tamanho (data-tamanho): normal, pequeno e grande — escala a página inteira via zoom (ver comentário em src/themes/product-themes.css sobre por que não é baseado em rem).
Em HTML estático, inclua themes.css depois de germinastack.css:
<html data-tema="dark" data-fonte="open_dyslexic" data-espacamento="grande" data-tamanho="grande">
<head>
<link rel="stylesheet" href="/static/vendor/germinastack/css/germinastack.css" />
<link rel="stylesheet" href="/static/vendor/germinastack/themes.css" />
</head>Popover de notificações (opcional)
Mesmo princípio de themes.css: um extra específico do produto GerminaStack, fora do
kit, importado só por quem usa o popover de notificações do cabeçalho (classes
.gs-notif-*). Reaproveita o menu contextual do kit (.gs-menu / .gs-menu-panel) só
para dar mais largura e rolagem ao painel — sem isso, o popover funciona com o tamanho
padrão do kit (240px, sem teto de altura).
import "germinastack-ui-components/styles.css";
import "germinastack-ui-components/notifications.css";Em HTML estático:
<link rel="stylesheet" href="/static/vendor/germinastack/css/germinastack.css" />
<link rel="stylesheet" href="/static/vendor/germinastack/notifications.css" />Publicação
npm login
npm run check
npm publishO nome germinastack-ui-components estava disponível no registry no momento da preparação. O prepublishOnly executa as validações antes do publish.
Publicação automática pelo GitHub Actions
O workflow publish.yml roda após merge na main. Ele valida o pacote e publica somente quando a versão de package.json ainda não existe no npm.
Antes do primeiro merge, configure o Trusted Publisher no npm para o pacote:
- npmjs.com → pacote → Settings → Trusted Publisher → GitHub Actions.
- Owner:
Nicolas25vlad; Repository:germinastack-ui-components; Workflow:publish.yml. - Autorize a ação
npm publish.
Isso usa OIDC e não exige salvar token npm no GitHub. Para lançar uma versão, altere version em uma PR e faça o merge depois do CI e da aprovação.
Estrutura do projeto
src/ # onde o time edita
css/
01-foundations.css # tokens, reset e acessibilidade global
02-layout.css # grid, página e navegação
03-actions-and-surfaces.css
04-content-and-forms.css
05-feedback-and-docs.css
06-advanced-components.css
07-theme.css # aparência final e overrides
js/
germinastack.js # runtime do kit
docs.js # apenas para a página de documentação
components/
Button.js
Card.js
themes/ # extras opcionais do produto, fora do kit
product-themes.css # -> dist/themes.css
product-notifications.css # -> dist/notifications.css
fonts/
OpenDyslexic-Regular.woff2
index.js # entrada ESM
dist/ # gerado; é o que aplicações e npm consomem
rollup.config.mjs # gera UMD, ESM, CSS e fontes
scripts/copy-to-static.mjs
index.html # documentação viva
playground.html # validação visualEdite somente src/, rode npm run build e nunca altere dist/ manualmente.
O que o kit cobre hoje
- hero, topbar, cards, sidebar e blocos de conteúdo
- botões, chips, badges e segmentado
- composer, inputs, textarea, select e comentário inline
- post, comentários, reply e menu contextual
- métricas, progresso, timeline, tabela, callout e empty state
- accordion, modal, toast, banner e alert
- pricing cards e blocos de showcase
- select/combobox com busca, grupos e navegação por teclado
- date picker / date range picker com calendário acessível
- data table com ordenação, filtro, paginação e seleção de linhas
- tooltip / popover com posicionamento automático e conteúdo rico
Bootstrap mínimo
<link rel="stylesheet" href="./dist/css/germinastack.css" />
<script src="./dist/js/germinastack.js" defer></script>
<main class="gs-page">
<section class="gs-card">Conteúdo</section>
</main>Fluxo recomendado para o time
- Validar visualmente o componente ou layout em
playground.html. - Consultar
index.htmlpara pegar markup, classes e contratos de comportamento. - Copiar o bloco necessário para a tela real.
- Ajustar conteúdo, dados e tokens.
- Criar JS específico do produto fora do kit quando a interação deixar de ser genérica.
Convenções
- prefixo CSS:
gs- - prefixo de comportamento:
data-gs-* - customização preferencial: sobrescrever tokens, não duplicar componente
- regra de negócio: fora do kit
- responsividade: reduzir colunas antes de mexer em tipografia e spacing
Contratos JS disponíveis
window.GerminaStackUI.init(root)Inicializa um escopo novo quando markup é inserido dinamicamente (tabs, menus, toasts, dismiss, accordion, selects, datepickers, datatables, tooltips).window.GerminaStackUI.validateAccessibility(root)Marca e informa imagens semalt, campos sem label/nome e botões ou links sem nome acessível.window.GerminaStackUI.showToast({ title, message, tone, duration })Dispara toast programaticamente.window.GerminaStackUI.request(url, options)Consome uma API JSON com serialização de body e erros HTTP normalizados.window.GerminaStackUI.closeMenus()Fecha todos os menus contextuais abertos.window.GerminaStackUI.openModal(modalEl)Abre modal com armadilha de foco e anúncio.window.GerminaStackUI.closeModal(modalEl)Fecha modal com restauração de foco.window.GerminaStackUI.activateTab(tabBtn)Ativa uma tab programaticamente.window.GerminaStackUI.toggleAccordion(triggerBtn)Alterna accordion com anúncio para leitor de tela.window.GerminaStackUI.announceToScreenReader(message, priority)Anuncia mensagem via região ao vivo ("polite"|"assertive").window.GerminaStackUI.trapFocus(element)Ativa armadilha de foco em um elemento (usado internamente por modais).window.GerminaStackUI.initSelects(root)Inicializa selects/combobox com busca, grupos e navegação por teclado.window.GerminaStackUI.initDatePickers(root)Inicializa date pickers e range pickers com calendário acessível.window.GerminaStackUI.initDataTables(root)Inicializa data tables com ordenação, filtro, paginação e seleção.window.GerminaStackUI.initTooltips(root)Inicializa tooltips e popovers com posicionamento automático.
Receitas práticas
Tela nova
- Comece por
gs-page. - Estruture com
gs-stack,gs-grid-2,gs-grid-3ougs-grid-4. - Use
gs-card,gs-side-card,gs-showcase-cardegs-postcomo blocos principais.
Dashboard
- Abra com
gs-metric-grid. - Adicione
gs-progress,gs-kpi-stripegs-table. - Se houver sequência temporal, encaixe
gs-timeline.
Interações
- tabs:
data-gs-tabs,data-gs-tab,data-gs-panel - menu:
data-gs-menu,data-gs-menu-trigger,data-gs-menu-panel - modal:
data-gs-modal-open,data-gs-modal,data-gs-modal-close - accordion:
data-gs-accordion-item,data-gs-accordion-trigger,data-gs-accordion-panel - feedback rápido:
data-gs-toastouGerminaStackUI.showToast(...) - select/combobox:
data-gs-select,data-gs-select-search,data-gs-select-placeholder,data-gs-select-multiple - date picker:
data-gs-datepicker,data-gs-datepicker-range,data-gs-datepicker-placeholder - data table:
data-gs-datatable,data-gs-datatable-sort,data-gs-datatable-filter,data-gs-datatable-paginate,data-gs-datatable-page-size - tooltip:
data-gs-tooltip,data-gs-tooltip-content,data-gs-tooltip-placement - popover:
data-gs-popover,data-gs-popover-trigger,data-gs-popover-title,data-gs-popover-content
Novos componentes (v1.2)
Select / Combobox
<div class="gs-select" data-gs-select data-gs-select-search data-gs-select-placeholder="Selecione...">
<button class="gs-select-trigger" type="button" aria-haspopup="listbox" aria-expanded="false">
<span class="gs-select-value">Selecione...</span>
<span class="gs-select-icon" aria-hidden="true">▼</span>
</button>
<div class="gs-select-panel" role="listbox" hidden>
<div class="gs-select-search"><input type="text" placeholder="Buscar..." aria-label="Filtrar opções" /></div>
<div class="gs-select-group">
<span class="gs-select-group-label">Grupo</span>
<div class="gs-select-option" role="option" data-value="1" aria-selected="false">Opção 1</div>
<div class="gs-select-option" role="option" data-value="2" aria-selected="false">Opção 2</div>
</div>
</div>
</div>Atributos: data-gs-select (raiz), data-gs-select-search (habilita busca), data-gs-select-placeholder, data-gs-select-multiple (seleção múltipla)
Teclado: Enter/Space abre, ↑↓ navega, Esc fecha, digita para filtrar, Home/End primeiro/último
Acessibilidade: role="listbox", role="option", aria-selected, aria-controls, aria-expanded, busca anuncia resultados via aria-live
Date Picker / Date Range Picker
<div class="gs-datepicker" data-gs-datepicker data-gs-datepicker-placeholder="Selecione uma data">
<button class="gs-datepicker-trigger" type="button" aria-haspopup="dialog" aria-expanded="false">
<span class="gs-datepicker-value">Selecione uma data</span>
<span class="gs-datepicker-icon" aria-hidden="true">📅</span>
</button>
<div class="gs-datepicker-panel" role="dialog" aria-modal="true" aria-label="Selecionar data" hidden>
<div class="gs-datepicker-header">
<button class="gs-datepicker-nav" type="button" aria-label="Mês anterior">‹</button>
<span class="gs-datepicker-title">Janeiro 2025</span>
<button class="gs-datepicker-nav" type="button" aria-label="Próximo mês">›</button>
</div>
<div class="gs-datepicker-grid" role="grid" aria-label="Dias do mês">
<div class="gs-datepicker-weekday" role="columnheader">Dom</div>
<!-- ... dias da semana ... -->
<div class="gs-datepicker-day" role="gridcell" aria-selected="false" tabindex="-1">1</div>
<!-- ... dias do mês ... -->
</div>
</div>
</div>Atributos: data-gs-datepicker (raiz), data-gs-datepicker-range (seleção de intervalo), data-gs-datepicker-placeholder
Teclado: Enter abre, setas navegam dias, PgUp/PgDn muda mês, Home/End primeira/última semana, Esc fecha
Acessibilidade: role="dialog", aria-modal="true", role="grid", role="gridcell", aria-selected, navegação por grade 2D
Data Table
<div class="gs-datatable" data-gs-datatable data-gs-datatable-sort data-gs-datatable-filter data-gs-datatable-paginate data-gs-datatable-page-size="10">
<div class="gs-datatable-toolbar">
<input type="text" class="gs-datatable-filter-input" placeholder="Filtrar..." aria-label="Filtrar linhas" />
<div class="gs-datatable-info" aria-live="polite"></div>
</div>
<div class="gs-datatable-wrap">
<table class="gs-table">
<thead>
<tr>
<th scope="col" data-gs-sort="string">Nome</th>
<th scope="col" data-gs-sort="number">Valor</th>
<th scope="col" data-gs-sort="date">Data</th>
<th scope="col"><input type="checkbox" class="gs-datatable-select-all" aria-label="Selecionar todas" /></th>
</tr>
</thead>
<tbody>
<tr data-gs-row>
<td>Item 1</td>
<td>100</td>
<td>2025-01-15</td>
<td><input type="checkbox" class="gs-datatable-row-select" /></td>
</tr>
</tbody>
</table>
</div>
<div class="gs-datatable-pagination" aria-label="Paginação">
<button class="gs-datatable-page-btn" type="button" aria-label="Primeira página" disabled>««</button>
<button class="gs-datatable-page-btn" type="button" aria-label="Página anterior" disabled>«</button>
<span class="gs-datatable-page-info">Página 1 de 5</span>
<button class="gs-datatable-page-btn" type="button" aria-label="Próxima página">»</button>
<button class="gs-datatable-page-btn" type="button" aria-label="Última página">»»</button>
</div>
</div>Atributos: data-gs-datatable (raiz), data-gs-datatable-sort, data-gs-datatable-filter, data-gs-datatable-paginate, data-gs-datatable-page-size
Colunas: data-gs-sort="string|number|date" no <th>
Teclado: Tab navega células, Enter/Space ordena (cabeçalho), Space seleciona linha (checkbox)
Acessibilidade: scope="col", aria-sort no cabeçalho ativo, aria-live no contador, checkboxes com aria-label
Tooltip / Popover
<!-- Tooltip -->
<button class="gs-btn gs-btn-secondary" type="button"
data-gs-tooltip
data-gs-tooltip-content="Dica contextual"
data-gs-tooltip-placement="top">
Passe o mouse
</button>
<!-- Popover -->
<button class="gs-btn gs-btn-primary" type="button"
data-gs-popover
data-gs-popover-trigger="click"
data-gs-popover-title="Ações"
data-gs-popover-content="Ações disponíveis para este item.">
Clique para ver
</button>Tooltip atributos: data-gs-tooltip, data-gs-tooltip-content, data-gs-tooltip-placement (top|right|bottom|left)
Popover atributos: data-gs-popover, data-gs-popover-trigger (hover|click), data-gs-popover-title, data-gs-popover-content (texto simples)
Teclado: Esc fecha, foco move para popover ao abrir (trigger=click)
Acessibilidade: role="tooltip" para tooltip, role="dialog" para popover, aria-describedby no trigger, posicionamento com Floating UI logic (viewport clamping, flip, shift)
Checklist antes de entregar uma tela
- os tokens foram reaproveitados sem cor solta?
- existe um único CTA primário por área?
- o layout colapsa bem em mobile?
- estados de foco e hover continuam visíveis?
- a interação poderia ser resolvida por
data-gs-*antes de criar JS novo?
Acessibilidade (WCAG 2.1 AA)
O kit implementa recursos de acessibilidade nativos. Antes de entregar, valide:
O runtime completa o estado de tabs (role="tab", role="tabpanel", aria-selected, aria-hidden), mantém o painel ativo focável, fecha modais com Escape restaurando o foco e atualiza aria-expanded nos comentários. Para novos componentes, prefira HTML nativo e só adicione ARIA quando o comportamento não puder ser expresso pelo elemento nativo.
Checklist de acessibilidade
- [ ] Navegação por teclado: Toda funcionalidade acessível via
Tab,Shift+Tab, setas,Enter,SpaceeEsc - [ ] Foco visível: Anel de foco (
--gs-focus-ring-width,--gs-focus-ring-color) visível em todos os elementos interativos - [ ] Armadilha de foco em modais:
Tab/Shift+Tabcicla dentro do modal; foco restaura ao fechar - [ ] Regiões ao vivo: Toasts, accordion e modal anunciam mudanças via
aria-live - [ ] ARIA automático: Tabs (
role="tablist/tab/tabpanel"), Accordion (aria-expanded,aria-controls), Menu (aria-expanded,aria-haspopup) - [ ] Contraste: Tokens principais atendem AA (4.5:1) — veja tabela abaixo
- [ ] Alto contraste:
prefers-contrast: highmantém bordas, foco e estados visíveis - [ ] Cores forçadas:
forced-colors: activeusa cores do sistema sem quebrar UI - [ ] Redução de movimento:
prefers-reduced-motion: reduceelimina animações/transições - [ ] Zoom 200%: Layout funcional sem scroll horizontal
- [ ] Labels: Todo input tem
<label>explícita; ícones decorativos têmaria-hidden="true"
Tabela de contraste dos tokens principais
| Token | Cor | Fundo | Contraste | WCAG |
|-------|-----|-------|-----------|------|
| --gs-color-navy-900 | #0a1929 | #fff | 18.2:1 | ✅ AAA |
| --gs-color-navy-700 | #1a3a5c | #fff | 10.4:1 | ✅ AAA |
| --gs-color-text | #0a1929 | #f0f2f5 | 17.1:1 | ✅ AAA |
| --gs-color-text-secondary | #546e7a | #f0f2f5 | 5.2:1 | ✅ AA |
| --gs-color-primary | #ff8c00 | #fff | 3.0:1 | ⚠️ Apenas texto grande (≥18pt/14pt bold) |
Testes manuais recomendados
- Teclado: Navegue toda a interface sem mouse
- Leitor de tela: NVDA (Windows) ou VoiceOver (macOS) — verifique anúncios de tabs, accordion, modal, toasts
- Alto contraste: DevTools → Rendering → Emule
prefers-contrast: higheforced-colors: active - Redução de movimento: DevTools → Rendering → Emule
prefers-reduced-motion: reduce - Zoom: Amplie a 200% — sem scroll horizontal
Diretrizes de contribuição para acessibilidade
- Novos componentes: Devem incluir
roleapropriado,aria-*necessários e navegação por teclado - Novos tokens de cor: Validar contraste AA (4.5:1 texto normal, 3:1 texto grande) antes de merge
- Animações: Respeitar
prefers-reduced-motion— usetransition: none !importantno media query - Foco: Nunca remova
outlinesem substituir por:focus-visiblecom anel visível - Testes: Rode checklist acima em PRs que tocam componentes interativos
Histórico git desta entrega
967038ffeat: scaffold GerminaStack UI kit foundationf99c400docs: add living documentation and playground590213fdocs: add repository handoff guides39f85ffrefactor: move UI kit to repository roota11yfeat: WCAG 2.1 AA accessibility enhancements (focus trap, live regions, keyboard nav, high contrast, reduced motion)v1.2feat: add Select/Combobox, DatePicker/RangePicker, DataTable, Tooltip/Popover components with full accessibility
