@yakuzaa/jade 0.1.13 → 0.1.15

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 +115 -13
  2. package/package.json +2 -2
package/commands/html.js CHANGED
@@ -99,6 +99,25 @@ function gerarCSS(tema = {}) {
99
99
  }
100
100
 
101
101
  /* ── Header fixo ─────────────────────────────── */
102
+ /* ── Banner de notificação (empurra layout) ─── */
103
+ #jade-banner {
104
+ position: fixed;
105
+ top: 0; left: 0; right: 0;
106
+ height: 0;
107
+ overflow: hidden;
108
+ z-index: 400;
109
+ transition: height 0.28s cubic-bezier(0.4,0,0.2,1);
110
+ }
111
+ #jade-banner.jade-banner-visivel { height: 48px; }
112
+ body.jade-com-banner #jade-header {
113
+ top: 48px;
114
+ transition: top 0.28s cubic-bezier(0.4,0,0.2,1);
115
+ }
116
+ body.jade-com-banner #jade-app {
117
+ margin-top: calc(52px + 48px);
118
+ transition: margin-top 0.28s cubic-bezier(0.4,0,0.2,1);
119
+ }
120
+
102
121
  #jade-header {
103
122
  position: fixed;
104
123
  top: 0; left: 0; right: 0;
@@ -111,6 +130,7 @@ function gerarCSS(tema = {}) {
111
130
  z-index: 300;
112
131
  box-shadow: 0 1px 0 rgba(255,255,255,0.06), 0 2px 8px rgba(0,0,0,0.2);
113
132
  flex-shrink: 0;
133
+ transition: top 0.28s cubic-bezier(0.4,0,0.2,1);
114
134
  }
115
135
 
116
136
  #jade-hamburger {
@@ -138,7 +158,34 @@ function gerarCSS(tema = {}) {
138
158
  white-space: nowrap;
139
159
  overflow: hidden;
140
160
  text-overflow: ellipsis;
161
+ transition: opacity 0.2s;
162
+ }
163
+ body.jade-com-busca #jade-header-titulo { opacity: 0; pointer-events: none; }
164
+
165
+ /* ── Search bar centralizado no header ─────── */
166
+ #jade-header-busca-wrapper {
167
+ position: absolute;
168
+ left: 50%;
169
+ transform: translateX(-50%);
170
+ width: min(380px, calc(100% - 180px));
171
+ display: flex;
172
+ align-items: center;
173
+ }
174
+ #jade-header-busca {
175
+ width: 100%;
176
+ height: 34px;
177
+ padding: 0 14px;
178
+ border: none;
179
+ border-radius: 999px;
180
+ background: rgba(255,255,255,0.13);
181
+ color: #fff;
182
+ font-size: 0.875rem;
183
+ font-family: var(--jade-fonte);
184
+ outline: none;
185
+ transition: background 0.15s;
141
186
  }
187
+ #jade-header-busca::placeholder { color: rgba(255,255,255,0.45); }
188
+ #jade-header-busca:focus { background: rgba(255,255,255,0.2); }
142
189
 
143
190
  /* ── Layout principal (abaixo do header) ─────── */
144
191
  #jade-app {
@@ -146,6 +193,11 @@ function gerarCSS(tema = {}) {
146
193
  height: calc(100dvh - 52px);
147
194
  margin-top: 52px;
148
195
  overflow: hidden;
196
+ transition: margin-top 0.28s cubic-bezier(0.4,0,0.2,1),
197
+ height 0.28s cubic-bezier(0.4,0,0.2,1);
198
+ }
199
+ body.jade-com-banner #jade-app {
200
+ height: calc(100dvh - 52px - 48px);
149
201
  }
150
202
 
151
203
  /* ── Nav lateral ─────────────────────────────── */
@@ -469,10 +521,33 @@ async function mudarTela(nome, telas, db, ui, navItems) {
469
521
  }
470
522
  }
471
523
 
472
- // Resolve @soma, @contagem, @media antes de renderizar
473
- resolverAgregacoes(tela, dadosMap);
524
+ // NOTA: @soma/@contagem/@media agora são resolvidos reativamente pelo runtime.
525
+ // Mantemos resolverAgregacoes apenas para versões antigas de runtime que não suportam reatividade.
526
+ if (!ui.setDadosEntidade) resolverAgregacoes(tela, dadosMap);
474
527
 
475
528
  ui.renderizarTela(tela, container, dadosMap);
