NIMBUS framework

Componha com propósito.
Escale com clareza.

A maioria das interfaces de sistemas internos existe apesar da arquitetura, não por causa dela. O Nimbus.js inverte essa equação: cada componente tem uma responsabilidade precisa, comunica-se por eventos e compõe-se por declaração — em um único arquivo JavaScript, sem dependências externas, sem etapa de build.

Ver componentes  → Ver exemplos
rolar
Princípios de design

Três escolhas que
separam o Nimbus.js.

Frameworks genéricos são construídos para cobrir todos os casos possíveis — o que os torna complexos demais para quem quer resolver um problema específico com precisão. O Nimbus.js tomou o caminho oposto. E cada decisão tem um motivo claro.

Construído para um problema real

Frameworks universais carregam a complexidade de todos os casos que nunca existirão no seu sistema. O Nimbus.js foi projetado para um contexto definido — cada componente resolve um problema concreto, cada detalhe serve a uma decisão deliberada, não a uma possibilidade hipotética.

Um arquivo. Funciona.

Não há npm install. Não há webpack.config.js. Não há node_modules com dezenas de milhares de arquivos para servir três componentes. Uma tag <script>. A API WM disponível. Interface funcionando.

O código lê como a interface parece

Cada .add() é uma decisão visível. O que está declarado é exatamente o que existe — sem configuração implícita, sem efeito colateral, sem surpresa para quem mantiver o código daqui a seis meses. A composição de uma janela é a sua própria documentação.

Arquitetura

Cada componente
conhece o seu lugar.

No Nimbus.js, responsabilidade única não é apenas princípio de código — é princípio de design. O Grid exibe dados e emite eventos. A Toolbar oferece ações e filtragem. O Form coleta, valida e notifica. A Window gerencia posição, foco e ciclo de vida.

Nenhum componente sabe o que o outro faz internamente. Eles não se acoplam — comunicam-se exclusivamente por eventos. Você, como desenvolvedor, é o compositor: decide o que acontece quando um evento é disparado, conectando peças independentes em um fluxo coeso.

O resultado é uma arquitetura onde cada parte pode ser substituída, testada e compreendida de forma isolada — sem que o sistema inteiro precise ser decifrado para fazer uma mudança pontual.

Encadeamento de eventos — fluxo típico
Toolbar
onSearch →
grid.filter(q)
Filtra a tabela em tempo real sem lógica adicional
Grid
rowClick →
abrirEdicao(row)
Entrega o objeto da linha — sem saber o que acontece depois
Form
submit →
salvar(data)
Valida, coleta e emite — sem saber onde os dados vão
Window
onClose →
win.close()
Encerra limpo — recursos liberados, sem vazamento de estado
Cada .on() é uma decisão de fluxo — visível, substituível, testável de forma isolada.
Como funciona

Três linhas.
A janela completa.

A API foi desenhada para ser autoexplicativa. Você lê o código de composição e sabe exatamente o que a janela contém — sem abrir nenhum outro arquivo, sem consultar documentação.

Abra a janela com WM.openWindow(). Adicione componentes com .add(). O encadeamento declara a interface na mesma ordem em que o usuário a verá — simples, eficiente, sem ambiguidade.

Inventário de Ativos
Toolbar Ações + campo de busca em tempo real
Grid Tabela com ordenação, filtro e badges
WM.openWindow({ title: 'Inventário', width: 720, height: 460 })
  .add(toolbar)
  .add(grid)
Componentes

O que existe. O que vem.

Quatro componentes em produção hoje, cada um com responsabilidade única e API coesa. Dezesseis no roadmap — priorizados pela necessidade real do sistema, não por completude teórica.

Disponíveis agora

