@thibezer/ui-components-kit 2.2.0 → 2.2.1

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.
package/README.md CHANGED
@@ -1,760 +1,760 @@
1
- # 🎨 UI Components Kit - Web Components Nativos & Universais
2
-
3
- Biblioteca de **Web Components Nativos Universais e Agnósticos**, construída no padrão oficial **W3C Custom Elements + Shadow DOM**, com TypeScript, Design Tokens em CSS modular e Vite.
4
-
5
- Projetada para funcionar em **qualquer linguagem, framework ou sistema web** (HTML puro, React, Next.js, Vue, Angular, Svelte, PHP, Django, WordPress, Blazor, etc.) com **zero dependências externas** (exceto `<ui-mapa>` e `<ui-canvas-cad>`, que usam o Leaflet como dependência opcional).
6
-
7
- ---
8
-
9
- ## 📑 Índice
10
-
11
- 1. [Por que Web Components?](#-por-que-web-components)
12
- 2. [Como Importar na sua Aplicação](#-como-importar-na-sua-aplicação)
13
- - [Opção 1: CDN / Script Tag (HTML puro, PHP, Django)](#opção-1-cdn--script-tag-html-puro-php-django)
14
- - [Opção 2: NPM / Módulos ES (React, Vue, Next.js, Vite)](#opção-2-npm--módulos-es-react-vue-nextjs-vite)
15
- 3. [Como Controlar os Componentes (5 Pilares)](#-como-controlar-os-componentes-5-pilares)
16
- 4. [⚡ Recursos Inteligentes de Alta Produtividade](#-recursos-inteligentes-de-alta-produtividade)
17
- - [Ações Declarativas "Zero-JS" (Triggers Nativos)](#1-ações-declarativas-zero-js-triggers-nativos)
18
- - [Formulários Automáticos com FormData Nativo (W3C FACE)](#2-formulários-automáticos-com-formdata-nativo-w3c-face)
19
- - [Barramento Global de Orquestração (UIBus)](#3-barramento-global-de-orquestração-uibus)
20
- - [Tabelas Autônomas com Auto-Fetch Remoto](#4-tabelas-autônomas-com-auto-fetch-remoto)
21
- 5. [💻 Exemplos de Uso por Tecnologia](#-exemplos-de-uso-por-tecnologia)
22
- - [HTML Puro + JavaScript](#html-puro--javascript)
23
- - [React / Next.js](#react--nextjs)
24
- - [Vue.js](#vuejs)
25
- - [Iframes / Microfrontends](#iframes--microfrontends)
26
- 6. [🧩 Catálogo de Componentes & Referência](#-catálogo-de-componentes--referência)
27
- 7. [🛠️ Como Executar e Compilar Localmente](#️-como-executar-e-compilar-localmente)
28
-
29
- ---
30
-
31
- ## 🎯 Por que Web Components?
32
-
33
- * 🌐 **100% Universal e Agnóstico**: Funciona em qualquer stack sem necessidade de bibliotecas intermediárias.
34
- * 🛡️ **Encapsulamento Total (Shadow DOM)**: O CSS da sua aplicação nunca quebra o componente, e o CSS do componente nunca vaza para o seu site.
35
- * 📐 **Design Tokens Centralizados**: Variáveis CSS personalizáveis para cores, tipografia, raios e densidade.
36
- * 🚀 **Suporte a Altíssima Densidade**: Otimizado para interfaces densas e técnicas (GIS, CAD, Topografia de 15px a 20px de altura) até interfaces fluidas modernas.
37
-
38
- ---
39
-
40
- ## 📦 Como Importar na sua Aplicação
41
-
42
- ### Opção 1: CDN / Script Tag (HTML puro, PHP, Django)
43
-
44
- Adicione as tags no `<head>` ou antes do fechamento do `</body>`:
45
-
46
- ```html
47
- <!-- 1. Design Tokens e Estilos Globais -->
48
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@thibezer/ui-components-kit@1/dist/ui-kit.css">
49
-
50
- <!-- 2. Biblioteca dos Componentes (Módulo ES) -->
51
- <script type="module" src="https://cdn.jsdelivr.net/npm/@thibezer/ui-components-kit@1/dist/index.js"></script>
52
-
53
- <!-- 3. Uso imediato no HTML -->
54
- <ui-botao-primario variante="primary">Clique Aqui</ui-botao-primario>
55
- ```
56
-
57
- > **Mapa e CAD via CDN (`<ui-mapa>`, `<ui-canvas-cad>`)**: esses componentes dependem do [Leaflet](https://leafletjs.com/), importado como `leaflet` (especificador "bare"), que o navegador só resolve com um *import map*. Declare-o **antes** do script da biblioteca:
58
- >
59
- > ```html
60
- > <script type="importmap">
61
- > { "imports": { "leaflet": "https://cdn.jsdelivr.net/npm/leaflet@1.9.4/+esm" } }
62
- > </script>
63
- > ```
64
- >
65
- > Os demais componentes não precisam do Leaflet. Com npm, basta `npm install leaflet`.
66
-
67
- ### Opção 2: NPM / Módulos ES (React, Vue, Next.js, Vite)
68
-
69
- Instale pelo npm:
70
-
71
- ```bash
72
- npm install @thibezer/ui-components-kit
73
- ```
74
-
75
- > O pacote é publicado já compilado (`dist/`) e **não executa build na instalação**, então funciona em CI/CD e em servidores com `npm ci --omit=dev`. A antiga instalação por URL Git (`git+https://github.com/...`) não é mais suportada: o repositório não versiona `dist/`.
76
-
77
- No ponto de entrada da sua aplicação (`main.ts`, `index.js` ou `App.tsx`):
78
-
79
- ```typescript
80
- // 1. Estilos globais obrigatórios (tokens CSS)
81
- import '@thibezer/ui-components-kit/style.css';
82
-
83
- // 2. Biblioteca completa (ou escolha os submódulos abaixo)
84
- import '@thibezer/ui-components-kit';
85
- ```
86
-
87
- #### 🚀 Importação Modular e Otimizada (Sub-paths)
88
-
89
- Pague apenas pelo que utilizar. Importe por domínio de funcionalidade ou por componente específico:
90
-
91
- O export map expõe explicitamente os pontos de entrada canônicos (ESM em `.js`, CommonJS em `.cjs` e tipos `.d.ts`):
92
-
93
- | Subpath | Arquivo (ESM) |
94
- |---|---|
95
- | `@thibezer/ui-components-kit` | `dist/index.js` |
96
- | `@thibezer/ui-components-kit/camadas` | `dist/camadas.js` |
97
- | `@thibezer/ui-components-kit/forms` | `dist/forms.js` |
98
- | `@thibezer/ui-components-kit/feedback` | `dist/feedback.js` |
99
- | `@thibezer/ui-components-kit/tabela` | `dist/tabela.js` |
100
- | `@thibezer/ui-components-kit/style.css` | `dist/ui-kit.css` (100% autocontido, sem `@import`) |
101
-
102
- ##### 1. Por Domínio / Categoria:
103
- ```typescript
104
- import '@thibezer/ui-components-kit/forms'; // Campos, Select, Checkbox, Radio, Switch (~8 kB gzip)
105
- import '@thibezer/ui-components-kit/feedback'; // Modais, Drawers, Alertas, Toasts, Tooltips, Skeletons (~6 kB gzip)
106
- import '@thibezer/ui-components-kit/data'; // Tabela, Tabela-Propriedades, Stat KPI, Badge (~4 kB gzip)
107
- import '@thibezer/ui-components-kit/tools'; // Ribbon CAD/Office e Paleta de Ferramentas (~10 kB gzip)
108
- import '@thibezer/ui-components-kit/core'; // Apenas UIBus, Zero-JS e ListenerBag (< 1 kB gzip)
109
- import '@thibezer/ui-components-kit/canvas'; // Mesa CAD vetorial e motor GIS (~33 kB gzip)
110
- import '@thibezer/ui-components-kit/camadas'; // Painel de Camadas GIS/CAD redimensionável (~21 kB gzip)
111
- import '@thibezer/ui-components-kit/mapa'; // Mapa Geográfico Leaflet (~3 kB gzip)
112
- ```
113
-
114
- ##### 2. Granular por Componente (Ultra Leve):
115
- ```typescript
116
- import '@thibezer/ui-components-kit/botao'; // Apenas <ui-botao> e <ui-botao-primario> (~3.4 kB gzip)
117
- import '@thibezer/ui-components-kit/campo-texto'; // Apenas <ui-campo-texto> com FACE e anti-zoom (~3.9 kB gzip)
118
- import '@thibezer/ui-components-kit/modal'; // Apenas <ui-modal> com bottom-sheet mobile (~3.3 kB gzip)
119
- import '@thibezer/ui-components-kit/card'; // Apenas <ui-card> com elevação (~2.3 kB gzip)
120
- import '@thibezer/ui-components-kit/tabela'; // Apenas <ui-tabela> virtualizada
121
- ```
122
-
123
- > **Zero Overhead**: Uma tela que utilize apenas `<ui-botao>` e `<ui-campo-texto>` importa menos de **8 kB gzip**, sem carregar nada de Leaflet, CAD, GIS ou virtualização.
124
-
125
- ---
126
-
127
- ## 🎛️ Como Controlar os Componentes (5 Pilares)
128
-
129
- ```text
130
- ┌─────────────────────────────────────────────────────────────┐
131
- │ SISTEMA EXTERNO │
132
- └──────┬───────────────▲─────────────────┬─────────────────▲──┘
133
- │ │ │ │
134
- 1. Atributos 4. Eventos Custom 2. Propriedades 3. Métodos
135
- (HTML) (ui-*) (Objetos/Listas) (Imperativo)
136
- │ │ │ │
137
- ┌──────▼───────────────┴─────────────────▼─────────────────┴──┐
138
- │ WEB COMPONENT (<ui-*>) │
139
- └─────────────────────────────────────────────────────────────┘
140
- ```
141
-
142
- ### 1. Atributos HTML (Controle Declarativo)
143
- Configurações simples passadas diretamente nas tags:
144
- ```html
145
- <ui-campo-texto label="CPF" placeholder="000.000.000-00" obrigatorio></ui-campo-texto>
146
- <ui-modal id="meu-modal" titulo="Confirmar Exclusão"></ui-modal>
147
- ```
148
-
149
- ---
150
-
151
- ### 📏 Ajuste de Altura e Dimensionamento Inteligente (Zero Atrito)
152
-
153
- Os campos de texto (`<ui-campo-texto>`), listas flutuantes/selects (`<ui-lista-flutuante>`, `<ui-select>`) e botões (`<ui-botao-primario>`) possuem 4 formas flexíveis de ajuste de altura:
154
-
155
- #### 1. Via Atributo de Tamanho Predefinido (`tamanho` ou `densidade`):
156
- ```html
157
- <!-- Compacto (26px) - Ideal para Toolbars CAD/GIS, tabelas e alta densidade -->
158
- <ui-campo-texto tamanho="sm" placeholder="26px Compacto"></ui-campo-texto>
159
- <ui-lista-flutuante tamanho="sm" placeholder="Selecione..."></ui-lista-flutuante>
160
-
161
- <!-- Padrão (34px) - Padrão moderno e equilibrado para formulários e modais -->
162
- <ui-campo-texto tamanho="md" placeholder="34px Padrão"></ui-campo-texto>
163
- <ui-lista-flutuante tamanho="md" placeholder="Selecione..."></ui-lista-flutuante>
164
-
165
- <!-- Conforto / Touch (42px) - Otimizado para dispositivos móveis e telas sensíveis ao toque -->
166
- <ui-campo-texto tamanho="lg" placeholder="42px Conforto"></ui-campo-texto>
167
- <ui-lista-flutuante tamanho="lg" placeholder="Selecione..."></ui-lista-flutuante>
168
- ```
169
-
170
- #### 2. Via Atributo de Altura Explícita (`altura` ou `height`):
171
- ```html
172
- <!-- Define a altura exata em pixels diretamente no elemento -->
173
- <ui-campo-texto altura="38" placeholder="Altura de 38px"></ui-campo-texto>
174
- <ui-lista-flutuante altura="44px" placeholder="Altura de 44px"></ui-lista-flutuante>
175
- <ui-botao-primario altura="40">Salvar</ui-botao-primario>
176
- ```
177
-
178
- #### 3. Via Variável CSS Customizável (`--ui-campo-altura`):
179
- ```css
180
- /* No seu CSS global ou no container pai */
181
- .meu-formulario {
182
- --ui-campo-altura: 36px; /* Aplica instantaneamente em todos os inputs, selects e botões filhos */
183
- }
184
- ```
185
-
186
- #### 4. Via Barramento Global de Densidade (`UIBus`):
187
- ```javascript
188
- import { UIBus } from '@thibezer/ui-components-kit';
189
-
190
- // Altera a densidade de toda a aplicação em tempo real:
191
- UIBus.definirDensidade('compacta'); // 26px
192
- UIBus.definirDensidade('padrao'); // 34px
193
- UIBus.definirDensidade('relaxada'); // 42px
194
- UIBus.definirDensidade(38); // Valor numérico em px customizado
195
- ```
196
-
197
- ---
198
-
199
- ### 2. Propriedades JavaScript (Dados Complexos)
200
- Para enviar arrays e objetos complexos:
201
- ```javascript
202
- const tabela = document.querySelector('ui-tabela');
203
- tabela.colunas = [
204
- { id: 'ponto', rotulo: 'Ponto', ordenavel: true },
205
- { id: 'altitude', rotulo: 'Altitude (m)' }
206
- ];
207
- tabela.dados = [
208
- { ponto: 'P-01', altitude: '542,15' },
209
- { ponto: 'P-02', altitude: '545,30' }
210
- ];
211
- ```
212
-
213
- ### 3. Métodos Imperativos (Ações Diretas)
214
- Comandos diretos chamados na instância do elemento:
215
- ```javascript
216
- const modal = document.getElementById('meu-modal');
217
- modal.abrir();
218
- modal.fechar();
219
- ```
220
-
221
- ### 4. Eventos Customizados Nativos (`ui-*`)
222
- Escuta de eventos disparados pelas interações do usuário:
223
- ```javascript
224
- const campo = document.querySelector('ui-campo-texto');
225
- campo.addEventListener('ui-input', (e) => {
226
- console.log('Texto digitado:', e.detail.value);
227
- });
228
- ```
229
-
230
- > **Mutação de usuário vs. programática (`<ui-camadas>`)**: eventos saem do componente **somente** em resposta a interações físicas (clique, drag-and-drop, teclado). Atribuir `painel.layers = [...]`, alterar atributos (`camada-ativa`, `colapsado`, `mapa-base-ativo`...) ou chamar métodos públicos (`definirCamadaAtiva`, `selecionarFeicao`, `limparSelecao`, `colapsar`, `definirAltura`...) apenas atualiza o DOM interno — sem redisparar eventos. Isso elimina loops de sincronização em apps reativos (React, Vue, Svelte). Para forçar a emissão numa chamada programática, passe `emitirEvento = true` (ex.: `painel.definirCamadaAtiva('lotes', true)`).
231
-
232
- ### 5. Serviços Globais e Helpers
233
- Utilitários prontos para uso sem necessidade de instanciar elementos:
234
- ```javascript
235
- import { UIToast, UIBus } from '@thibezer/ui-components-kit';
236
-
237
- UIToast.notificar({
238
- tipo: 'sucesso',
239
- titulo: 'Registro Salvo!',
240
- mensagem: 'Os dados foram sincronizados.',
241
- duracao: 4000
242
- });
243
- ```
244
-
245
- ### 6. Escala de Elevação (z-index)
246
- Todos os componentes flutuantes consomem tokens de elevação previsíveis (com fallback), definidos em `ui-kit.css`. Sobrescreva-os no `:root` da aplicação para encaixar a pilha do kit entre os HUDs e modais do seu app:
247
- ```css
248
- :root {
249
- --ui-z-workspace-hud: 500; /* <ui-camadas flutuante>, <ui-seletor-mapa-base>, toolbars do canvas */
250
- --ui-z-docked-bar: 600; /* <ui-ribbon> recolhido, <ui-tabela-propriedades flutuante> */
251
- --ui-z-drawer: 700; /* <ui-drawer> e backdrop */
252
- --ui-z-modal: 1000; /* <ui-modal> e backdrop */
253
- --ui-z-popover: 1050; /* menus suspensos/contexto, <ui-select> (acima do modal, funciona dentro dele) */
254
- --ui-z-toast: 1100; /* UIToast */
255
- --ui-z-tooltip: 1200; /* <ui-tooltip> */
256
- }
257
- ```
258
-
259
- ### 7. Acessibilidade Nativa de Rótulos
260
- `<ui-input>` (alias de `<ui-campo-texto>`), `<ui-select>` e `<ui-switch>` geram IDs únicos internamente e associam o rótulo visível ao controle nativo do Shadow DOM — o projeto consumidor não precisa gerenciar IDs:
261
- ```html
262
- <ui-input label="Nome"></ui-input> <!-- <label for> ↔ <input> interno -->
263
- <ui-select label="Cidade">...</ui-select> <!-- aria-labelledby = rótulo + valor atual -->
264
- <ui-switch label="Modo escuro"></ui-switch> <!-- role="switch" aria-labelledby -->
265
-
266
- <!-- Sem o atributo label, o nome acessível vem de fora do Shadow DOM: -->
267
- <label>Telefone <ui-input></ui-input></label>
268
- <ui-switch aria-label="Camada visível"></ui-switch>
269
- ```
270
-
271
- ### 8. Temas Claro e Escuro
272
- Sem configuração, o kit **segue o tema do sistema operacional** (`prefers-color-scheme`). Para fixar um tema, use o atributo na raiz — ou em qualquer elemento, para fixar só aquele trecho:
273
- ```html
274
- <html data-tema="escuro"> <!-- ou "claro"; também aceitos: class="dark|light" e data-theme="dark|light" -->
275
- <aside data-tema="claro">…</aside> <!-- trecho claro dentro de uma página escura -->
276
- ```
277
- ```javascript
278
- UIBus.definirTema('auto'); // volta a seguir o SO
279
- UIBus.on('tema:alterado', ({ tema }) => { /* também dispara quando o SO muda, se o tema não estiver fixado */ });
280
- ```
281
- Os componentes recebem o tema **apenas pelos tokens de cor** (`--ui-cor-*`, `--ui-sombra-*`), que atravessam o Shadow DOM. Todo token de texto atinge contraste **WCAG AA (4,5:1)** nos dois temas, inclusive sobre fundos tingidos de status e no texto sobre a cor primária e o botão destrutivo — verificado em `tests/tema.test.ts`.
282
-
283
- | Token | Uso |
284
- | :--- | :--- |
285
- | `--ui-cor-texto-sucesso` / `-erro` / `-alerta` / `-info` | Texto e tons de status (alertas, badges, toasts) |
286
- | `--ui-cor-texto-sobre-status` | Texto sobre fundo sólido de status (badge sólido) |
287
- | `--ui-cor-fundo-recuado` | Faixas rebaixadas (rodapés de modal e drawer) |
288
- | `--ui-sombra-sm` / `-md` / `-lg` | Sombras: densas no escuro, suaves no claro |
289
-
290
- ### 9. Tipografia e Raios
291
- Todos os componentes usam apenas dois tokens de família de fonte e uma escala de raios derivada de `--ui-raio-borda`. Sobrescreva no `:root` (a escala é calculada lá):
292
- ```css
293
- :root {
294
- --ui-fonte-base: 'Roboto', sans-serif; /* textos da interface */
295
- --ui-fonte-codigo: 'JetBrains Mono', monospace; /* coordenadas, valores técnicos, código */
296
-
297
- --ui-raio-borda: 4px; /* base: botões, campos, menus */
298
- /* derivados automaticamente: --ui-raio-sm (2/3), --ui-raio-lg (5/3), --ui-raio-xl (8/3) */
299
- /* --ui-raio-borda: 0 → interface totalmente reta */
300
- }
301
- ```
302
-
303
- ### 10. Estilização Interna com `::part`
304
- O Shadow DOM isola o CSS, mas os elementos internos principais são expostos com `part`, com nomes consistentes entre componentes (uma regra serve para vários):
305
-
306
- | Componente | Parts |
307
- | :--- | :--- |
308
- | `<ui-botao>` / `<ui-botao-primario>` | `base`, `spinner` |
309
- | `<ui-campo-texto>` / `<ui-input>` | `rotulo`, `campo`, `input`, `icone`, `icone-esquerda`, `icone-direita`, `ajuda` |
310
- | `<ui-lista-flutuante>` / `<ui-select>` | `rotulo`, `campo`, `valor`, `seta`, `lista`, `opcao`, `opcao-selecionada` |
311
- | `<ui-checkbox>`, `<ui-radio>`, `<ui-switch>` | `base`, `controle`, `indicador`, `rotulo` |
312
- | `<ui-segmented>` | `base`, `indicador`, `opcao`, `opcao-selecionada` |
313
- | `<ui-modal>`, `<ui-drawer>` | `fundo`, `painel`, `cabecalho`, `titulo`, `descricao` (drawer), `fechar`, `corpo`, `rodape` |
314
- | `<ui-card>` | `base`, `midia`, `cabecalho`, `corpo`, `rodape` |
315
- | `<ui-badge>` / `<ui-chip>` | `base`, `rotulo`, `remover` |
316
- | `<ui-alerta>` / toasts | `base`, `icone`, `conteudo`, `titulo`, `mensagem`, `acao`, `fechar`, `progresso` |
317
- | `<ui-tooltip>` | `balao`, `texto`, `seta` |
318
- | `<ui-tabela>` | `base`, `tabela`, `celula-cabecalho`, `ordenar`, `linha`, `linha-selecionada`, `celula`, `vazio`, `carregando` |
319
-
320
- ```css
321
- ui-campo-texto::part(campo) { border-width: 2px; }
322
- ui-modal::part(painel) { max-width: 720px; }
323
- ui-tabela::part(linha-selecionada) { background: #0b3d2a; }
324
- :is(ui-checkbox, ui-radio, ui-switch)::part(rotulo) { font-weight: 600; }
325
- ```
326
-
327
- ---
328
-
329
- ## ⚡ Recursos Inteligentes de Alta Produtividade
330
-
331
- ### 1. Ações Declarativas "Zero-JS" (Triggers Nativos)
332
- Você pode acionar modais, fechar janelas, disparar notificações toast ou copiar textos **sem escrever nenhuma linha de JavaScript**, apenas adicionando atributos nas tags HTML:
333
-
334
- ```html
335
- <!-- Abrir Modal sem JS -->
336
- <ui-botao-primario target-modal="modal-exclusao" variante="destrutivo">
337
- Excluir Registro
338
- </ui-botao-primario>
339
-
340
- <!-- Modal com Fechamento e Toast automáticos -->
341
- <ui-modal id="modal-exclusao" titulo="Confirmação">
342
- Tem certeza que deseja excluir?
343
- <div slot="rodape">
344
- <ui-botao-primario dismiss-modal variante="secundario">Cancelar</ui-botao-primario>
345
- <ui-botao-primario dismiss-modal toast-sucesso="Excluído com sucesso!" variante="destrutivo">
346
- Confirmar
347
- </ui-botao-primario>
348
- </div>
349
- </ui-modal>
350
-
351
- <!-- Copiar Texto em 1 Clique -->
352
- <ui-campo-texto id="input-token" value="SIGEF-2026-X88"></ui-campo-texto>
353
- <ui-botao-primario copiar-texto="#input-token" copiar-mensagem="Token copiado!">
354
- Copiar Chave
355
- </ui-botao-primario>
356
- ```
357
-
358
- #### Tabela de Atributos Zero-JS Disponíveis:
359
- | Atributo | Descrição | Exemplo de Uso |
360
- | :--- | :--- | :--- |
361
- | `target-modal="id"` | Abre o modal com o ID especificado ao clicar. | `target-modal="modal-login"` |
362
- | `dismiss-modal` | Fecha o modal atual (ou o especificado por ID). | `dismiss-modal` |
363
- | `toast-sucesso="msg"` | Dispara uma notificação flutuante de sucesso. | `toast-sucesso="Salvo com sucesso!"` |
364
- | `toast-erro="msg"` | Dispara uma notificação flutuante de erro. | `toast-erro="Falha na conexão."` |
365
- | `toast-alerta="msg"` | Dispara uma notificação flutuante de aviso. | `toast-alerta="Preencha os campos obrigatórios."` |
366
- | `copiar-texto="texto\|#id"` | Copia o texto ou o valor do elemento referenciado. | `copiar-texto="#campo-pix"` |
367
- | `limpar-form="id"` | Reseta todos os campos do formulário indicado. | `limpar-form="form-cadastro"` |
368
- | `alternar-tema` | Alterna entre tema claro e escuro globalmente (a partir do tema em vigor, inclusive o do SO). | `alternar-tema` |
369
-
370
- ---
371
-
372
- ### 2. Formulários Automáticos com `FormData` Nativo (W3C FACE)
373
- Todos os campos (`<ui-campo-texto>`, `<ui-lista-flutuante>`, `<ui-checkbox>`, `<ui-radio>`, `<ui-switch>`) implementam a especificação oficial de **Form-Associated Custom Elements**.
374
-
375
- Isso significa que você extrai os dados de todos os campos de uma única vez, sem ler um por um:
376
-
377
- ```html
378
- <form id="form-imovel">
379
- <ui-campo-texto name="denominacao" label="Nome da Fazenda" value="Boa Vista"></ui-campo-texto>
380
- <ui-campo-texto name="municipio" label="Município" value="Uberlândia"></ui-campo-texto>
381
- <ui-checkbox name="georreferenciado" label="Georreferenciado" marcado value="sim"></ui-checkbox>
382
-
383
- <ui-botao-primario type="submit">Salvar Imóvel</ui-botao-primario>
384
- </form>
385
- ```
386
-
387
- ```javascript
388
- const form = document.getElementById('form-imovel');
389
-
390
- form.addEventListener('submit', (e) => {
391
- e.preventDefault();
392
-
393
- // Extrai TODOS os campos em 1 única linha nativa:
394
- const dados = Object.fromEntries(new FormData(form));
395
- console.log(dados);
396
- // Resultado: { denominacao: "Boa Vista", municipio: "Uberlândia", georreferenciado: "sim" }
397
- });
398
- ```
399
-
400
- Assim como nos campos nativos, **Enter** em um `<ui-campo-texto>` submete o formulário pelo botão de envio padrão (`<ui-botao-primario type="submit">` ou `<button>`), que também pode estar fora do `<form>` com `form="id-do-form"`. Para impedir, chame `preventDefault()` no `keydown`. O `name`/`value` do botão que submeteu chega como `e.submitter` (use `new FormData(form, e.submitter)`), e gatilhos Zero-JS em botões `disabled` ou `carregando` são ignorados.
401
-
402
- ---
403
-
404
- ### 3. Barramento Global de Orquestração (`UIBus`)
405
- O `UIBus` é uma central reativa que permite comandar qualquer componente do sistema ou ouvir eventos sem precisar de `querySelector`:
406
-
407
- ```javascript
408
- import { UIBus } from '@thibezer/ui-components-kit';
409
-
410
- // 1. Executar Ações Diretas:
411
- UIBus.abrirModal('modal-confirmacao');
412
- UIBus.fecharModal('modal-confirmacao');
413
- UIBus.notificar({ tipo: 'sucesso', mensagem: 'Operação concluída!' });
414
- UIBus.copiar('Texto para a área de transferência', 'Copiado!');
415
- UIBus.definirDensidade('compacta'); // 'compacta' | 'normal' | 'relaxada'
416
- UIBus.definirTema('escuro'); // 'claro' | 'escuro' | 'auto' (segue o SO); sem argumento, alterna
417
- UIBus.obterTema(); // tema em vigor: 'claro' | 'escuro'
418
-
419
- // 2. Comunicação Desacoplada (Pub/Sub):
420
- UIBus.on('vertice:selecionado', (dadosVertice) => {
421
- console.log('Vértice selecionado em qualquer tela:', dadosVertice);
422
- });
423
-
424
- UIBus.emit('vertice:selecionado', { id: 101, nome: 'M-01', altitude: 432.10 });
425
- ```
426
-
427
- ---
428
-
429
- ### 4. Tabelas Autônomas com Auto-Fetch Remoto
430
- A `<ui-tabela>` pode buscar dados de uma API remota de forma totalmente autônoma, exibindo indicador de loading, tratando erros e permitindo filtragem instantânea:
431
-
432
- ```html
433
- <ui-tabela
434
- id="tabela-vertices"
435
- src="/api/v1/geodesia/vertices"
436
- max-height="400px"
437
- densidade="compacta">
438
- </ui-tabela>
439
- ```
440
-
441
- ```javascript
442
- const tabela = document.getElementById('tabela-vertices');
443
-
444
- // Definir colunas da tabela:
445
- tabela.colunas = [
446
- { id: 'nome_vertice', rotulo: 'Vértice', ordenavel: true },
447
- { id: 'este', rotulo: 'Este (m)', ordenavel: true, alinhamento: 'direita' },
448
- { id: 'norte', rotulo: 'Norte (m)', ordenavel: true, alinhamento: 'direita' }
449
- ];
450
-
451
- // Métodos inteligentes disponíveis na tabela:
452
- tabela.filtrar('M-01'); // Filtra instantaneamente em todas as colunas
453
- tabela.recarregar(); // Recarrega os dados da API remota
454
- ```
455
-
456
- ---
457
-
458
- ## 💻 Exemplos de Uso por Tecnologia
459
-
460
- ### HTML Puro + JavaScript
461
- ```html
462
- <!DOCTYPE html>
463
- <html lang="pt-BR">
464
- <head>
465
- <link rel="stylesheet" href="dist/ui-kit.css">
466
- <script type="module" src="dist/index.js"></script>
467
- </head>
468
- <body>
469
- <ui-campo-texto id="meu-campo" label="Nome do Projeto"></ui-campo-texto>
470
- <ui-botao-primario target-modal="meu-modal">Abrir Detalhes</ui-botao-primario>
471
-
472
- <ui-modal id="meu-modal" titulo="Detalhes">
473
- <p>Conteúdo do modal...</p>
474
- <div slot="rodape">
475
- <ui-botao-primario dismiss-modal>Fechar</ui-botao-primario>
476
- </div>
477
- </ui-modal>
478
-
479
- <script>
480
- document.getElementById('meu-campo').addEventListener('ui-input', (e) => {
481
- console.log('Digitado:', e.detail.value);
482
- });
483
- </script>
484
- </body>
485
- </html>
486
- ```
487
-
488
- ---
489
-
490
- ### React / Next.js (SSR & Client Components)
491
-
492
- A biblioteca é **100% SSR-safe**: todas as classes herdam de `SafeHTMLElement` e o registro de tags utiliza verificações de segurança para ambientes sem DOM (Node.js). Isso garante que você pode importar tipos, classes e constantes tanto no servidor quanto no cliente sem encontrar `ReferenceError: HTMLElement is not defined` ou `customElements is not defined`.
493
-
494
- #### Tipos no TSX (autocompletar e checagem)
495
- O pacote gera tipos para todas as tags a partir do Custom Elements Manifest. Registre-os uma vez no `tsconfig.json`:
496
-
497
- ```json
498
- { "compilerOptions": { "types": ["@thibezer/ui-components-kit/tipos-react"] } }
499
- ```
500
-
501
- A partir daí o editor sugere atributos, propriedades e eventos de cada tag, e o TypeScript recusa valores inválidos:
502
-
503
- ```tsx
504
- <ui-tabela
505
- colunas={[{ id: 'ponto', rotulo: 'Ponto', ordenavel: true }]} // tipado como TabelaColuna[]
506
- densidade="compacta" // 'compacta' | 'normal' | 'relaxada'
507
- onui-sort={(e) => console.log(e.detail)} // eventos ui-* no formato do React 19
508
- />
509
- <ui-tabela densidade="enorme" /> // ❌ erro de tipo
510
- ```
511
-
512
- Outros JSX (Preact, Solid etc.) podem usar o mapa agnóstico `ElementosUI` de `@thibezer/ui-components-kit/tipos-elementos`.
513
-
514
- #### No Next.js (App Router):
515
-
516
- Crie um componente cliente provedor ou registre no topo do seu layout/página cliente:
517
-
518
- ```tsx
519
- // components/UIProvider.tsx
520
- 'use client';
521
-
522
- import { useEffect } from 'react';
523
- import '@thibezer/ui-components-kit/style.css';
524
- import '@thibezer/ui-components-kit/register'; // Registra todos os Custom Elements com segurança no cliente
525
-
526
- export function UIProvider({ children }: { children: React.ReactNode }) {
527
- return <>{children}</>;
528
- }
529
- ```
530
-
531
- Ou registre de forma modular apenas o que a tela precisa:
532
-
533
- ```tsx
534
- // app/dashboard/page.tsx
535
- 'use client';
536
-
537
- import React, { useEffect, useRef, useState } from 'react';
538
- import '@thibezer/ui-components-kit/style.css';
539
- import '@thibezer/ui-components-kit/forms';
540
- import '@thibezer/ui-components-kit/botao';
541
- import '@thibezer/ui-components-kit/tabela';
542
- import { UIBus } from '@thibezer/ui-components-kit/core';
543
- import type { UITabela } from '@thibezer/ui-components-kit/tabela';
544
-
545
- export default function DashboardPropriedades() {
546
- const tabelaRef = useRef<UITabela>(null);
547
- const [nome, setNome] = useState('');
548
-
549
- useEffect(() => {
550
- if (tabelaRef.current) {
551
- tabelaRef.current.colunas = [
552
- { id: 'id', rotulo: 'Código' },
553
- { id: 'nome', rotulo: 'Propriedade' }
554
- ];
555
- tabelaRef.current.dados = [
556
- { id: 1, nome: 'Fazenda Santa Luzia' }
557
- ];
558
- }
559
- }, []);
560
-
561
- return (
562
- <div style={{ padding: 24 }}>
563
- <ui-campo-texto
564
- label="Pesquisar Imóvel"
565
- value={nome}
566
- onInput={(e: any) => {
567
- // Os eventos nativos `input`/`change` não têm `detail`: leia o valor do próprio elemento
568
- const valor = e.target.value;
569
- setNome(valor);
570
- tabelaRef.current?.filtrar(valor);
571
- }}
572
- ></ui-campo-texto>
573
-
574
- <ui-tabela ref={tabelaRef} max-height="300px" densidade="compacta"></ui-tabela>
575
-
576
- <ui-botao-primario
577
- variante="primary"
578
- onClick={() => UIBus.notificar({ tipo: 'sucesso', mensagem: 'Dados sincronizados!' })}>
579
- Sincronizar
580
- </ui-botao-primario>
581
- </div>
582
- );
583
- }
584
- ```
585
-
586
- ---
587
-
588
- ### Vue.js
589
-
590
- Para autocompletar e checar props e eventos nos templates (Volar), registre os tipos no `tsconfig.json` e informe ao Vue que tags `ui-*` são custom elements:
591
-
592
- ```json
593
- { "compilerOptions": { "types": ["@thibezer/ui-components-kit/tipos-vue"] } }
594
- ```
595
-
596
- ```javascript
597
- // vite.config.js
598
- vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('ui-') } } })
599
- ```
600
-
601
- ```vue
602
- <template>
603
- <div class="container">
604
- <ui-campo-texto
605
- :value="termoBusca"
606
- label="Buscar Vértice"
607
- @ui-input="aoDigitar"
608
- />
609
-
610
- <ui-lista-flutuante
611
- .itens="opcoes"
612
- @ui-selecionar="aoSelecionar"
613
- />
614
-
615
- <ui-botao-primario target-modal="modal-confirmacao">
616
- Confirmar Operação
617
- </ui-botao-primario>
618
- </div>
619
- </template>
620
-
621
- <script setup>
622
- import { ref } from 'vue';
623
- import '@thibezer/ui-components-kit/style.css';
624
- import '@thibezer/ui-components-kit';
625
-
626
- const termoBusca = ref('');
627
- const opcoes = ref([
628
- { id: '1', label: 'Marco Geodésico M' },
629
- { id: '2', label: 'Ponto Topográfico P' }
630
- ]);
631
-
632
- function aoDigitar(e) {
633
- termoBusca.value = e.detail.value;
634
- }
635
-
636
- function aoSelecionar(e) {
637
- console.log('Opção selecionada:', e.detail);
638
- }
639
- </script>
640
- ```
641
-
642
- ---
643
-
644
- ### Iframes / Microfrontends
645
- Comunicação segura entre iframes e sistemas pais via eventos do `UIBus`:
646
-
647
- ```javascript
648
- // Dentro do Iframe (Filho):
649
- import { UIBus } from '@thibezer/ui-components-kit';
650
-
651
- UIBus.on('vertice:salvo', (dados) => {
652
- window.parent.postMessage({ tipo: 'VERTICE_SALVO', payload: dados }, '*');
653
- });
654
-
655
- // No Sistema Principal (Pai):
656
- window.addEventListener('message', (event) => {
657
- if (event.data?.tipo === 'VERTICE_SALVO') {
658
- console.log('Recebido do Iframe:', event.data.payload);
659
- }
660
- });
661
- ```
662
-
663
- ---
664
-
665
- ## 🧩 Catálogo de Componentes & Referência
666
-
667
- ### 🟢 Camada 1: Fundamentos
668
- | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
669
- | :--- | :--- | :--- | :--- |
670
- | `<ui-botao-primario>` | Botão com estados de loading, ícone e variantes. Form-associated (`type="submit"`/`"reset"`, `name`/`value`, `form`). Só com ícone, informe `aria-label` (ou `title`). | `variante`, `carregando`, `disabled`, `type`, `aria-label`, `target-modal` | `ui-click` |
671
- | `<ui-campo-texto>` | Input de texto com Floating Label, validação e senha. | `label`, `value`, `tipo`, `obrigatorio`, `name` | `ui-input`, `ui-change` |
672
- | `<ui-lista-flutuante>` | Select/Dropdown com Bottom Sheet no mobile. | `itens`, `value`, `placeholder`, `name` | `ui-selecionar` |
673
- | `<ui-texto>` | Tipografia semântica (H1-H6, corpo, caption, código). | `variante`, `cor`, `peso` | - |
674
- | `<ui-icone>` | Wrapper para ícones vetoriais padronizados. | `nome`, `tamanho`, `cor` | - |
675
-
676
- ### 🔵 Camada 2: Controles & Seleção
677
- | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
678
- | :--- | :--- | :--- | :--- |
679
- | `<ui-checkbox>` | Caixa de seleção múltipla com estado indeterminado. | `marcado`, `indeterminado`, `name`, `value` | `ui-change` |
680
- | `<ui-radio>` | Opção única com agrupamento automático por nome. | `marcado`, `name`, `value` | `ui-change` |
681
- | `<ui-switch>` | Chave de alternância liga/desliga física instantânea. | `ativo`, `name`, `value` | `ui-change` |
682
- | `<ui-segmented>` | Controle segmentado de opções (Pills/Tabs deslizantes). | `opcoes`, `value`, `name`, `tamanho` | `ui-change`, `ui-selecionar` |
683
- | `<ui-badge>` / `<ui-chip>` | Tags de status e chips com botão de remoção. | `variante`, `removivel`, `value` | `ui-remove` |
684
- | `<ui-avatar>` | Avatar com fotos, iniciais e status online. | `nome`, `src`, `status`, `tamanho` | - |
685
-
686
- ### 🟣 Camada 3: Contêineres, Overlays, Dados & GIS
687
- | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
688
- | :--- | :--- | :--- | :--- |
689
- | `<ui-card>` | Cartão de conteúdo com slots nomeados e elevação. | `elevacao`, `clicavel` | `ui-click` |
690
- | `<ui-modal>` | Modal centralizado no PC e Bottom Sheet no Mobile. Abrir/fechar por `abrir()`/`fechar()` ou pelo atributo `aberto` tem o mesmo efeito (eventos, foco, `inert`). Foco inicial no `[autofocus]` ou no primeiro controle do conteúdo; ao fechar, volta ao gatilho. Modais empilhados: só o último aberto é interativo. | `aberto`, `titulo`, `bottom-sheet`, `bloquear-fechamento` (oculta o "✕" e ignora Esc/fundo) | `ui-abrir`, `ui-fechar` |
691
- | `<ui-drawer>` | Painel lateral deslizante (Sheet/Gaveta direita/esquerda). | `aberto`, `posicao` (`direita`, `esquerda`, `baixo`, `cima`), `titulo`, `largura` | `ui-abrir`, `ui-fechar` |
692
- | `<ui-alerta>` | Banner de notificação contextual fixo. | `variante`, `titulo`, `fechavel` | `ui-fechar` |
693
- | `<ui-toast>` | Notificações flutuantes inteligentes com pilha flex. | `UIToast.notificar({ tipo, mensagem })` | - |
694
- | `<ui-tooltip>` | Dica contextual inteligente (Hover PC / Toque Mobile). O texto vira `aria-description` do gatilho (lido pelo leitor de tela, também repassado pelo `<ui-botao>`); **Esc** fecha sem mover o foco; o balão não some ao levar o ponteiro até ele. | `texto`, `posicao`, `gatilho` | - |
695
- | `<ui-skeleton>` | Placeholder de carregamento animado com pulsos. | `tipo`, `largura`, `altura`, `animado` | - |
696
- | `<ui-stat>` | Cartão KPI de estatísticas, métricas e tendências. | `rotulo`, `valor`, `variacao`, `tendencia` (`alta`, `baixa`, `neutro`) | - |
697
- | `<ui-tabela>` | Tabela orientada a dados, virtualizada tipo Excel. **Teclado**: cabeçalhos ordenáveis são botões (Tab + Enter/Espaço, com `aria-sort`); nas linhas, ↑/↓, Home/End e PageUp/PageDown movem o foco e Enter/Espaço selecionam (`aria-current`). A seleção é mantida ao ordenar e filtrar. Nome acessível via `aria-label`. | `colunas`, `dados`, `src`, `densidade`, `aria-label` | `ui-sort`, `ui-column-resize`, `ui-linha-clique` |
698
- | `<ui-tabela-propriedades>` | Inspetor de propriedades técnicas padrão AutoCAD & Revit com cálculos matemáticos inline (+, -, *, /, ^, %), arraste de valor contínuo (scrubbing), splitter redimensionável e editores CAD. | `categorias`, `tipo-objeto`, `splitter-pos`, `modo-aplicar`, `filtro` | `ui-propriedade-alterada`, `ui-aplicar`, `ui-desfazer`, `ui-editar-tipo`, `ui-acao-clique`, `ui-quick-select`, `ui-calculadora` |
699
- | `<ui-ribbon>` | Barra de ferramentas em abas e grupos (estilo AutoCAD / Word / Excel): botões grandes e pequenos em colunas de 3, toggles, menus suspensos, abas contextuais, modo recolhido (duplo clique na aba) e navegação por teclado (roving tabindex). | `abas`, `aba-ativa`, `recolhido`, `compacto` | `ui-ferramenta`, `ui-aba-change` |
700
- | `<ui-paleta-ferramentas>` | Paleta de ferramentas (estilo Illustrator / Photoshop): seleção exclusiva, grupos com flyout (clique longo, botão direito ou seta), 1 ou 2 colunas, vertical/horizontal e atalhos de teclado que percorrem o grupo. | `ferramentas`, `valor`, `orientacao`, `colunas`, `tamanho`, `atalhos` | `ui-change`, `ui-selecionar`, `ui-ferramenta` |
701
- | `<ui-mapa>` | Mapa geográfico interativo com camadas OpenStreetMap. | `lat`, `lng`, `zoom`, `camadas` | - |
702
- | `<ui-camadas>` | Painel de camadas vetoriais CAD/GIS com hierarquia em árvore, barra de arraste vertical (`redimensionavel`), estabilidade de altura sem colapso, drag-and-drop, métricas geodésicas e persistência no LocalStorage. | `redimensionavel`, `altura`, `min-altura`, `max-altura`, `flutuante`, `colapsado`, `camada-ativa`, `persistir` | `ui-redimensionar-altura`, `ui-camada-selecionada`, `ui-camada-visibilidade`, `ui-camadas-reordenadas`, `ui-acao-massa` |
703
- | `<ui-canvas-cad>` | Mesa CAD/GIS para poligonais, vértices geodésicos e **feições genéricas** (ponto, linha, polígono, círculo, texto) que você cria: seleção por clique e caixa, popup, edição de vértices, snap, 15 ferramentas de desenho/medição, oficial × prévia, cursores remotos e culling/clusters para 100 mil feições. Linha multiparte, feição `oculta`, selo de texto e contorno de ponto. Nenhuma camada vem pronta. Guia: [`docs/guia-migracao-mapengine.md`](docs/guia-migracao-mapengine.md). | `pontos`, `segmentos`, `ferramentas`, `sem-camadas-padrao`, `sem-painel-camadas`, `sem-barra-rapida`, `sem-atalho-snap`, `aceitar-origem`, `inicializarAgora()`, `definirFeicoes()`, `aplicarLote()`, `definirFerramenta()`, `editarVertices()`, `definirMargensHud()`, `definirEstilosExternos()`, `fitBounds()` | `ui-ponto-selecionado`, `cad-selecao`, `cad-feicao-selecionada`, `cad-feicao-criada`, `cad-feicao-atualizada`, `cad-feicao-hover`, `cad-feicao-menu`, `cad-snap`, `cad-previas` e outros (ver `docs/canvas-cad-eventos.md`) |
704
-
705
- #### `<ui-canvas-cad>`: montar só com API pública (2.1)
706
-
707
- ```html
708
- <ui-canvas-cad id="mesa" sem-camadas-padrao sem-painel-camadas sem-barra-rapida sem-atalho-snap aceitar-origem></ui-canvas-cad>
709
- ```
710
- ```js
711
- const mapa = mesa.inicializarAgora(); // L.Map síncrono (idempotente; nunca cria um 2º mapa)
712
- mesa.definirEstilosExternos([...document.styleSheets]); // CSS do app dentro do shadow root (string ou folhas)
713
- mesa.definirMargensHud({ base: 56, direita: 320 }); // HUDs de desenho/edição fora de barras e painéis
714
- mesa.aplicarLote('glebas', { adicionar, atualizar, remover }); // uma regravação, ordem preservada
715
- mesa.atualizarFeicao('glebas', 'g1', { propriedades }, { substituirPropriedades: true });
716
- mesa.definirOpcoesPopup({ copiarParaAreaDeTransferencia: false });
717
- ```
718
-
719
- - Camadas de fábrica (satélite, SIGEF, homologados, perímetro, vizinhos, vértices, grade) só somem com `sem-camadas-padrao`; sem
720
- o atributo continuam como sempre.
721
- - `Feicao.oculta` (não desenha nem seleciona, mas existe) ≠ `Feicao.excluida`. Linha multiparte: `geometria.partes`.
722
- - Tudo, com exemplos: [`docs/guia-migracao-mapengine.md`](docs/guia-migracao-mapengine.md) · eventos e ordem das ferramentas:
723
- [`docs/canvas-cad-eventos.md`](docs/canvas-cad-eventos.md) · números de desempenho: [`docs/desempenho-feicoes.md`](docs/desempenho-feicoes.md).
724
-
725
-
726
- ---
727
-
728
- ### Custom Elements Manifest
729
- O pacote publica `custom-elements.json` (campo `customElements` do `package.json`), o formato padrão que IDEs, Storybook e geradores de documentação leem para listar tags, atributos, propriedades, eventos e `::part` de cada componente. Ele é gerado no `npm run build` pelo [`@custom-elements-manifest/analyzer`](https://custom-elements-manifest.open-wc.org/), e os tipos React/Vue são derivados dele — por isso nunca ficam desatualizados em relação ao código.
730
-
731
- ---
732
-
733
- ## 🛠️ Como Executar e Compilar Localmente
734
-
735
- 1. **Instalar Dependências**:
736
- ```bash
737
- npm install
738
- ```
739
-
740
- 2. **Executar o Playground Sandbox em Desenvolvimento**:
741
- ```bash
742
- npm run dev
743
- ```
744
- Acesse: `http://localhost:5173/`
745
-
746
- 3. **Compilar Pacote de Produção (Library Mode)**:
747
- ```bash
748
- npm run build
749
- ```
750
- Gera na pasta `dist/`:
751
- * `dist/index.js` e `dist/<modulo>.js` (Módulos ES para Vite, Webpack, Rollup)
752
- * `dist/index.cjs` e `dist/<modulo>.cjs` (CommonJS para `require`)
753
- * `dist/*.d.ts` (Tipagens TypeScript)
754
- * `dist/ui-kit.css` (Design Tokens compilados, 100% autocontido — o build falha se restar qualquer `@import`)
755
- * `dist/custom-elements.json` (Custom Elements Manifest) e `dist/tipos-react.d.ts`, `dist/tipos-vue.d.ts`, `dist/tipos-elementos.d.ts`
756
-
757
- 4. **Verificar os tipos gerados** (depois do build):
758
- ```bash
759
- npm run test:tipos
760
- ```
1
+ # 🎨 UI Components Kit - Web Components Nativos & Universais
2
+
3
+ Biblioteca de **Web Components Nativos Universais e Agnósticos**, construída no padrão oficial **W3C Custom Elements + Shadow DOM**, com TypeScript, Design Tokens em CSS modular e Vite.
4
+
5
+ Projetada para funcionar em **qualquer linguagem, framework ou sistema web** (HTML puro, React, Next.js, Vue, Angular, Svelte, PHP, Django, WordPress, Blazor, etc.) com **zero dependências externas** (exceto `<ui-mapa>` e `<ui-canvas-cad>`, que usam o Leaflet como dependência opcional).
6
+
7
+ ---
8
+
9
+ ## 📑 Índice
10
+
11
+ 1. [Por que Web Components?](#-por-que-web-components)
12
+ 2. [Como Importar na sua Aplicação](#-como-importar-na-sua-aplicação)
13
+ - [Opção 1: CDN / Script Tag (HTML puro, PHP, Django)](#opção-1-cdn--script-tag-html-puro-php-django)
14
+ - [Opção 2: NPM / Módulos ES (React, Vue, Next.js, Vite)](#opção-2-npm--módulos-es-react-vue-nextjs-vite)
15
+ 3. [Como Controlar os Componentes (5 Pilares)](#-como-controlar-os-componentes-5-pilares)
16
+ 4. [⚡ Recursos Inteligentes de Alta Produtividade](#-recursos-inteligentes-de-alta-produtividade)
17
+ - [Ações Declarativas "Zero-JS" (Triggers Nativos)](#1-ações-declarativas-zero-js-triggers-nativos)
18
+ - [Formulários Automáticos com FormData Nativo (W3C FACE)](#2-formulários-automáticos-com-formdata-nativo-w3c-face)
19
+ - [Barramento Global de Orquestração (UIBus)](#3-barramento-global-de-orquestração-uibus)
20
+ - [Tabelas Autônomas com Auto-Fetch Remoto](#4-tabelas-autônomas-com-auto-fetch-remoto)
21
+ 5. [💻 Exemplos de Uso por Tecnologia](#-exemplos-de-uso-por-tecnologia)
22
+ - [HTML Puro + JavaScript](#html-puro--javascript)
23
+ - [React / Next.js](#react--nextjs)
24
+ - [Vue.js](#vuejs)
25
+ - [Iframes / Microfrontends](#iframes--microfrontends)
26
+ 6. [🧩 Catálogo de Componentes & Referência](#-catálogo-de-componentes--referência)
27
+ 7. [🛠️ Como Executar e Compilar Localmente](#️-como-executar-e-compilar-localmente)
28
+
29
+ ---
30
+
31
+ ## 🎯 Por que Web Components?
32
+
33
+ * 🌐 **100% Universal e Agnóstico**: Funciona em qualquer stack sem necessidade de bibliotecas intermediárias.
34
+ * 🛡️ **Encapsulamento Total (Shadow DOM)**: O CSS da sua aplicação nunca quebra o componente, e o CSS do componente nunca vaza para o seu site.
35
+ * 📐 **Design Tokens Centralizados**: Variáveis CSS personalizáveis para cores, tipografia, raios e densidade.
36
+ * 🚀 **Suporte a Altíssima Densidade**: Otimizado para interfaces densas e técnicas (GIS, CAD, Topografia de 15px a 20px de altura) até interfaces fluidas modernas.
37
+
38
+ ---
39
+
40
+ ## 📦 Como Importar na sua Aplicação
41
+
42
+ ### Opção 1: CDN / Script Tag (HTML puro, PHP, Django)
43
+
44
+ Adicione as tags no `<head>` ou antes do fechamento do `</body>`:
45
+
46
+ ```html
47
+ <!-- 1. Design Tokens e Estilos Globais -->
48
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@thibezer/ui-components-kit@1/dist/ui-kit.css">
49
+
50
+ <!-- 2. Biblioteca dos Componentes (Módulo ES) -->
51
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@thibezer/ui-components-kit@1/dist/index.js"></script>
52
+
53
+ <!-- 3. Uso imediato no HTML -->
54
+ <ui-botao-primario variante="primary">Clique Aqui</ui-botao-primario>
55
+ ```
56
+
57
+ > **Mapa e CAD via CDN (`<ui-mapa>`, `<ui-canvas-cad>`)**: esses componentes dependem do [Leaflet](https://leafletjs.com/), importado como `leaflet` (especificador "bare"), que o navegador só resolve com um *import map*. Declare-o **antes** do script da biblioteca:
58
+ >
59
+ > ```html
60
+ > <script type="importmap">
61
+ > { "imports": { "leaflet": "https://cdn.jsdelivr.net/npm/leaflet@1.9.4/+esm" } }
62
+ > </script>
63
+ > ```
64
+ >
65
+ > Os demais componentes não precisam do Leaflet. Com npm, basta `npm install leaflet`.
66
+
67
+ ### Opção 2: NPM / Módulos ES (React, Vue, Next.js, Vite)
68
+
69
+ Instale pelo npm:
70
+
71
+ ```bash
72
+ npm install @thibezer/ui-components-kit
73
+ ```
74
+
75
+ > O pacote é publicado já compilado (`dist/`) e **não executa build na instalação**, então funciona em CI/CD e em servidores com `npm ci --omit=dev`. A antiga instalação por URL Git (`git+https://github.com/...`) não é mais suportada: o repositório não versiona `dist/`.
76
+
77
+ No ponto de entrada da sua aplicação (`main.ts`, `index.js` ou `App.tsx`):
78
+
79
+ ```typescript
80
+ // 1. Estilos globais obrigatórios (tokens CSS)
81
+ import '@thibezer/ui-components-kit/style.css';
82
+
83
+ // 2. Biblioteca completa (ou escolha os submódulos abaixo)
84
+ import '@thibezer/ui-components-kit';
85
+ ```
86
+
87
+ #### 🚀 Importação Modular e Otimizada (Sub-paths)
88
+
89
+ Pague apenas pelo que utilizar. Importe por domínio de funcionalidade ou por componente específico:
90
+
91
+ O export map expõe explicitamente os pontos de entrada canônicos (ESM em `.js`, CommonJS em `.cjs` e tipos `.d.ts`):
92
+
93
+ | Subpath | Arquivo (ESM) |
94
+ |---|---|
95
+ | `@thibezer/ui-components-kit` | `dist/index.js` |
96
+ | `@thibezer/ui-components-kit/camadas` | `dist/camadas.js` |
97
+ | `@thibezer/ui-components-kit/forms` | `dist/forms.js` |
98
+ | `@thibezer/ui-components-kit/feedback` | `dist/feedback.js` |
99
+ | `@thibezer/ui-components-kit/tabela` | `dist/tabela.js` |
100
+ | `@thibezer/ui-components-kit/style.css` | `dist/ui-kit.css` (100% autocontido, sem `@import`) |
101
+
102
+ ##### 1. Por Domínio / Categoria:
103
+ ```typescript
104
+ import '@thibezer/ui-components-kit/forms'; // Campos, Select, Checkbox, Radio, Switch (~8 kB gzip)
105
+ import '@thibezer/ui-components-kit/feedback'; // Modais, Drawers, Alertas, Toasts, Tooltips, Skeletons (~6 kB gzip)
106
+ import '@thibezer/ui-components-kit/data'; // Tabela, Tabela-Propriedades, Stat KPI, Badge (~4 kB gzip)
107
+ import '@thibezer/ui-components-kit/tools'; // Ribbon CAD/Office e Paleta de Ferramentas (~10 kB gzip)
108
+ import '@thibezer/ui-components-kit/core'; // Apenas UIBus, Zero-JS e ListenerBag (< 1 kB gzip)
109
+ import '@thibezer/ui-components-kit/canvas'; // Mesa CAD vetorial e motor GIS (~33 kB gzip)
110
+ import '@thibezer/ui-components-kit/camadas'; // Painel de Camadas GIS/CAD redimensionável (~21 kB gzip)
111
+ import '@thibezer/ui-components-kit/mapa'; // Mapa Geográfico Leaflet (~3 kB gzip)
112
+ ```
113
+
114
+ ##### 2. Granular por Componente (Ultra Leve):
115
+ ```typescript
116
+ import '@thibezer/ui-components-kit/botao'; // Apenas <ui-botao> e <ui-botao-primario> (~3.4 kB gzip)
117
+ import '@thibezer/ui-components-kit/campo-texto'; // Apenas <ui-campo-texto> com FACE e anti-zoom (~3.9 kB gzip)
118
+ import '@thibezer/ui-components-kit/modal'; // Apenas <ui-modal> com bottom-sheet mobile (~3.3 kB gzip)
119
+ import '@thibezer/ui-components-kit/card'; // Apenas <ui-card> com elevação (~2.3 kB gzip)
120
+ import '@thibezer/ui-components-kit/tabela'; // Apenas <ui-tabela> virtualizada
121
+ ```
122
+
123
+ > **Zero Overhead**: Uma tela que utilize apenas `<ui-botao>` e `<ui-campo-texto>` importa menos de **8 kB gzip**, sem carregar nada de Leaflet, CAD, GIS ou virtualização.
124
+
125
+ ---
126
+
127
+ ## 🎛️ Como Controlar os Componentes (5 Pilares)
128
+
129
+ ```text
130
+ ┌─────────────────────────────────────────────────────────────┐
131
+ │ SISTEMA EXTERNO │
132
+ └──────┬───────────────▲─────────────────┬─────────────────▲──┘
133
+ │ │ │ │
134
+ 1. Atributos 4. Eventos Custom 2. Propriedades 3. Métodos
135
+ (HTML) (ui-*) (Objetos/Listas) (Imperativo)
136
+ │ │ │ │
137
+ ┌──────▼───────────────┴─────────────────▼─────────────────┴──┐
138
+ │ WEB COMPONENT (<ui-*>) │
139
+ └─────────────────────────────────────────────────────────────┘
140
+ ```
141
+
142
+ ### 1. Atributos HTML (Controle Declarativo)
143
+ Configurações simples passadas diretamente nas tags:
144
+ ```html
145
+ <ui-campo-texto label="CPF" placeholder="000.000.000-00" obrigatorio></ui-campo-texto>
146
+ <ui-modal id="meu-modal" titulo="Confirmar Exclusão"></ui-modal>
147
+ ```
148
+
149
+ ---
150
+
151
+ ### 📏 Ajuste de Altura e Dimensionamento Inteligente (Zero Atrito)
152
+
153
+ Os campos de texto (`<ui-campo-texto>`), listas flutuantes/selects (`<ui-lista-flutuante>`, `<ui-select>`) e botões (`<ui-botao-primario>`) possuem 4 formas flexíveis de ajuste de altura:
154
+
155
+ #### 1. Via Atributo de Tamanho Predefinido (`tamanho` ou `densidade`):
156
+ ```html
157
+ <!-- Compacto (26px) - Ideal para Toolbars CAD/GIS, tabelas e alta densidade -->
158
+ <ui-campo-texto tamanho="sm" placeholder="26px Compacto"></ui-campo-texto>
159
+ <ui-lista-flutuante tamanho="sm" placeholder="Selecione..."></ui-lista-flutuante>
160
+
161
+ <!-- Padrão (34px) - Padrão moderno e equilibrado para formulários e modais -->
162
+ <ui-campo-texto tamanho="md" placeholder="34px Padrão"></ui-campo-texto>
163
+ <ui-lista-flutuante tamanho="md" placeholder="Selecione..."></ui-lista-flutuante>
164
+
165
+ <!-- Conforto / Touch (42px) - Otimizado para dispositivos móveis e telas sensíveis ao toque -->
166
+ <ui-campo-texto tamanho="lg" placeholder="42px Conforto"></ui-campo-texto>
167
+ <ui-lista-flutuante tamanho="lg" placeholder="Selecione..."></ui-lista-flutuante>
168
+ ```
169
+
170
+ #### 2. Via Atributo de Altura Explícita (`altura` ou `height`):
171
+ ```html
172
+ <!-- Define a altura exata em pixels diretamente no elemento -->
173
+ <ui-campo-texto altura="38" placeholder="Altura de 38px"></ui-campo-texto>
174
+ <ui-lista-flutuante altura="44px" placeholder="Altura de 44px"></ui-lista-flutuante>
175
+ <ui-botao-primario altura="40">Salvar</ui-botao-primario>
176
+ ```
177
+
178
+ #### 3. Via Variável CSS Customizável (`--ui-campo-altura`):
179
+ ```css
180
+ /* No seu CSS global ou no container pai */
181
+ .meu-formulario {
182
+ --ui-campo-altura: 36px; /* Aplica instantaneamente em todos os inputs, selects e botões filhos */
183
+ }
184
+ ```
185
+
186
+ #### 4. Via Barramento Global de Densidade (`UIBus`):
187
+ ```javascript
188
+ import { UIBus } from '@thibezer/ui-components-kit';
189
+
190
+ // Altera a densidade de toda a aplicação em tempo real:
191
+ UIBus.definirDensidade('compacta'); // 26px
192
+ UIBus.definirDensidade('padrao'); // 34px
193
+ UIBus.definirDensidade('relaxada'); // 42px
194
+ UIBus.definirDensidade(38); // Valor numérico em px customizado
195
+ ```
196
+
197
+ ---
198
+
199
+ ### 2. Propriedades JavaScript (Dados Complexos)
200
+ Para enviar arrays e objetos complexos:
201
+ ```javascript
202
+ const tabela = document.querySelector('ui-tabela');
203
+ tabela.colunas = [
204
+ { id: 'ponto', rotulo: 'Ponto', ordenavel: true },
205
+ { id: 'altitude', rotulo: 'Altitude (m)' }
206
+ ];
207
+ tabela.dados = [
208
+ { ponto: 'P-01', altitude: '542,15' },
209
+ { ponto: 'P-02', altitude: '545,30' }
210
+ ];
211
+ ```
212
+
213
+ ### 3. Métodos Imperativos (Ações Diretas)
214
+ Comandos diretos chamados na instância do elemento:
215
+ ```javascript
216
+ const modal = document.getElementById('meu-modal');
217
+ modal.abrir();
218
+ modal.fechar();
219
+ ```
220
+
221
+ ### 4. Eventos Customizados Nativos (`ui-*`)
222
+ Escuta de eventos disparados pelas interações do usuário:
223
+ ```javascript
224
+ const campo = document.querySelector('ui-campo-texto');
225
+ campo.addEventListener('ui-input', (e) => {
226
+ console.log('Texto digitado:', e.detail.value);
227
+ });
228
+ ```
229
+
230
+ > **Mutação de usuário vs. programática (`<ui-camadas>`)**: eventos saem do componente **somente** em resposta a interações físicas (clique, drag-and-drop, teclado). Atribuir `painel.layers = [...]`, alterar atributos (`camada-ativa`, `colapsado`, `mapa-base-ativo`...) ou chamar métodos públicos (`definirCamadaAtiva`, `selecionarFeicao`, `limparSelecao`, `colapsar`, `definirAltura`...) apenas atualiza o DOM interno — sem redisparar eventos. Isso elimina loops de sincronização em apps reativos (React, Vue, Svelte). Para forçar a emissão numa chamada programática, passe `emitirEvento = true` (ex.: `painel.definirCamadaAtiva('lotes', true)`).
231
+
232
+ ### 5. Serviços Globais e Helpers
233
+ Utilitários prontos para uso sem necessidade de instanciar elementos:
234
+ ```javascript
235
+ import { UIToast, UIBus } from '@thibezer/ui-components-kit';
236
+
237
+ UIToast.notificar({
238
+ tipo: 'sucesso',
239
+ titulo: 'Registro Salvo!',
240
+ mensagem: 'Os dados foram sincronizados.',
241
+ duracao: 4000
242
+ });
243
+ ```
244
+
245
+ ### 6. Escala de Elevação (z-index)
246
+ Todos os componentes flutuantes consomem tokens de elevação previsíveis (com fallback), definidos em `ui-kit.css`. Sobrescreva-os no `:root` da aplicação para encaixar a pilha do kit entre os HUDs e modais do seu app:
247
+ ```css
248
+ :root {
249
+ --ui-z-workspace-hud: 500; /* <ui-camadas flutuante>, <ui-seletor-mapa-base>, toolbars do canvas */
250
+ --ui-z-docked-bar: 600; /* <ui-ribbon> recolhido, <ui-tabela-propriedades flutuante> */
251
+ --ui-z-drawer: 700; /* <ui-drawer> e backdrop */
252
+ --ui-z-modal: 1000; /* <ui-modal> e backdrop */
253
+ --ui-z-popover: 1050; /* menus suspensos/contexto, <ui-select> (acima do modal, funciona dentro dele) */
254
+ --ui-z-toast: 1100; /* UIToast */
255
+ --ui-z-tooltip: 1200; /* <ui-tooltip> */
256
+ }
257
+ ```
258
+
259
+ ### 7. Acessibilidade Nativa de Rótulos
260
+ `<ui-input>` (alias de `<ui-campo-texto>`), `<ui-select>` e `<ui-switch>` geram IDs únicos internamente e associam o rótulo visível ao controle nativo do Shadow DOM — o projeto consumidor não precisa gerenciar IDs:
261
+ ```html
262
+ <ui-input label="Nome"></ui-input> <!-- <label for> ↔ <input> interno -->
263
+ <ui-select label="Cidade">...</ui-select> <!-- aria-labelledby = rótulo + valor atual -->
264
+ <ui-switch label="Modo escuro"></ui-switch> <!-- role="switch" aria-labelledby -->
265
+
266
+ <!-- Sem o atributo label, o nome acessível vem de fora do Shadow DOM: -->
267
+ <label>Telefone <ui-input></ui-input></label>
268
+ <ui-switch aria-label="Camada visível"></ui-switch>
269
+ ```
270
+
271
+ ### 8. Temas Claro e Escuro
272
+ Sem configuração, o kit **segue o tema do sistema operacional** (`prefers-color-scheme`). Para fixar um tema, use o atributo na raiz — ou em qualquer elemento, para fixar só aquele trecho:
273
+ ```html
274
+ <html data-tema="escuro"> <!-- ou "claro"; também aceitos: class="dark|light" e data-theme="dark|light" -->
275
+ <aside data-tema="claro">…</aside> <!-- trecho claro dentro de uma página escura -->
276
+ ```
277
+ ```javascript
278
+ UIBus.definirTema('auto'); // volta a seguir o SO
279
+ UIBus.on('tema:alterado', ({ tema }) => { /* também dispara quando o SO muda, se o tema não estiver fixado */ });
280
+ ```
281
+ Os componentes recebem o tema **apenas pelos tokens de cor** (`--ui-cor-*`, `--ui-sombra-*`), que atravessam o Shadow DOM. Todo token de texto atinge contraste **WCAG AA (4,5:1)** nos dois temas, inclusive sobre fundos tingidos de status e no texto sobre a cor primária e o botão destrutivo — verificado em `tests/tema.test.ts`.
282
+
283
+ | Token | Uso |
284
+ | :--- | :--- |
285
+ | `--ui-cor-texto-sucesso` / `-erro` / `-alerta` / `-info` | Texto e tons de status (alertas, badges, toasts) |
286
+ | `--ui-cor-texto-sobre-status` | Texto sobre fundo sólido de status (badge sólido) |
287
+ | `--ui-cor-fundo-recuado` | Faixas rebaixadas (rodapés de modal e drawer) |
288
+ | `--ui-sombra-sm` / `-md` / `-lg` | Sombras: densas no escuro, suaves no claro |
289
+
290
+ ### 9. Tipografia e Raios
291
+ Todos os componentes usam apenas dois tokens de família de fonte e uma escala de raios derivada de `--ui-raio-borda`. Sobrescreva no `:root` (a escala é calculada lá):
292
+ ```css
293
+ :root {
294
+ --ui-fonte-base: 'Roboto', sans-serif; /* textos da interface */
295
+ --ui-fonte-codigo: 'JetBrains Mono', monospace; /* coordenadas, valores técnicos, código */
296
+
297
+ --ui-raio-borda: 4px; /* base: botões, campos, menus */
298
+ /* derivados automaticamente: --ui-raio-sm (2/3), --ui-raio-lg (5/3), --ui-raio-xl (8/3) */
299
+ /* --ui-raio-borda: 0 → interface totalmente reta */
300
+ }
301
+ ```
302
+
303
+ ### 10. Estilização Interna com `::part`
304
+ O Shadow DOM isola o CSS, mas os elementos internos principais são expostos com `part`, com nomes consistentes entre componentes (uma regra serve para vários):
305
+
306
+ | Componente | Parts |
307
+ | :--- | :--- |
308
+ | `<ui-botao>` / `<ui-botao-primario>` | `base`, `spinner` |
309
+ | `<ui-campo-texto>` / `<ui-input>` | `rotulo`, `campo`, `input`, `icone`, `icone-esquerda`, `icone-direita`, `ajuda` |
310
+ | `<ui-lista-flutuante>` / `<ui-select>` | `rotulo`, `campo`, `valor`, `seta`, `lista`, `opcao`, `opcao-selecionada` |
311
+ | `<ui-checkbox>`, `<ui-radio>`, `<ui-switch>` | `base`, `controle`, `indicador`, `rotulo` |
312
+ | `<ui-segmented>` | `base`, `indicador`, `opcao`, `opcao-selecionada` |
313
+ | `<ui-modal>`, `<ui-drawer>` | `fundo`, `painel`, `cabecalho`, `titulo`, `descricao` (drawer), `fechar`, `corpo`, `rodape` |
314
+ | `<ui-card>` | `base`, `midia`, `cabecalho`, `corpo`, `rodape` |
315
+ | `<ui-badge>` / `<ui-chip>` | `base`, `rotulo`, `remover` |
316
+ | `<ui-alerta>` / toasts | `base`, `icone`, `conteudo`, `titulo`, `mensagem`, `acao`, `fechar`, `progresso` |
317
+ | `<ui-tooltip>` | `balao`, `texto`, `seta` |
318
+ | `<ui-tabela>` | `base`, `tabela`, `celula-cabecalho`, `ordenar`, `linha`, `linha-selecionada`, `celula`, `vazio`, `carregando` |
319
+
320
+ ```css
321
+ ui-campo-texto::part(campo) { border-width: 2px; }
322
+ ui-modal::part(painel) { max-width: 720px; }
323
+ ui-tabela::part(linha-selecionada) { background: #0b3d2a; }
324
+ :is(ui-checkbox, ui-radio, ui-switch)::part(rotulo) { font-weight: 600; }
325
+ ```
326
+
327
+ ---
328
+
329
+ ## ⚡ Recursos Inteligentes de Alta Produtividade
330
+
331
+ ### 1. Ações Declarativas "Zero-JS" (Triggers Nativos)
332
+ Você pode acionar modais, fechar janelas, disparar notificações toast ou copiar textos **sem escrever nenhuma linha de JavaScript**, apenas adicionando atributos nas tags HTML:
333
+
334
+ ```html
335
+ <!-- Abrir Modal sem JS -->
336
+ <ui-botao-primario target-modal="modal-exclusao" variante="destrutivo">
337
+ Excluir Registro
338
+ </ui-botao-primario>
339
+
340
+ <!-- Modal com Fechamento e Toast automáticos -->
341
+ <ui-modal id="modal-exclusao" titulo="Confirmação">
342
+ Tem certeza que deseja excluir?
343
+ <div slot="rodape">
344
+ <ui-botao-primario dismiss-modal variante="secundario">Cancelar</ui-botao-primario>
345
+ <ui-botao-primario dismiss-modal toast-sucesso="Excluído com sucesso!" variante="destrutivo">
346
+ Confirmar
347
+ </ui-botao-primario>
348
+ </div>
349
+ </ui-modal>
350
+
351
+ <!-- Copiar Texto em 1 Clique -->
352
+ <ui-campo-texto id="input-token" value="SIGEF-2026-X88"></ui-campo-texto>
353
+ <ui-botao-primario copiar-texto="#input-token" copiar-mensagem="Token copiado!">
354
+ Copiar Chave
355
+ </ui-botao-primario>
356
+ ```
357
+
358
+ #### Tabela de Atributos Zero-JS Disponíveis:
359
+ | Atributo | Descrição | Exemplo de Uso |
360
+ | :--- | :--- | :--- |
361
+ | `target-modal="id"` | Abre o modal com o ID especificado ao clicar. | `target-modal="modal-login"` |
362
+ | `dismiss-modal` | Fecha o modal atual (ou o especificado por ID). | `dismiss-modal` |
363
+ | `toast-sucesso="msg"` | Dispara uma notificação flutuante de sucesso. | `toast-sucesso="Salvo com sucesso!"` |
364
+ | `toast-erro="msg"` | Dispara uma notificação flutuante de erro. | `toast-erro="Falha na conexão."` |
365
+ | `toast-alerta="msg"` | Dispara uma notificação flutuante de aviso. | `toast-alerta="Preencha os campos obrigatórios."` |
366
+ | `copiar-texto="texto\|#id"` | Copia o texto ou o valor do elemento referenciado. | `copiar-texto="#campo-pix"` |
367
+ | `limpar-form="id"` | Reseta todos os campos do formulário indicado. | `limpar-form="form-cadastro"` |
368
+ | `alternar-tema` | Alterna entre tema claro e escuro globalmente (a partir do tema em vigor, inclusive o do SO). | `alternar-tema` |
369
+
370
+ ---
371
+
372
+ ### 2. Formulários Automáticos com `FormData` Nativo (W3C FACE)
373
+ Todos os campos (`<ui-campo-texto>`, `<ui-lista-flutuante>`, `<ui-checkbox>`, `<ui-radio>`, `<ui-switch>`) implementam a especificação oficial de **Form-Associated Custom Elements**.
374
+
375
+ Isso significa que você extrai os dados de todos os campos de uma única vez, sem ler um por um:
376
+
377
+ ```html
378
+ <form id="form-imovel">
379
+ <ui-campo-texto name="denominacao" label="Nome da Fazenda" value="Boa Vista"></ui-campo-texto>
380
+ <ui-campo-texto name="municipio" label="Município" value="Uberlândia"></ui-campo-texto>
381
+ <ui-checkbox name="georreferenciado" label="Georreferenciado" marcado value="sim"></ui-checkbox>
382
+
383
+ <ui-botao-primario type="submit">Salvar Imóvel</ui-botao-primario>
384
+ </form>
385
+ ```
386
+
387
+ ```javascript
388
+ const form = document.getElementById('form-imovel');
389
+
390
+ form.addEventListener('submit', (e) => {
391
+ e.preventDefault();
392
+
393
+ // Extrai TODOS os campos em 1 única linha nativa:
394
+ const dados = Object.fromEntries(new FormData(form));
395
+ console.log(dados);
396
+ // Resultado: { denominacao: "Boa Vista", municipio: "Uberlândia", georreferenciado: "sim" }
397
+ });
398
+ ```
399
+
400
+ Assim como nos campos nativos, **Enter** em um `<ui-campo-texto>` submete o formulário pelo botão de envio padrão (`<ui-botao-primario type="submit">` ou `<button>`), que também pode estar fora do `<form>` com `form="id-do-form"`. Para impedir, chame `preventDefault()` no `keydown`. O `name`/`value` do botão que submeteu chega como `e.submitter` (use `new FormData(form, e.submitter)`), e gatilhos Zero-JS em botões `disabled` ou `carregando` são ignorados.
401
+
402
+ ---
403
+
404
+ ### 3. Barramento Global de Orquestração (`UIBus`)
405
+ O `UIBus` é uma central reativa que permite comandar qualquer componente do sistema ou ouvir eventos sem precisar de `querySelector`:
406
+
407
+ ```javascript
408
+ import { UIBus } from '@thibezer/ui-components-kit';
409
+
410
+ // 1. Executar Ações Diretas:
411
+ UIBus.abrirModal('modal-confirmacao');
412
+ UIBus.fecharModal('modal-confirmacao');
413
+ UIBus.notificar({ tipo: 'sucesso', mensagem: 'Operação concluída!' });
414
+ UIBus.copiar('Texto para a área de transferência', 'Copiado!');
415
+ UIBus.definirDensidade('compacta'); // 'compacta' | 'normal' | 'relaxada'
416
+ UIBus.definirTema('escuro'); // 'claro' | 'escuro' | 'auto' (segue o SO); sem argumento, alterna
417
+ UIBus.obterTema(); // tema em vigor: 'claro' | 'escuro'
418
+
419
+ // 2. Comunicação Desacoplada (Pub/Sub):
420
+ UIBus.on('vertice:selecionado', (dadosVertice) => {
421
+ console.log('Vértice selecionado em qualquer tela:', dadosVertice);
422
+ });
423
+
424
+ UIBus.emit('vertice:selecionado', { id: 101, nome: 'M-01', altitude: 432.10 });
425
+ ```
426
+
427
+ ---
428
+
429
+ ### 4. Tabelas Autônomas com Auto-Fetch Remoto
430
+ A `<ui-tabela>` pode buscar dados de uma API remota de forma totalmente autônoma, exibindo indicador de loading, tratando erros e permitindo filtragem instantânea:
431
+
432
+ ```html
433
+ <ui-tabela
434
+ id="tabela-vertices"
435
+ src="/api/v1/geodesia/vertices"
436
+ max-height="400px"
437
+ densidade="compacta">
438
+ </ui-tabela>
439
+ ```
440
+
441
+ ```javascript
442
+ const tabela = document.getElementById('tabela-vertices');
443
+
444
+ // Definir colunas da tabela:
445
+ tabela.colunas = [
446
+ { id: 'nome_vertice', rotulo: 'Vértice', ordenavel: true },
447
+ { id: 'este', rotulo: 'Este (m)', ordenavel: true, alinhamento: 'direita' },
448
+ { id: 'norte', rotulo: 'Norte (m)', ordenavel: true, alinhamento: 'direita' }
449
+ ];
450
+
451
+ // Métodos inteligentes disponíveis na tabela:
452
+ tabela.filtrar('M-01'); // Filtra instantaneamente em todas as colunas
453
+ tabela.recarregar(); // Recarrega os dados da API remota
454
+ ```
455
+
456
+ ---
457
+
458
+ ## 💻 Exemplos de Uso por Tecnologia
459
+
460
+ ### HTML Puro + JavaScript
461
+ ```html
462
+ <!DOCTYPE html>
463
+ <html lang="pt-BR">
464
+ <head>
465
+ <link rel="stylesheet" href="dist/ui-kit.css">
466
+ <script type="module" src="dist/index.js"></script>
467
+ </head>
468
+ <body>
469
+ <ui-campo-texto id="meu-campo" label="Nome do Projeto"></ui-campo-texto>
470
+ <ui-botao-primario target-modal="meu-modal">Abrir Detalhes</ui-botao-primario>
471
+
472
+ <ui-modal id="meu-modal" titulo="Detalhes">
473
+ <p>Conteúdo do modal...</p>
474
+ <div slot="rodape">
475
+ <ui-botao-primario dismiss-modal>Fechar</ui-botao-primario>
476
+ </div>
477
+ </ui-modal>
478
+
479
+ <script>
480
+ document.getElementById('meu-campo').addEventListener('ui-input', (e) => {
481
+ console.log('Digitado:', e.detail.value);
482
+ });
483
+ </script>
484
+ </body>
485
+ </html>
486
+ ```
487
+
488
+ ---
489
+
490
+ ### React / Next.js (SSR & Client Components)
491
+
492
+ A biblioteca é **100% SSR-safe**: todas as classes herdam de `SafeHTMLElement` e o registro de tags utiliza verificações de segurança para ambientes sem DOM (Node.js). Isso garante que você pode importar tipos, classes e constantes tanto no servidor quanto no cliente sem encontrar `ReferenceError: HTMLElement is not defined` ou `customElements is not defined`.
493
+
494
+ #### Tipos no TSX (autocompletar e checagem)
495
+ O pacote gera tipos para todas as tags a partir do Custom Elements Manifest. Registre-os uma vez no `tsconfig.json`:
496
+
497
+ ```json
498
+ { "compilerOptions": { "types": ["@thibezer/ui-components-kit/tipos-react"] } }
499
+ ```
500
+
501
+ A partir daí o editor sugere atributos, propriedades e eventos de cada tag, e o TypeScript recusa valores inválidos:
502
+
503
+ ```tsx
504
+ <ui-tabela
505
+ colunas={[{ id: 'ponto', rotulo: 'Ponto', ordenavel: true }]} // tipado como TabelaColuna[]
506
+ densidade="compacta" // 'compacta' | 'normal' | 'relaxada'
507
+ onui-sort={(e) => console.log(e.detail)} // eventos ui-* no formato do React 19
508
+ />
509
+ <ui-tabela densidade="enorme" /> // ❌ erro de tipo
510
+ ```
511
+
512
+ Outros JSX (Preact, Solid etc.) podem usar o mapa agnóstico `ElementosUI` de `@thibezer/ui-components-kit/tipos-elementos`.
513
+
514
+ #### No Next.js (App Router):
515
+
516
+ Crie um componente cliente provedor ou registre no topo do seu layout/página cliente:
517
+
518
+ ```tsx
519
+ // components/UIProvider.tsx
520
+ 'use client';
521
+
522
+ import { useEffect } from 'react';
523
+ import '@thibezer/ui-components-kit/style.css';
524
+ import '@thibezer/ui-components-kit/register'; // Registra todos os Custom Elements com segurança no cliente
525
+
526
+ export function UIProvider({ children }: { children: React.ReactNode }) {
527
+ return <>{children}</>;
528
+ }
529
+ ```
530
+
531
+ Ou registre de forma modular apenas o que a tela precisa:
532
+
533
+ ```tsx
534
+ // app/dashboard/page.tsx
535
+ 'use client';
536
+
537
+ import React, { useEffect, useRef, useState } from 'react';
538
+ import '@thibezer/ui-components-kit/style.css';
539
+ import '@thibezer/ui-components-kit/forms';
540
+ import '@thibezer/ui-components-kit/botao';
541
+ import '@thibezer/ui-components-kit/tabela';
542
+ import { UIBus } from '@thibezer/ui-components-kit/core';
543
+ import type { UITabela } from '@thibezer/ui-components-kit/tabela';
544
+
545
+ export default function DashboardPropriedades() {
546
+ const tabelaRef = useRef<UITabela>(null);
547
+ const [nome, setNome] = useState('');
548
+
549
+ useEffect(() => {
550
+ if (tabelaRef.current) {
551
+ tabelaRef.current.colunas = [
552
+ { id: 'id', rotulo: 'Código' },
553
+ { id: 'nome', rotulo: 'Propriedade' }
554
+ ];
555
+ tabelaRef.current.dados = [
556
+ { id: 1, nome: 'Fazenda Santa Luzia' }
557
+ ];
558
+ }
559
+ }, []);
560
+
561
+ return (
562
+ <div style={{ padding: 24 }}>
563
+ <ui-campo-texto
564
+ label="Pesquisar Imóvel"
565
+ value={nome}
566
+ onInput={(e: any) => {
567
+ // Os eventos nativos `input`/`change` não têm `detail`: leia o valor do próprio elemento
568
+ const valor = e.target.value;
569
+ setNome(valor);
570
+ tabelaRef.current?.filtrar(valor);
571
+ }}
572
+ ></ui-campo-texto>
573
+
574
+ <ui-tabela ref={tabelaRef} max-height="300px" densidade="compacta"></ui-tabela>
575
+
576
+ <ui-botao-primario
577
+ variante="primary"
578
+ onClick={() => UIBus.notificar({ tipo: 'sucesso', mensagem: 'Dados sincronizados!' })}>
579
+ Sincronizar
580
+ </ui-botao-primario>
581
+ </div>
582
+ );
583
+ }
584
+ ```
585
+
586
+ ---
587
+
588
+ ### Vue.js
589
+
590
+ Para autocompletar e checar props e eventos nos templates (Volar), registre os tipos no `tsconfig.json` e informe ao Vue que tags `ui-*` são custom elements:
591
+
592
+ ```json
593
+ { "compilerOptions": { "types": ["@thibezer/ui-components-kit/tipos-vue"] } }
594
+ ```
595
+
596
+ ```javascript
597
+ // vite.config.js
598
+ vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('ui-') } } })
599
+ ```
600
+
601
+ ```vue
602
+ <template>
603
+ <div class="container">
604
+ <ui-campo-texto
605
+ :value="termoBusca"
606
+ label="Buscar Vértice"
607
+ @ui-input="aoDigitar"
608
+ />
609
+
610
+ <ui-lista-flutuante
611
+ .itens="opcoes"
612
+ @ui-selecionar="aoSelecionar"
613
+ />
614
+
615
+ <ui-botao-primario target-modal="modal-confirmacao">
616
+ Confirmar Operação
617
+ </ui-botao-primario>
618
+ </div>
619
+ </template>
620
+
621
+ <script setup>
622
+ import { ref } from 'vue';
623
+ import '@thibezer/ui-components-kit/style.css';
624
+ import '@thibezer/ui-components-kit';
625
+
626
+ const termoBusca = ref('');
627
+ const opcoes = ref([
628
+ { id: '1', label: 'Marco Geodésico M' },
629
+ { id: '2', label: 'Ponto Topográfico P' }
630
+ ]);
631
+
632
+ function aoDigitar(e) {
633
+ termoBusca.value = e.detail.value;
634
+ }
635
+
636
+ function aoSelecionar(e) {
637
+ console.log('Opção selecionada:', e.detail);
638
+ }
639
+ </script>
640
+ ```
641
+
642
+ ---
643
+
644
+ ### Iframes / Microfrontends
645
+ Comunicação segura entre iframes e sistemas pais via eventos do `UIBus`:
646
+
647
+ ```javascript
648
+ // Dentro do Iframe (Filho):
649
+ import { UIBus } from '@thibezer/ui-components-kit';
650
+
651
+ UIBus.on('vertice:salvo', (dados) => {
652
+ window.parent.postMessage({ tipo: 'VERTICE_SALVO', payload: dados }, '*');
653
+ });
654
+
655
+ // No Sistema Principal (Pai):
656
+ window.addEventListener('message', (event) => {
657
+ if (event.data?.tipo === 'VERTICE_SALVO') {
658
+ console.log('Recebido do Iframe:', event.data.payload);
659
+ }
660
+ });
661
+ ```
662
+
663
+ ---
664
+
665
+ ## 🧩 Catálogo de Componentes & Referência
666
+
667
+ ### 🟢 Camada 1: Fundamentos
668
+ | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
669
+ | :--- | :--- | :--- | :--- |
670
+ | `<ui-botao-primario>` | Botão com estados de loading, ícone e variantes. Form-associated (`type="submit"`/`"reset"`, `name`/`value`, `form`). Só com ícone, informe `aria-label` (ou `title`). | `variante`, `carregando`, `disabled`, `type`, `aria-label`, `target-modal` | `ui-click` |
671
+ | `<ui-campo-texto>` | Input de texto com Floating Label, validação e senha. | `label`, `value`, `tipo`, `obrigatorio`, `name` | `ui-input`, `ui-change` |
672
+ | `<ui-lista-flutuante>` | Select/Dropdown com Bottom Sheet no mobile. | `itens`, `value`, `placeholder`, `name` | `ui-selecionar` |
673
+ | `<ui-texto>` | Tipografia semântica (H1-H6, corpo, caption, código). | `variante`, `cor`, `peso` | - |
674
+ | `<ui-icone>` | Wrapper para ícones vetoriais padronizados. | `nome`, `tamanho`, `cor` | - |
675
+
676
+ ### 🔵 Camada 2: Controles & Seleção
677
+ | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
678
+ | :--- | :--- | :--- | :--- |
679
+ | `<ui-checkbox>` | Caixa de seleção múltipla com estado indeterminado. | `marcado`, `indeterminado`, `name`, `value` | `ui-change` |
680
+ | `<ui-radio>` | Opção única com agrupamento automático por nome. | `marcado`, `name`, `value` | `ui-change` |
681
+ | `<ui-switch>` | Chave de alternância liga/desliga física instantânea. | `ativo`, `name`, `value` | `ui-change` |
682
+ | `<ui-segmented>` | Controle segmentado de opções (Pills/Tabs deslizantes). | `opcoes`, `value`, `name`, `tamanho` | `ui-change`, `ui-selecionar` |
683
+ | `<ui-badge>` / `<ui-chip>` | Tags de status e chips com botão de remoção. | `variante`, `removivel`, `value` | `ui-remove` |
684
+ | `<ui-avatar>` | Avatar com fotos, iniciais e status online. | `nome`, `src`, `status`, `tamanho` | - |
685
+
686
+ ### 🟣 Camada 3: Contêineres, Overlays, Dados & GIS
687
+ | Tag | Descrição | Principais Atributos / Props | Eventos Emitidos |
688
+ | :--- | :--- | :--- | :--- |
689
+ | `<ui-card>` | Cartão de conteúdo com slots nomeados e elevação. | `elevacao`, `clicavel` | `ui-click` |
690
+ | `<ui-modal>` | Modal centralizado no PC e Bottom Sheet no Mobile. Abrir/fechar por `abrir()`/`fechar()` ou pelo atributo `aberto` tem o mesmo efeito (eventos, foco, `inert`). Foco inicial no `[autofocus]` ou no primeiro controle do conteúdo; ao fechar, volta ao gatilho. Modais empilhados: só o último aberto é interativo. | `aberto`, `titulo`, `bottom-sheet`, `bloquear-fechamento` (oculta o "✕" e ignora Esc/fundo) | `ui-abrir`, `ui-fechar` |
691
+ | `<ui-drawer>` | Painel lateral deslizante (Sheet/Gaveta direita/esquerda). | `aberto`, `posicao` (`direita`, `esquerda`, `baixo`, `cima`), `titulo`, `largura` | `ui-abrir`, `ui-fechar` |
692
+ | `<ui-alerta>` | Banner de notificação contextual fixo. | `variante`, `titulo`, `fechavel` | `ui-fechar` |
693
+ | `<ui-toast>` | Notificações flutuantes inteligentes com pilha flex. | `UIToast.notificar({ tipo, mensagem })` | - |
694
+ | `<ui-tooltip>` | Dica contextual inteligente (Hover PC / Toque Mobile). O texto vira `aria-description` do gatilho (lido pelo leitor de tela, também repassado pelo `<ui-botao>`); **Esc** fecha sem mover o foco; o balão não some ao levar o ponteiro até ele. | `texto`, `posicao`, `gatilho` | - |
695
+ | `<ui-skeleton>` | Placeholder de carregamento animado com pulsos. | `tipo`, `largura`, `altura`, `animado` | - |
696
+ | `<ui-stat>` | Cartão KPI de estatísticas, métricas e tendências. | `rotulo`, `valor`, `variacao`, `tendencia` (`alta`, `baixa`, `neutro`) | - |
697
+ | `<ui-tabela>` | Tabela orientada a dados, virtualizada tipo Excel. **Teclado**: cabeçalhos ordenáveis são botões (Tab + Enter/Espaço, com `aria-sort`); nas linhas, ↑/↓, Home/End e PageUp/PageDown movem o foco e Enter/Espaço selecionam (`aria-current`). A seleção é mantida ao ordenar e filtrar. Nome acessível via `aria-label`. | `colunas`, `dados`, `src`, `densidade`, `aria-label` | `ui-sort`, `ui-column-resize`, `ui-linha-clique` |
698
+ | `<ui-tabela-propriedades>` | Inspetor de propriedades técnicas padrão AutoCAD & Revit com cálculos matemáticos inline (+, -, *, /, ^, %), arraste de valor contínuo (scrubbing), splitter redimensionável e editores CAD. | `categorias`, `tipo-objeto`, `splitter-pos`, `modo-aplicar`, `filtro` | `ui-propriedade-alterada`, `ui-aplicar`, `ui-desfazer`, `ui-editar-tipo`, `ui-acao-clique`, `ui-quick-select`, `ui-calculadora` |
699
+ | `<ui-ribbon>` | Barra de ferramentas em abas e grupos (estilo AutoCAD / Word / Excel): botões grandes e pequenos em colunas de 3, toggles, menus suspensos, abas contextuais, modo recolhido (duplo clique na aba) e navegação por teclado (roving tabindex). | `abas`, `aba-ativa`, `recolhido`, `compacto` | `ui-ferramenta`, `ui-aba-change` |
700
+ | `<ui-paleta-ferramentas>` | Paleta de ferramentas (estilo Illustrator / Photoshop): seleção exclusiva, grupos com flyout (clique longo, botão direito ou seta), 1 ou 2 colunas, vertical/horizontal e atalhos de teclado que percorrem o grupo. | `ferramentas`, `valor`, `orientacao`, `colunas`, `tamanho`, `atalhos` | `ui-change`, `ui-selecionar`, `ui-ferramenta` |
701
+ | `<ui-mapa>` | Mapa geográfico interativo com camadas OpenStreetMap. | `lat`, `lng`, `zoom`, `camadas` | - |
702
+ | `<ui-camadas>` | Painel de camadas vetoriais CAD/GIS com hierarquia em árvore, barra de arraste vertical (`redimensionavel`), estabilidade de altura sem colapso, drag-and-drop, métricas geodésicas e persistência no LocalStorage. | `redimensionavel`, `altura`, `min-altura`, `max-altura`, `flutuante`, `colapsado`, `camada-ativa`, `persistir` | `ui-redimensionar-altura`, `ui-camada-selecionada`, `ui-camada-visibilidade`, `ui-camadas-reordenadas`, `ui-acao-massa` |
703
+ | `<ui-canvas-cad>` | Mesa CAD/GIS para poligonais, vértices geodésicos e **feições genéricas** (ponto, linha, polígono, círculo, texto) que você cria: seleção por clique e caixa, popup, edição de vértices, snap, 15 ferramentas de desenho/medição, oficial × prévia, cursores remotos e culling/clusters para 100 mil feições. Linha multiparte, feição `oculta`, selo de texto e contorno de ponto. Nenhuma camada vem pronta. Guia: [`docs/guia-migracao-mapengine.md`](docs/guia-migracao-mapengine.md). | `pontos`, `segmentos`, `ferramentas`, `sem-camadas-padrao`, `sem-painel-camadas`, `sem-barra-rapida`, `sem-atalho-snap`, `aceitar-origem`, `inicializarAgora()`, `definirFeicoes()`, `aplicarLote()`, `definirFerramenta()`, `editarVertices()`, `definirMargensHud()`, `definirEstilosExternos()`, `fitBounds()` | `ui-ponto-selecionado`, `cad-selecao`, `cad-feicao-selecionada`, `cad-feicao-criada`, `cad-feicao-atualizada`, `cad-feicao-hover`, `cad-feicao-menu`, `cad-snap`, `cad-previas` e outros (ver `docs/canvas-cad-eventos.md`) |
704
+
705
+ #### `<ui-canvas-cad>`: montar só com API pública (2.1)
706
+
707
+ ```html
708
+ <ui-canvas-cad id="mesa" sem-camadas-padrao sem-painel-camadas sem-barra-rapida sem-atalho-snap aceitar-origem></ui-canvas-cad>
709
+ ```
710
+ ```js
711
+ const mapa = mesa.inicializarAgora(); // L.Map síncrono (idempotente; nunca cria um 2º mapa)
712
+ mesa.definirEstilosExternos([...document.styleSheets]); // CSS do app dentro do shadow root (string ou folhas)
713
+ mesa.definirMargensHud({ base: 56, direita: 320 }); // HUDs de desenho/edição fora de barras e painéis
714
+ mesa.aplicarLote('glebas', { adicionar, atualizar, remover }); // uma regravação, ordem preservada
715
+ mesa.atualizarFeicao('glebas', 'g1', { propriedades }, { substituirPropriedades: true });
716
+ mesa.definirOpcoesPopup({ copiarParaAreaDeTransferencia: false });
717
+ ```
718
+
719
+ - Camadas de fábrica (satélite, SIGEF, homologados, perímetro, vizinhos, vértices, grade) só somem com `sem-camadas-padrao`; sem
720
+ o atributo continuam como sempre.
721
+ - `Feicao.oculta` (não desenha nem seleciona, mas existe) ≠ `Feicao.excluida`. Linha multiparte: `geometria.partes`.
722
+ - Tudo, com exemplos: [`docs/guia-migracao-mapengine.md`](docs/guia-migracao-mapengine.md) · eventos e ordem das ferramentas:
723
+ [`docs/canvas-cad-eventos.md`](docs/canvas-cad-eventos.md) · números de desempenho: [`docs/desempenho-feicoes.md`](docs/desempenho-feicoes.md).
724
+
725
+
726
+ ---
727
+
728
+ ### Custom Elements Manifest
729
+ O pacote publica `custom-elements.json` (campo `customElements` do `package.json`), o formato padrão que IDEs, Storybook e geradores de documentação leem para listar tags, atributos, propriedades, eventos e `::part` de cada componente. Ele é gerado no `npm run build` pelo [`@custom-elements-manifest/analyzer`](https://custom-elements-manifest.open-wc.org/), e os tipos React/Vue são derivados dele — por isso nunca ficam desatualizados em relação ao código.
730
+
731
+ ---
732
+
733
+ ## 🛠️ Como Executar e Compilar Localmente
734
+
735
+ 1. **Instalar Dependências**:
736
+ ```bash
737
+ npm install
738
+ ```
739
+
740
+ 2. **Executar o Playground Sandbox em Desenvolvimento**:
741
+ ```bash
742
+ npm run dev
743
+ ```
744
+ Acesse: `http://localhost:5173/`
745
+
746
+ 3. **Compilar Pacote de Produção (Library Mode)**:
747
+ ```bash
748
+ npm run build
749
+ ```
750
+ Gera na pasta `dist/`:
751
+ * `dist/index.js` e `dist/<modulo>.js` (Módulos ES para Vite, Webpack, Rollup)
752
+ * `dist/index.cjs` e `dist/<modulo>.cjs` (CommonJS para `require`)
753
+ * `dist/*.d.ts` (Tipagens TypeScript)
754
+ * `dist/ui-kit.css` (Design Tokens compilados, 100% autocontido — o build falha se restar qualquer `@import`)
755
+ * `dist/custom-elements.json` (Custom Elements Manifest) e `dist/tipos-react.d.ts`, `dist/tipos-vue.d.ts`, `dist/tipos-elementos.d.ts`
756
+
757
+ 4. **Verificar os tipos gerados** (depois do build):
758
+ ```bash
759
+ npm run test:tipos
760
+ ```