529
+
530
+ // Conecta search bar do header ao filtro da tela, se existir
531
+ const buscaWrapper = document.getElementById('jade-header-busca-wrapper');
532
+ const buscaInput = document.getElementById('jade-header-busca');
533
+ if (buscaWrapper && buscaInput) {
534
+ const signal = ui.getFiltroPorTela?.(nome);
535
+ if (signal) {
536
+ buscaWrapper.style.display = '';
537
+ document.body.classList.add('jade-com-busca');
538
+ buscaInput.value = '';
539
+ signal.set('');
540
+ let _bt = null;
541
+ buscaInput.oninput = () => {
542
+ clearTimeout(_bt);
543
+ _bt = setTimeout(() => signal.set(buscaInput.value.toLowerCase()), 200);
544
+ };
545
+ } else {
546
+ buscaWrapper.style.display = 'none';
547
+ document.body.classList.remove('jade-com-busca');
548
+ buscaInput.oninput = null;
549
+ }
550
+ }
476
551
  }
477
552
 
478
553
  async function iniciar() {
@@ -510,8 +585,8 @@ async function iniciar() {
510
585
  const navEl = document.getElementById('jade-nav');
511
586
  const isMobile = () => window.innerWidth <= 768;
512
587
 
513
- const iconeMenu = criarElementoIcone('menu', 22);
514
- const iconeFechar = criarElementoIcone('fechar', 22);
588
+ const iconeMenu = criarElementoIcone('menu', 24);
589
+ const iconeFechar = criarElementoIcone('fechar', 24);
515
590
  if (iconeMenu) hamburger.appendChild(iconeMenu);
516
591
 
517
592
  function abrirDrawer() {
@@ -586,15 +661,37 @@ async function iniciar() {
586
661
  }
587
662
  });
588
663
 
589
- // Handler: jade:acao — dispara jade:acao:concluido após processar
590
- // (evita spinner eterno em botões sem implementação WASM real)
591
- window.addEventListener('jade:acao', (e) => {
592
- const acao = e.detail?.acao;
593
- // Navegar via router.navegar() é tratado pelo runtime interno —
594
- // aqui garantimos que o botão sai do estado de carregamento
595
- setTimeout(() => {
596
- window.dispatchEvent(new CustomEvent('jade:acao:concluido', { detail: { acao } }));
597
- }, 300);
664
+ // Handler: jade:acao — chama função WASM (se existir), atualiza dados reativamente
665
+ window.addEventListener('jade:acao', async (e) => {
666
+ const { acao, tela: nomeTela } = e.detail ?? {};
667
+ if (!acao) return;
668
+
669
+ let chamouWasm = false;
670
+ try {
671
+ // 1. Tenta chamar função WASM exportada com o mesmo nome
672
+ if (typeof runtime?.call === 'function') {
673
+ try {
674
+ runtime.call(acao);
675
+ chamouWasm = true;
676
+ } catch (_) { /* função não exportada ainda — ignora */ }
677
+ }
678
+
679
+ // 2. Recarrega dados das entidades ativas e propaga via signals (sem re-render completo)
680
+ const entidades = ui.getEntidadesAtivas?.() ?? [];
681
+ await Promise.all(entidades.map(async (entidade) => {
682
+ const dados = await db.find(entidade).catch(() => []);
683
+ ui.setDadosEntidade?.(entidade, dados);
684
+ }));
685
+
686
+ // 3. Notificação apenas se houve chamada WASM real
687
+ if (chamouWasm) {
688
+ ui.mostrarNotificacao('Ação concluída com sucesso', 'sucesso');
689
+ }
690
+ } catch (err) {
691
+ ui.mostrarNotificacao('Erro ao executar ação: ' + (err?.message ?? err), 'erro');
692
+ }
693
+
694
+ window.dispatchEvent(new CustomEvent('jade:acao:concluido', { detail: { acao } }));
598
695
  });
599
696
 
600
697
  // Renderiza primeira tela navegável
@@ -643,9 +740,14 @@ ${gerarCSS(tema)}
643
740
  Carregando...
644
741
  </div>
645
742
 
743
+ <div id="jade-banner" role="status" aria-live="polite"></div>
744
+
646
745
  <header id="jade-header" style="display:none">
647
746
  <button id="jade-hamburger" aria-label="Abrir menu" aria-expanded="false"></button>
648
747
  <span id="jade-header-titulo">${nome}</span>
748
+ <div id="jade-header-busca-wrapper" style="display:none" role="search">
749
+ <input id="jade-header-busca" type="search" placeholder="Buscar..." autocomplete="off" aria-label="Buscar na tela atual">
750
+ </div>
649
751
  </header>
650
752
 
651
753
  <div id="jade-overlay" role="presentation"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yakuzaa/jade",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
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.8"
21
+ "@yakuzaa/jade-runtime": "^0.1.11"
22
22
  },
23
23
  "keywords": [
24
24
  "jade",