Disponível
Window
Gerencia posição, foco e ciclo de vida. Arrastável por mouse e toque, com animação de abertura e fechamento. Tudo que uma janela precisa ser — nada além disso.
WM.openWindow(opts)
Disponível
Grid
Exibe, ordena e filtra dados. Emite eventos por interação — rowClick, sort. Não sabe o que acontece depois de emitir. Não precisa.
WM.Grid({ columns, data })
Disponível
Form
Coleta, valida e notifica. Suporta text, select, textarea, date e number. Emite submit com os dados — você decide o que fazer com eles.
WM.Form().addField(opts)
Disponível
Toolbar
Oferece ações e filtragem. Conecta-se ao Grid via onSearch sem saber que o Grid existe — apenas chama a função recebida.
WM.Toolbar().addButton()

Alta prioridade — em desenvolvimento

Toast
Notificações temporárias de sucesso, erro, aviso e informação. Empilháveis, com posição e duração configuráveis.
WM.Toast.success('msg')
ConfirmDialog
Confirmação modal com callbacks de confirmação e cancelamento. Substitui o alert() nativo com uma experiência consistente.
WM.ConfirmDialog(opts)
Pagination
Controle de paginação para o Grid. Navegação por páginas, itens por página configurável e evento de troca — desacoplado do Grid por design.
WM.Pagination({ total, page })
Tabs
Navegação por abas dentro de uma janela. Organiza conteúdo de um mesmo contexto em seções distintas — sem abrir múltiplas janelas.
WM.Tabs().addTab(label, el)

Roadmap — médio prazo

Roadmap
Timeline
Linha do tempo de eventos para exibir o histórico de um registro: criação, movimentações, manutenções, mudanças de status.
WM.Timeline({ events })
Roadmap
Chart
Gráficos de barra, linha e pizza para dashboards. Dados atualizáveis via setData() sem recriar o componente.
WM.Chart({ type, data })
Roadmap
Select+Search
Dropdown com busca integrada para listas extensas — responsáveis, categorias, fornecedores com dezenas de entradas.
type: 'select-search'
Roadmap
Upload
Área drag-and-drop para seleção de arquivos, com preview antes do envio e validação de tipo e tamanho máximo.
WM.Upload({ accept, maxSize })

Longo prazo

Futuro
DatePicker
Seletor visual de data com calendário, para contextos que exigem seleção de intervalo ou formatação além do input nativo.
type: 'datepicker'
Futuro
Toggle
Switch visual para campos booleanos — Ativo/Inativo, Visível/Oculto, Permitido/Bloqueado. Mais legível que um checkbox.
WM.Toggle({ label, checked })
Futuro
Accordion
Seções expansíveis para organizar informações extensas sem fragmentar em múltiplas janelas ou abas.
WM.Accordion().addPanel()
Futuro
Progress
Barra de progresso para operações assíncronas — importação de dados, exportação de relatórios, sincronização com serviços externos.
WM.Progress({ value, max })
Exemplos

Da API ao resultado.

Três padrões de uso — do mais simples ao mais composto. Em cada um, o código declara a interface e os eventos orquestram o fluxo.

Dados em tabela,
com um evento.

O Grid recebe colunas e dados e entrega ordenação e filtro nativos. A propriedade badge: true coloriza os valores da coluna de status automaticamente por categoria.

O evento rowClick entrega o objeto completo da linha clicada — o Grid não sabe o que acontece depois. Você decide. Essa separação é intencional e é o que torna cada peça substituível.

grid.filter(query) refiltra os dados em tempo real sem recriar a tabela. Conecte-o ao onSearch da Toolbar e a busca instantânea está pronta — zero lógica adicional.
grid.js
const grid = WM.Grid({
  columns: [
    { field: 'patrimonio', title: 'Patrimônio', sortable: true, width: '110px' },
    { field: 'descricao',  title: 'Descrição',  sortable: true  },
    { field: 'status',     title: 'Status',     badge: true, width: '110px' },
    { field: 'responsavel',title: 'Responsável', width: '100px' },
  ],
  data: ativos
})

