@yakuzaa/jade 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/commands/html.js +113 -11
  2. package/package.json +2 -2
package/commands/html.js CHANGED
@@ -456,6 +456,28 @@ function formatarValor(v, campo) {
456
456
  return v.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
457
457
  }
458
458
 
459
+ function exportarCSV(dados, nomeArquivo) {
460
+ if (!dados.length) return;
461
+ const campos = Object.keys(dados[0]).filter(k => !k.startsWith('_') && k !== 'id');
462
+ const linhas = [
463
+ campos.join(';'),
464
+ ...dados.map(r => campos.map(c => {
465
+ const v = String(r[c] ?? '').replace(/"/g, '""');
466
+ return `"${v}"`;
467
+ }).join(';'))
468
+ ];
469
+ const bom = '\uFEFF'; // UTF-8 BOM para Excel
470
+ const blob = new Blob([bom + linhas.join('\n')], { type: 'text/csv;charset=utf-8;' });
471
+ const url = URL.createObjectURL(blob);
472
+ const a = document.createElement('a');
473
+ a.href = url;
474
+ a.download = (nomeArquivo || 'exportacao') + '.csv';
475
+ document.body.appendChild(a);
476
+ a.click();
477
+ document.body.removeChild(a);
478
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
479
+ }
480
+
459
481
  // Resolve marcadores @funcao:Entidade:campo nos descritores de tela
460
482
  function resolverAgregacoes(tela, dadosMap) {
461
483
  for (const el of tela.elementos || []) {
@@ -521,8 +543,9 @@ async function mudarTela(nome, telas, db, ui, navItems) {
521
543
  }
522
544
  }
523
545
 
524
- // Resolve @soma, @contagem, @media antes de renderizar
525
- resolverAgregacoes(tela, dadosMap);
546
+ // NOTA: @soma/@contagem/@media agora são resolvidos reativamente pelo runtime.
547
+ // Mantemos resolverAgregacoes apenas para versões antigas de runtime que não suportam reatividade.
548
+ if (!ui.setDadosEntidade) resolverAgregacoes(tela, dadosMap);
526
549
 
527
550
  ui.renderizarTela(tela, container, dadosMap);
528
551
 
@@ -536,7 +559,11 @@ async function mudarTela(nome, telas, db, ui, navItems) {
536
559
  document.body.classList.add('jade-com-busca');
537
560
  buscaInput.value = '';
538
561
  signal.set('');
539
- buscaInput.oninput = () => signal.set(buscaInput.value.toLowerCase());
562
+ let _bt = null;
563
+ buscaInput.oninput = () => {
564
+ clearTimeout(_bt);
565
+ _bt = setTimeout(() => signal.set(buscaInput.value.toLowerCase()), 200);
566
+ };
540
567
  } else {
541
568
  buscaWrapper.style.display = 'none';
542
569
  document.body.classList.remove('jade-com-busca');
@@ -656,15 +683,90 @@ async function iniciar() {
656
683
  }
657
684
  });
658
685
 
659
- // Handler: jade:acao — dispara jade:acao:concluido após processar
660
- // (evita spinner eterno em botões sem implementação WASM real)
661
- window.addEventListener('jade:acao', (e) => {
662
- const acao = e.detail?.acao;
663
- // Navegar via router.navegar() é tratado pelo runtime interno —
664
- // aqui garantimos que o botão sai do estado de carregamento
665
- setTimeout(() => {
686
+ // Handler: jade:acao — CRUD, WASM, CSV export
687
+ window.addEventListener('jade:acao', async (e) => {
688
+ const { acao, tela: nomeTela } = e.detail ?? {};
689
+ if (!acao) return;
690
+
691
+ // Padrão: novoXxx abre modal de criação para entidade Xxx
692
+ const matchNovo = acao.match(/^novo([A-Z][a-zA-Z]*)/);
693
+ if (matchNovo) {
694
+ ui.abrirModalCRUD?.('criar', matchNovo[1]);
695
+ window.dispatchEvent(new CustomEvent('jade:acao:concluido', { detail: { acao } }));
696
+ return;
697
+ }
698
+
699
+ // Padrão: exportarCSV ou exportarCsv → exporta entidade ativa como CSV
700
+ if (/^exportar(CSV|Csv|csv)?/.test(acao)) {
701
+ const entidades = ui.getEntidadesAtivas?.() ?? [];
702
+ const entidade = entidades[0];
703
+ if (entidade) {
704
+ const dados = await db.find(entidade).catch(() => []);
705
+ exportarCSV(dados, entidade);
706
+ ui.mostrarNotificacao(`${entidade} exportado com sucesso`, 'sucesso');
707
+ }
666
708
  window.dispatchEvent(new CustomEvent('jade:acao:concluido', { detail: { acao } }));
667
- }, 300);
709
+ return;
710
+ }
711
+
712
+ let chamouWasm = false;
713
+ try {
714
+ if (typeof runtime?.call === 'function') {
715
+ try { runtime.call(acao); chamouWasm = true; } catch (_) { /* não exportado */ }
716
+ }
717
+
718
+ const entidades = ui.getEntidadesAtivas?.() ?? [];
719
+ await Promise.all(entidades.map(async (entidade) => {
720
+ const dados = await db.find(entidade).catch(() => []);
721
+ ui.setDadosEntidade?.(entidade, dados);
722
+ }));
723
+
724
+ if (chamouWasm) ui.mostrarNotificacao('Ação concluída com sucesso', 'sucesso');
725
+ } catch (err) {
726
+ ui.mostrarNotificacao('Erro ao executar ação: ' + (err?.message ?? err), 'erro');
727
+ }
728
+
729
+ window.dispatchEvent(new CustomEvent('jade:acao:concluido', { detail: { acao } }));
730
+ });
731
+
732
+ // Handlers CRUD: criar, atualizar, remover
733
+ window.addEventListener('jade:crud:criar', async (e) => {
734
+ const { entidade, dados } = e.detail ?? {};
735
+ if (!entidade || !dados) return;
736
+ try {
737
+ await db.insert(entidade, dados);
738
+ const registros = await db.find(entidade);
739
+ ui.setDadosEntidade?.(entidade, registros);
740
+ ui.mostrarNotificacao(`${entidade} criado com sucesso`, 'sucesso');
741
+ } catch (err) {
742
+ ui.mostrarNotificacao('Erro ao criar: ' + (err?.message ?? err), 'erro');
743
+ }
744
+ });
745
+
746
+ window.addEventListener('jade:crud:atualizar', async (e) => {
747
+ const { entidade, id, dados } = e.detail ?? {};
748
+ if (!entidade || !id || !dados) return;
749
+ try {
750
+ await db.update(entidade, id, dados);
751
+ const registros = await db.find(entidade);
752
+ ui.setDadosEntidade?.(entidade, registros);
753
+ ui.mostrarNotificacao(`${entidade} atualizado`, 'sucesso');
754
+ } catch (err) {
755
+ ui.mostrarNotificacao('Erro ao atualizar: ' + (err?.message ?? err), 'erro');
756
+ }
757
+ });
758
+
759
+ window.addEventListener('jade:crud:remover', async (e) => {
760
+ const { entidade, id } = e.detail ?? {};
761
+ if (!entidade || !id) return;
762
+ try {
763
+ await db.delete(entidade, id);
764
+ const registros = await db.find(entidade);
765
+ ui.setDadosEntidade?.(entidade, registros);
766
+ ui.mostrarNotificacao(`${entidade} excluído`, 'info');
767
+ } catch (err) {
768
+ ui.mostrarNotificacao('Erro ao excluir: ' + (err?.message ?? err), 'erro');
769
+ }
668
770
  });
669
771
 
670
772
  // Renderiza primeira tela navegável
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yakuzaa/jade",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Jade DSL — linguagem empresarial em português compilada para WebAssembly. Instala compilador + runtime + CLI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@yakuzaa/jade-compiler": "^0.1.15",
21
- "@yakuzaa/jade-runtime": "^0.1.10"
21
+ "@yakuzaa/jade-runtime": "^0.1.12"
22
22
  },
23
23
  "keywords": [
24
24
  "jade",