// O Grid emite — você decide o que acontece
grid.on('rowClick', row => {
  abrirEdicao(row)
})

WM.openWindow({ title: 'Inventário de Ativos', width: 720, height: 460 })
  .add(grid)

Toolbar + Grid:
comunicação por função.

A Toolbar não sabe que o Grid existe. Ela recebe uma função — onSearch — e a chama quando o usuário digita. Quem filtra é o Grid. Quem conecta é o desenvolvedor.

Esse é o modelo de coesão do Nimbus.js: componentes independentes orquestrados por código explícito. Nenhuma mágica, nenhum canal oculto, nenhuma dependência implícita.

WM.closeAll() fecha todas as janelas abertas. Útil para reinicializar o estado da interface entre operações críticas sem recarregar a página.
composicao.js
const grid = WM.Grid({
  columns: [
    { field: 'patrimonio', title: 'Patrimônio', sortable: true },
    { field: 'descricao',  title: 'Descrição',  sortable: true },
    { field: 'status',     title: 'Status',     badge: true    },
  ],
  data: ativos
})

// Toolbar não conhece o Grid — recebe e chama
const toolbar = WM.Toolbar()
  .addButton({ label: 'Novo',    onClick: () => abrirCadastro() })
  .addButton({ label: 'Exportar', onClick: () => exportar() })
  .addSeparator()
  .addSearch({ placeholder: 'Buscar...', onSearch: q => grid.filter(q) })

// Você, o compositor, declara a ordem
WM.openWindow({ title: 'Inventário', width: 660, height: 440 })
  .add(toolbar)
  .add(grid)

O ciclo completo:
Grid → Form → salvar.

O padrão de edição inline revela o encadeamento de eventos em sua forma mais completa: um clique no Grid inicia a cadeia, o Form coleta e valida, o submit encerra o ciclo.

Cada componente cumpre sua responsabilidade e passa o controle para frente. Nenhum passo está oculto — tudo é código explícito, em sequência, legível de cima para baixo.

O título da janela de edição usa o valor do registro como referência: 'Editar — ' + row.descricao. Contexto imediato para o usuário, custo zero para o desenvolvedor.
edicao-inline.js
// Grid dispara → Form recebe → Window encerra
grid.on('rowClick', row => {

  const form = WM.Form()
    .addField({ name: 'patrimonio', label: 'Nº Patrimônio', value: row.patrimonio })
    .addField({ name: 'descricao',  label: 'Descrição',     value: row.descricao  })
    .addField({ name: 'status', label: 'Status', type: 'select',
                  options: ['Em uso', 'Disponível', 'Manutenção'],
                  value: row.status })
    .addField({ name: 'responsavel', label: 'Responsável', value: row.responsavel })

  // Form coleta, valida e emite — você fecha
  form.on('submit', data => { salvar(data); winEd.close() })

  const winEd = WM.openWindow({
    title: 'Editar — ' + row.descricao, width: 480, height: 380
  }).add(form)

})
Instalação

Um arquivo. Pronto.

Sem gerenciador de pacotes. Sem etapa de build. Sem configuração de ambiente. A inclusão do script é suficiente — a API WM está disponível imediatamente.

via npm
npm install @coreops/nimbus
ou via script
<script src="nimbus.js"></script>
<script>
WM.openWindow({ title: 'Inventário', width: 720, height: 460 })
.add(toolbar).add(grid)
</script>
Interface funcionando
01

Instale via npm

Execute npm install @coreops/nimbus ou baixe nimbus.js e adicione via <script>. Compatível com qualquer template HTML sem modificação de ambiente ou processo de build.

02

Use a API WM

A API global WM estará pronta: openWindow, Grid, Form e Toolbar — sem instanciação prévia, sem cerimônia.

03

Componha e conecte

Adicione componentes com .add() e conecte-os por eventos com .on(). O código declara a interface e orquestra o fluxo — explícito, legível, sem surpresas.