Compare commits
No commits in common. "master" and "master-eli-badge" have entirely different histories.
master
...
master-eli
135 changed files with 1257 additions and 51034 deletions
|
|
@ -22,38 +22,8 @@ Construir um Design System de componentes em **Vue 3** para reutilização em m
|
||||||
- TypeScript (modo estrito e tipagem forte)
|
- TypeScript (modo estrito e tipagem forte)
|
||||||
- **defineComponent** (obrigatório)
|
- **defineComponent** (obrigatório)
|
||||||
- Sem TSX (padrão: `<template>` + `<script lang="ts">`)
|
- Sem TSX (padrão: `<template>` + `<script lang="ts">`)
|
||||||
- Estilo: **NÃO usar CSS scoped**. Usar namespacing estático (BEM) com prefixo `eli-` (ex: `.eli-botao__texto`).
|
- Estilo: preferir CSS scoped por componente (se aplicável)
|
||||||
- Ícones: caso seja necessário o uso de ícones, usar **lucide** (biblioteca `lucide-vue-next`) como padrão do repositório.
|
- Ícones: se usar, definir um padrão único do repositório (não inventar por componente)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Regras de Estilização (CSS) - IMPORTANTE
|
|
||||||
|
|
||||||
Para garantir compatibilidade e evitar problemas de hidratação/build em projetos consumidores:
|
|
||||||
|
|
||||||
1. **NUNCA usar `<style scoped>`**.
|
|
||||||
* O atributo `scoped` gera hashes dinâmicos (`data-v-xyz`) que mudam a cada build.
|
|
||||||
* Isso quebra o estilo se o projeto consumidor não atualizar o CSS instantaneamente.
|
|
||||||
|
|
||||||
2. **Use Namespacing Estático (Padrão BEM)**.
|
|
||||||
* Todas as classes devem começar com o prefixo do componente (ex: `.eli-tabela`).
|
|
||||||
* Elementos internos devem seguir o padrão BEM ou similar (ex: `.eli-tabela__cabecalho`, `.eli-tabela--carregando`).
|
|
||||||
* **Exemplo Correto:**
|
|
||||||
```css
|
|
||||||
.eli-modal { ... }
|
|
||||||
.eli-modal__titulo { ... }
|
|
||||||
```
|
|
||||||
* **Exemplo INCORRETO:**
|
|
||||||
```css
|
|
||||||
.container { ... } /* Muito genérico */
|
|
||||||
.titulo { ... } /* Conflita com outros estilos */
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Evite seletores de tag soltos**.
|
|
||||||
* Não estilize tags HTML diretamente (ex: `div`, `input`, `button`) a menos que estejam estritamente aninhadas em uma classe namespaced.
|
|
||||||
* Melhor ainda: coloque classes em todos os elementos que precisam de estilo.
|
|
||||||
* **Válido:** `.eli-form input { ... }` (aceitável, mas prefira `.eli-form__input`)
|
|
||||||
* **Proibido:** `input { ... }` (afeta a aplicação inteira do consumidor)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -70,27 +40,6 @@ Para garantir compatibilidade e evitar problemas de hidratação/build em projet
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Convenção atual de entradas (IMPORTANTE)
|
|
||||||
|
|
||||||
O componente **`EliInput` foi removido**. O padrão atual é a família **`EliEntrada*`**:
|
|
||||||
|
|
||||||
- `EliEntradaTexto`
|
|
||||||
- `EliEntradaNumero`
|
|
||||||
- `EliEntradaDataHora`
|
|
||||||
|
|
||||||
E o contrato padrão para entradas é:
|
|
||||||
- prop `value`
|
|
||||||
- evento `update:value`
|
|
||||||
- prop obrigatória `opcoes` (contém `rotulo` e outras opções)
|
|
||||||
|
|
||||||
Exemplo:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliEntradaTexto v-model:value="nome" :opcoes="{ rotulo: 'Nome' }" />
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Estrutura obrigatória do repositório
|
## Estrutura obrigatória do repositório
|
||||||
- Cada componente deve possuir **sua própria pasta** em `src/componentes/`
|
- Cada componente deve possuir **sua própria pasta** em `src/componentes/`
|
||||||
- Dentro de cada pasta do componente:
|
- Dentro de cada pasta do componente:
|
||||||
|
|
@ -213,43 +162,6 @@ Evitar comentários óbvios (“isso é um botão”).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Convenção atual de EliTabela (IMPORTANTE)
|
|
||||||
|
|
||||||
### Filtro avançado
|
|
||||||
|
|
||||||
O filtro avançado da `EliTabela` é configurado via `tabela.filtroAvancado`.
|
|
||||||
|
|
||||||
Regras:
|
|
||||||
- O **operador é travado na definição** (o usuário não escolhe operador)
|
|
||||||
- Cada filtro pode ser usado **no máximo 1 vez**
|
|
||||||
- UI: modal mostra **apenas os componentes de entrada** definidos no filtro
|
|
||||||
- Persistência: salva em `localStorage` apenas `{ coluna, valor }[]` por `tabela.nome`
|
|
||||||
|
|
||||||
Se você for evoluir isso para backend:
|
|
||||||
- usar `parametrosConsulta.filtros` (`tipoFiltro[]`) no `tabela.consulta`
|
|
||||||
- manter compatibilidade com simulação local (quando necessário)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Publicação do pacote (npm)
|
|
||||||
|
|
||||||
### Regra de publicação (sem usar `package.json.files`)
|
|
||||||
|
|
||||||
Este repositório **não usa** o campo `package.json.files`.
|
|
||||||
O controle do que vai para o tarball publicado é feito via **`.npmignore`**.
|
|
||||||
|
|
||||||
**Ação obrigatória:** sempre que adicionar/renomear/remover arquivos importantes para consumo (ex.: `IA.md`, mudanças de CSS em `dist/`, novas tipagens geradas), revisar e atualizar o `.npmignore`.
|
|
||||||
|
|
||||||
**Validação obrigatória:** após alterar `.npmignore`, rodar:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm pack --dry-run
|
|
||||||
```
|
|
||||||
|
|
||||||
E confirmar que o tarball inclui o que deve estar disponível para consumidores.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Qualidade e consistência
|
## Qualidade e consistência
|
||||||
- Antes de finalizar um componente:
|
- Antes de finalizar um componente:
|
||||||
- Conferir documentação (README raiz + README do componente)
|
- Conferir documentação (README raiz + README do componente)
|
||||||
|
|
@ -276,18 +188,6 @@ Sempre que uma mudança for relevante para desenvolvedores/usuários/IA, **atual
|
||||||
- README da raiz (se impactar o projeto)
|
- README da raiz (se impactar o projeto)
|
||||||
- README do componente (se impactar API/uso/comportamento)
|
- README do componente (se impactar API/uso/comportamento)
|
||||||
|
|
||||||
### Documentação para IAs consumidoras (IA.md)
|
|
||||||
|
|
||||||
O arquivo **`IA.md`** (na raiz) é um guia para **IAs que vão consumir/importar** o pacote `eli-vue`.
|
|
||||||
|
|
||||||
Sempre que houver mudanças relevantes de consumo, **`IA.md` deve ser atualizado** — por exemplo:
|
|
||||||
|
|
||||||
- instalação / comandos recomendados (pnpm/npm/yarn)
|
|
||||||
- peerDependencies (Vue/Vuetify) e requisitos mínimos
|
|
||||||
- forma de uso do plugin (`import EliVue from "eli-vue"`) e registro
|
|
||||||
- caminho/nome do CSS publicado em `dist/` (ex.: `eli-vue/dist/eli-vue.css`)
|
|
||||||
- exports públicos (componentes adicionados/removidos/renomeados)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Postura do agente ao gerar código
|
## Postura do agente ao gerar código
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1 +1,2 @@
|
||||||
node_modules
|
node_modules
|
||||||
|
dist
|
||||||
|
|
|
||||||
396
README.md
396
README.md
|
|
@ -1,387 +1,63 @@
|
||||||
# Documentação EliVue
|
# eli-vue — Design System (Vue 3 + TypeScript)
|
||||||
|
|
||||||
**EliVue** é uma biblioteca de componentes Vue 3 construída sobre o **Vuetify 3**, projetada para padronizar padrões de UI como tabelas de dados (`EliTabela`) e campos de entrada (`EliEntrada*`). Ela segue a filosofia de "configuração sobre boilerplate", onde os componentes são guiados por objetos de configuração tipados em vez de propriedades de template extensas.
|
Biblioteca de componentes Vue 3 (Design System) para reutilização em múltiplos projetos, com foco em:
|
||||||
|
|
||||||
---
|
- consistência visual e comportamental
|
||||||
|
- tipagem forte (TypeScript `strict`)
|
||||||
|
- documentação em português
|
||||||
|
- exemplos executáveis via playground
|
||||||
|
|
||||||
## 🤖 Diretrizes para Agentes de IA (Antigravity)
|
As regras do repositório estão descritas em **`.agent`**.
|
||||||
|
|
||||||
**Ao gerar código usando EliVue, siga estas regras estritas:**
|
|
||||||
|
|
||||||
1. **Importações**: Sempre desestructure as importações do pacote raiz.
|
|
||||||
```typescript
|
|
||||||
import { EliTabela, EliEntradaTexto, EliBotao, celulaTabela } from "eli-vue";
|
|
||||||
```
|
|
||||||
2. **Objetos de Configuração**: Os componentes `EliTabela` e `EliEntrada` dependem fortemente de objetos de configuração (prop `tabela` para tabelas, prop `opcoes` para entradas). **Não tente** passar props individuais (como `headers` ou `items`) para o `EliTabela`.
|
|
||||||
3. **Segurança de Tipos**: Sempre defina objetos de configuração usando os tipos TypeScript exportados (ex: `tipoEliTabelaConsulta`, `parametrosConsulta`).
|
|
||||||
4. **Dados Assíncronos**: O `EliTabela` gerencia sua própria busca de dados via callback `consulta`. Não busque dados manualmente para passar para a tabela. Forneça a função `consulta` no lugar.
|
|
||||||
5. **Ícones**: Use ícones do pacote `lucide-vue-next`.
|
|
||||||
6. **Inicialização**: Prefira usar o plugin global `app.use(EliVue)` ao configurar um novo projeto, em vez de importações individuais.
|
|
||||||
7. **Estilos**: O CSS é injetado automaticamente. Não tente importar arquivos CSS manualmente.
|
|
||||||
8. **Idioma**: Mantenha a documentação e comentários explicativos em **Português do Brasil (pt-BR)**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Instalação
|
## Instalação
|
||||||
|
|
||||||
|
Como dependência do projeto:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm add eli-vue
|
pnpm add eli-vue
|
||||||
# Dependências (Peer Dependencies)
|
|
||||||
pnpm add vue vuetify lucide-vue-next
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Certifique-se de que seu projeto esteja configurado com Vuetify 3.
|
> Observação: `vue` e `vuetify` são **peerDependencies**. Garanta que seu projeto já os tenha instalados.
|
||||||
|
|
||||||
---
|
## Uso
|
||||||
|
|
||||||
## 📦 Referência de Componentes
|
### 1) Registro global (plugin)
|
||||||
|
|
||||||
### 1. EliTabela (Tabela de Dados)
|
```ts
|
||||||
|
import { createApp } from "vue";
|
||||||
|
import EliVue from "eli-vue";
|
||||||
|
|
||||||
O componente `EliTabela` é uma tabela poderosa com paginação no servidor (server-side), busca integrada, ordenação e menus de ação.
|
import App from "./App.vue";
|
||||||
|
|
||||||
#### API
|
createApp(App).use(EliVue).mount("#app");
|
||||||
- **Prop**: `tabela` (Obrigatório)
|
|
||||||
- **Tipo**: `tipoEliTabelaConsulta<T>`
|
|
||||||
|
|
||||||
#### Interface de Configuração (`tipoEliTabelaConsulta`)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// De: eli-vue/src/componentes/EliTabela/types-eli-tabela.ts
|
|
||||||
|
|
||||||
export type tipoEliTabelaConsulta<T> = {
|
|
||||||
// Identificador único para a tabela (usado para persistência local de visibilidade das colunas)
|
|
||||||
nome: string;
|
|
||||||
|
|
||||||
// Função para buscar dados. DEVE retornar um objeto de resposta padrão.
|
|
||||||
consulta: (params: parametrosConsulta<T>) => Promise<tipoResposta<tipoEliConsultaPaginada<T>>>;
|
|
||||||
|
|
||||||
// Definições das colunas
|
|
||||||
colunas: tipoEliColuna<T>[];
|
|
||||||
|
|
||||||
// Opções de UI
|
|
||||||
mostrarCaixaDeBusca?: boolean;
|
|
||||||
registros_por_consulta?: number; // padrão: 10
|
|
||||||
maximo_botoes_paginacao?: number; // padrão: 7
|
|
||||||
mensagemVazio?: string;
|
|
||||||
|
|
||||||
// Ações
|
|
||||||
acoesLinha?: tipoEliTabelaAcao<T>[]; // Ações para cada linha (menu de contexto)
|
|
||||||
acoesTabela?: Array<{ // Ações globais (superior/inferior)
|
|
||||||
// Ações da Tabela (Botões Globais)
|
|
||||||
acoesTabela?: Array<{
|
|
||||||
/**
|
|
||||||
* Posição do botão:
|
|
||||||
* - "superior": Ao lado da caixa de busca (canto superior direito).
|
|
||||||
* - "inferior": No rodapé, alinhado à esquerda (canto inferior esquerdo).
|
|
||||||
*/
|
|
||||||
posicao: "superior" | "inferior";
|
|
||||||
|
|
||||||
/** Rótulo do botão */
|
|
||||||
rotulo: string;
|
|
||||||
|
|
||||||
/** Ícone (Lucide) */
|
|
||||||
icone?: LucideIcon;
|
|
||||||
|
|
||||||
/** Cor do botão (ex: "primary", "success", "error") */
|
|
||||||
cor?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Função executada ao clicar.
|
|
||||||
* Recebe um objeto contendo:
|
|
||||||
* - Parâmetros atuais da consulta (offSet, limit, filtros, etc.)
|
|
||||||
* - Helper `atualizarConsulta()`: Promise<void> para recarregar a tabela.
|
|
||||||
*/
|
|
||||||
acao: (params: parametrosConsulta<T> & { atualizarConsulta: () => Promise<void> }) => void;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
// Definição de Filtro Avançado
|
|
||||||
filtroAvancado?: Array<{
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
/** Função que gera o filtro com base no valor recebido do input */
|
|
||||||
filtro: (valor: unknown) => tipoFiltro<T>;
|
|
||||||
/** Definição do componente de entrada, ex: ["texto", { ... }] */
|
|
||||||
entrada: any;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Definindo Colunas (helper `celulaTabela`)
|
### 2) Importação direta de componentes
|
||||||
|
|
||||||
Use o helper `celulaTabela` para criar definições de células com segurança de tipo.
|
```ts
|
||||||
|
import { EliBotao, EliInput, EliBadge } from "eli-vue";
|
||||||
```typescript
|
|
||||||
// Tipos de células disponíveis e seus dados:
|
|
||||||
// "textoSimples": { texto: string; acao?: () => void }
|
|
||||||
// "textoTruncado": { texto: string; acao?: () => void }
|
|
||||||
// "numero": { numero: number; prefixo?: string; sufixo?: string; acao?: () => void }
|
|
||||||
// "tags": { opcoes: Array<{ rotulo: string; cor?: string; icone?: LucideIcon; acao?: () => void }> }
|
|
||||||
// "data": { valor: string; formato: "data" | "data_hora" | "relativo"; acao?: () => void }
|
|
||||||
// "badge": { texto: string; cor: string }
|
|
||||||
|
|
||||||
{
|
|
||||||
rotulo: "Nome",
|
|
||||||
celula: (row) => celulaTabela("textoSimples", { texto: row.nome }),
|
|
||||||
visivel: true
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Exemplo de Uso com Filtros Avançados
|
## Convenções do projeto
|
||||||
|
|
||||||
```vue
|
- Componentes usam **prefixo `Eli`** (ex.: `EliBotao`, `EliInput`).
|
||||||
<script setup lang="ts">
|
- Pastas seguem **português** (ex.: `src/componentes/botao`, `src/componentes/campo`, `src/componentes/indicador`).
|
||||||
import { EliTabela, celulaTabela, criarFiltro26 } from "eli-vue";
|
- Sem TSX; padrão SFC: `<template>` + `<script lang="ts">` + `defineComponent`.
|
||||||
import type { tipoEliTabelaConsulta } from "eli-vue";
|
- Evitar `any`.
|
||||||
import { UsuarioService } from "@/services/UsuarioService";
|
|
||||||
import { BadgeCheck, Pencil, Plus } from "lucide-vue-next";
|
|
||||||
|
|
||||||
type Usuario = { id: number; nome: string; email: string; ativo: boolean; created_at: string };
|
## Como criar um novo componente (checklist)
|
||||||
|
|
||||||
const tabelaConfig: tipoEliTabelaConsulta<Usuario> = {
|
1. Criar pasta em `src/componentes/<nome_em_portugues>/`
|
||||||
nome: "tabela-usuarios",
|
2. Criar `EliNomeDoComponente.vue` com `defineComponent` + comentários úteis
|
||||||
mostrarCaixaDeBusca: true,
|
3. Criar `index.ts` re-exportando o componente
|
||||||
registros_por_consulta: 10,
|
4. Criar `README.md` do componente (API, exemplos, casos de borda)
|
||||||
|
5. Criar playground em `src/playground/<nome>.playground.vue` (3+ variações)
|
||||||
colunas: [
|
6. Exportar no `src/index.ts`
|
||||||
{
|
|
||||||
rotulo: "Nome",
|
|
||||||
celula: (usuario) => celulaTabela("textoSimples", { texto: usuario.nome }),
|
|
||||||
visivel: true,
|
|
||||||
coluna_ordem: "nome"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rotulo: "Status",
|
|
||||||
visivel: true,
|
|
||||||
celula: (usuario) => celulaTabela("tags", {
|
|
||||||
opcoes: [
|
|
||||||
usuario.ativo
|
|
||||||
? { rotulo: "Ativo", cor: "success", icone: BadgeCheck }
|
|
||||||
: { rotulo: "Inativo", cor: "error" }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rotulo: "Criado em",
|
|
||||||
celula: (usuario) => celulaTabela("data", { valor: usuario.created_at, formato: "data_hora" }),
|
|
||||||
visivel: true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
// Configuração de filtros avançados
|
|
||||||
filtroAvancado: [
|
|
||||||
{
|
|
||||||
rotulo: "Nome",
|
|
||||||
chave: "nome",
|
|
||||||
// Função que retorna o objeto de filtro estruturado
|
|
||||||
filtro: (valor: unknown) => criarFiltro26({ nome: { like: valor as string } }),
|
|
||||||
// Definição do input: ["tipo", opcoes]
|
|
||||||
entrada: ["texto", { rotulo: "Nome do usuário" }] as any
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rotulo: "Ativo?",
|
|
||||||
chave: "ativo",
|
|
||||||
filtro: (valor: unknown) => criarFiltro26({ ativo: { "=": valor } }),
|
|
||||||
entrada: ["selecao", {
|
|
||||||
rotulo: "Status",
|
|
||||||
itens: () => [
|
|
||||||
{ chave: "true", rotulo: "Ativo" },
|
|
||||||
{ chave: "false", rotulo: "Inativo" }
|
|
||||||
]
|
|
||||||
}] as any
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
acoesTabela: [
|
|
||||||
{
|
|
||||||
rotulo: "Novo Usuário",
|
|
||||||
icone: Plus,
|
|
||||||
posicao: "superior",
|
|
||||||
cor: "primary",
|
|
||||||
// O callback recebe: offSet, limit, filtros, e o helper 'atualizarConsulta'
|
|
||||||
acao: async ({ atualizarConsulta }) => {
|
|
||||||
// Exemplo: Abrir modal de criação e depois atualizar a tabela
|
|
||||||
await openCreateUserModal();
|
|
||||||
await atualizarConsulta();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rotulo: "Exportar CSV",
|
|
||||||
icone: Download,
|
|
||||||
posicao: "inferior",
|
|
||||||
cor: "success",
|
|
||||||
acao: (params) => {
|
|
||||||
// 'params' contém os filtros atuais aplicados na tabela
|
|
||||||
UsuarioService.exportarCsv(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
consulta: async (params) => {
|
## Como rodar o playground
|
||||||
// params contém: offSet, limit, texto_busca, coluna_ordem, direcao_ordem, filtros
|
|
||||||
return await UsuarioService.listar(params);
|
|
||||||
},
|
|
||||||
|
|
||||||
acoesLinha: [
|
```bash
|
||||||
{
|
pnpm dev
|
||||||
rotulo: "Editar",
|
|
||||||
icone: Pencil,
|
|
||||||
cor: "primary",
|
|
||||||
acao: (usuario) => console.log("Editar", usuario)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<EliTabela :tabela="tabelaConfig" />
|
|
||||||
</template>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
O playground fica em `src/playground` e serve para validar visualmente os componentes durante o desenvolvimento.
|
||||||
|
|
||||||
### 2. EliEntrada (Inputs)
|
|
||||||
|
|
||||||
Um conjunto de wrappers padronizados em torno dos campos do Vuetify.
|
|
||||||
|
|
||||||
#### Variantes
|
|
||||||
- `EliEntradaTexto`: Texto, Email, URL, CPF, CNPJ, CEP.
|
|
||||||
- `EliEntradaNumero`: Inteiros, Decimais, Moeda.
|
|
||||||
- `EliEntradaDataHora`: Data, DataHora.
|
|
||||||
- `EliEntradaSelecao`: Select/Dropdown (pode ser assíncrono).
|
|
||||||
- `EliEntradaParagrafo`: Textarea.
|
|
||||||
|
|
||||||
#### API Comum
|
|
||||||
Todas as entradas aceitam duas props principais:
|
|
||||||
1. `value`: O binding v-model.
|
|
||||||
2. `opcoes`: Um objeto de configuração específico para o tipo de entrada.
|
|
||||||
|
|
||||||
#### Objetos de Configuração (`tiposEntradas.ts`)
|
|
||||||
|
|
||||||
**EliEntradaTexto**
|
|
||||||
```typescript
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**EliEntradaNumero**
|
|
||||||
```typescript
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
precisao?: number; // 0=inteiro (padrão se null), 0.1=1 decimal, 0.01=2 decimais. Se undefined/null, assume decimal livre.
|
|
||||||
prefixo?: string; // ex: "R$"
|
|
||||||
sufixo?: string; // ex: "kg"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**EliEntradaDataHora**
|
|
||||||
```typescript
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
modo?: "data" | "dataHora"; // padrão: "dataHora"
|
|
||||||
min?: string; // String ISO
|
|
||||||
max?: string; // String ISO
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**EliEntradaSelecao**
|
|
||||||
```typescript
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
// Função que retorna itens ou promise de itens.
|
|
||||||
// IMPORTANTE: Itens devem ser objetos { chave: string, rotulo: string }
|
|
||||||
itens: () => Array<{ chave: string; rotulo: string }> | Promise<Array<{ chave: string; rotulo: string }>>;
|
|
||||||
limpavel?: boolean;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Exemplo de Uso
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora } from "eli-vue";
|
|
||||||
|
|
||||||
const nome = ref("");
|
|
||||||
const salario = ref<number | null>(null);
|
|
||||||
const nascimento = ref<string | null>(null); // ISO string
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<EliEntradaTexto
|
|
||||||
:value="nome"
|
|
||||||
@update:value="nome = $event"
|
|
||||||
:opcoes="{ rotulo: 'Nome Completo', formato: 'texto' }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EliEntradaNumero
|
|
||||||
:value="salario"
|
|
||||||
@update:value="salario = $event"
|
|
||||||
:opcoes="{ rotulo: 'Salário', prefixo: 'R$', precisao: 0.01 }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Exibe como data local, vincula como string ISO -->
|
|
||||||
<EliEntradaDataHora
|
|
||||||
:value="nascimento"
|
|
||||||
@update:value="nascimento = $event"
|
|
||||||
:opcoes="{ rotulo: 'Data de Nascimento', modo: 'data' }"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. EliBotao
|
|
||||||
|
|
||||||
Wrapper simples para `v-btn`.
|
|
||||||
|
|
||||||
- **Props**: `color`, `variant` (elevated, flat, text, etc.), `size`, `loading`, `disabled`.
|
|
||||||
- **Slots**: slot padrão para o conteúdo do botão.
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliBotao color="primary" @click="salvar">
|
|
||||||
Salvar
|
|
||||||
</EliBotao>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. EliCartao & EliBadge
|
|
||||||
|
|
||||||
**EliCartao**
|
|
||||||
Cartão padronizado para itens de domínio.
|
|
||||||
- **Props**: `titulo`, `status` (tipo `CartaoStatus`: "novo" | "rascunho" | "vendido" | "cancelado"), `variant`.
|
|
||||||
- **Slots**: `default` (conteúdo), `acoes` (ações de rodapé).
|
|
||||||
|
|
||||||
**EliBadge**
|
|
||||||
Badge aprimorado com raios.
|
|
||||||
- **Props**: `badge` (conteúdo), `color`, `radius` ("suave" | "pill").
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Solução de Problemas e Dicas
|
|
||||||
|
|
||||||
### 1. "Failed to resolve component"
|
|
||||||
- Certifique-se de que `app.use(EliVue)` foi chamado no `main.ts`.
|
|
||||||
- Se importar diretamente, garanta importações padrão: `import { EliTabela } from 'eli-vue'`.
|
|
||||||
|
|
||||||
### 2. Problemas de Estilo
|
|
||||||
- **Injeção de CSS**: O `eli-vue` injeta CSS automaticamente. Verifique sua CSP (Política de Segurança de Conteúdo) se os estilos estiverem bloqueados.
|
|
||||||
- **Vuetify**: Certifique-se de que o Vuetify 3 está corretamente instalado e os estilos (`vuetify/styles`) estão importados no seu arquivo de entrada principal.
|
|
||||||
|
|
||||||
### 3. Erros de TypeScript no `celulaTabela`
|
|
||||||
- Garanta que o segundo argumento corresponda ao esquema específico do tipo de célula.
|
|
||||||
- Exemplo: `celulaTabela("textoSimples", { texto: ... })` funciona, mas `celulaTabela("textoSimples", { numero: ... })` falhará.
|
|
||||||
|
|
||||||
### 4. Ícones não aparecem
|
|
||||||
- Passe o **objeto do componente** (ex: importado de `lucide-vue-next`), não o nome em string.
|
|
||||||
- Exemplo: `icone: Pencil` (Correto) vs `icone: "pencil"` (Incorreto).
|
|
||||||
|
|
||||||
### 5. Valores do `EliEntrada`
|
|
||||||
- `EliEntradaTexto` com `formato='cpfCnpj'` emite a string **formatada** (ex: "123.456.789-00").
|
|
||||||
- `EliEntradaNumero` emite um `number` ou `null`.
|
|
||||||
- `EliEntradaDataHora` trabalha com **Strings ISO** (ex: "2023-01-01T00:00:00Z"). A exibição é localizada, mas o valor do modelo é sempre ISO.
|
|
||||||
|
|
|
||||||
17
biome.json
17
biome.json
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
||||||
"extends": ["./node_modules/p-comuns/Documentos/biome.json"],
|
|
||||||
"files": {
|
|
||||||
"includes": ["src/**/*.{js,ts,jsx,tsx,vue}"]
|
|
||||||
},
|
|
||||||
"linter": {
|
|
||||||
"rules": {
|
|
||||||
"suspicious": {
|
|
||||||
"noExplicitAny": "error"
|
|
||||||
},
|
|
||||||
"style": {
|
|
||||||
"noNonNullAssertion": "error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13796
dist/eli-vue.es.js
vendored
13796
dist/eli-vue.es.js
vendored
File diff suppressed because one or more lines are too long
116
dist/eli-vue.umd.js
vendored
116
dist/eli-vue.umd.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/quero-quero.gif
vendored
BIN
dist/quero-quero.gif
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB |
|
|
@ -1,231 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { CampoDensidade, CampoVariante } from "../../tipos";
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas";
|
|
||||||
type EntradaDataHora = PadroesEntradas["dataHora"];
|
|
||||||
type PropsAntigas = {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
rotulo?: string;
|
|
||||||
placeholder?: string;
|
|
||||||
desabilitado?: boolean;
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
densidade?: CampoDensidade;
|
|
||||||
variante?: CampoVariante;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
};
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaDataHora["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaDataHora["opcoes"]>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
modo: {
|
|
||||||
type: PropType<PropsAntigas["modo"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
rotulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
placeholder: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
desabilitado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
limpavel: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
mensagensErro: {
|
|
||||||
type: PropType<string | string[]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dica: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dicaPersistente: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
densidade: {
|
|
||||||
type: PropType<CampoDensidade>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
variante: {
|
|
||||||
type: PropType<CampoVariante>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
min: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
max: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
valor: import("vue").WritableComputedRef<string, string>;
|
|
||||||
tipoInput: import("vue").ComputedRef<"date" | "datetime-local">;
|
|
||||||
minLocal: import("vue").ComputedRef<string | undefined>;
|
|
||||||
maxLocal: import("vue").ComputedRef<string | undefined>;
|
|
||||||
opcoesEfetivas: import("vue").ComputedRef<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../../tipos").CampoDensidade;
|
|
||||||
variante?: import("../../tipos").CampoVariante;
|
|
||||||
}>;
|
|
||||||
desabilitadoEfetivo: import("vue").ComputedRef<boolean>;
|
|
||||||
emitCompatFocus: () => void;
|
|
||||||
emitCompatBlur: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: string | null) => true;
|
|
||||||
input: (_v: string | null) => true;
|
|
||||||
change: (_v: string | null) => true;
|
|
||||||
"update:modelValue": (_v: string | null) => true;
|
|
||||||
alterar: (_v: string | null) => true;
|
|
||||||
foco: () => true;
|
|
||||||
desfoco: () => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaDataHora["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaDataHora["opcoes"]>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
modo: {
|
|
||||||
type: PropType<PropsAntigas["modo"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
rotulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
placeholder: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
desabilitado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
limpavel: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
mensagensErro: {
|
|
||||||
type: PropType<string | string[]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dica: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dicaPersistente: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
densidade: {
|
|
||||||
type: PropType<CampoDensidade>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
variante: {
|
|
||||||
type: PropType<CampoVariante>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
min: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
max: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: string | null) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
|
||||||
onChange?: ((_v: string | null) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
|
||||||
onAlterar?: ((_v: string | null) => any) | undefined;
|
|
||||||
onFoco?: (() => any) | undefined;
|
|
||||||
onDesfoco?: (() => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
modo: "data" | "dataHora" | undefined;
|
|
||||||
limpavel: boolean;
|
|
||||||
erro: boolean;
|
|
||||||
mensagensErro: string | string[];
|
|
||||||
dica: string;
|
|
||||||
dicaPersistente: boolean;
|
|
||||||
min: string | undefined;
|
|
||||||
max: string | undefined;
|
|
||||||
densidade: CampoDensidade;
|
|
||||||
variante: CampoVariante;
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../../tipos").CampoDensidade;
|
|
||||||
variante?: import("../../tipos").CampoVariante;
|
|
||||||
};
|
|
||||||
value: string | null | undefined;
|
|
||||||
modelValue: string | null;
|
|
||||||
rotulo: string;
|
|
||||||
placeholder: string;
|
|
||||||
desabilitado: boolean;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas";
|
|
||||||
type EntradaNumero = PadroesEntradas["numero"];
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaNumero["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaNumero["opcoes"]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
emit: ((event: "input", _v: number | null | undefined) => void) & ((event: "update:value", _v: number | null | undefined) => void) & ((event: "change", _v: number | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void);
|
|
||||||
displayValue: import("vue").Ref<string, string>;
|
|
||||||
isInteiro: import("vue").ComputedRef<boolean>;
|
|
||||||
onUpdateModelValue: (texto: string) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: EntradaNumero["value"]) => true;
|
|
||||||
/** Compat Vue2 (v-model padrão: value + input) */
|
|
||||||
input: (_v: EntradaNumero["value"]) => true;
|
|
||||||
change: (_v: EntradaNumero["value"]) => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaNumero["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaNumero["opcoes"]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
onChange?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
value: number | null | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -1,50 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas";
|
|
||||||
type EntradaTexto = PadroesEntradas["texto"];
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaTexto["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaTexto["opcoes"]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
emit: ((event: "input", _v: string | null | undefined) => void) & ((event: "update:value", _v: string | null | undefined) => void) & ((event: "change", _v: string | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void);
|
|
||||||
localValue: import("vue").WritableComputedRef<string | null | undefined, string | null | undefined>;
|
|
||||||
inputHtmlType: import("vue").ComputedRef<"text" | "email" | "url">;
|
|
||||||
inputMode: import("vue").ComputedRef<string | undefined>;
|
|
||||||
onInput: (e: Event) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: EntradaTexto["value"]) => true;
|
|
||||||
/** Compat Vue2 (v-model padrão: value + input) */
|
|
||||||
input: (_v: EntradaTexto["value"]) => true;
|
|
||||||
change: (_v: EntradaTexto["value"]) => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: PropType<EntradaTexto["value"]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<EntradaTexto["opcoes"]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
value: string | null | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
7
dist/types/componentes/EliEntrada/index.d.ts
vendored
7
dist/types/componentes/EliEntrada/index.d.ts
vendored
|
|
@ -1,7 +0,0 @@
|
||||||
import EliEntradaDataHora from "./EliEntradaDataHora.vue";
|
|
||||||
import EliEntradaNumero from "./EliEntradaNumero.vue";
|
|
||||||
import EliEntradaParagrafo from "./EliEntradaParagrafo.vue";
|
|
||||||
import EliEntradaSelecao from "./EliEntradaSelecao.vue";
|
|
||||||
import EliEntradaTexto from "./EliEntradaTexto.vue";
|
|
||||||
export { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora, EliEntradaParagrafo, EliEntradaSelecao, };
|
|
||||||
export type { PadroesEntradas, TipoEntrada } from "./tiposEntradas";
|
|
||||||
11934
dist/types/componentes/EliEntrada/registryEliEntradas.d.ts
vendored
11934
dist/types/componentes/EliEntrada/registryEliEntradas.d.ts
vendored
File diff suppressed because one or more lines are too long
146
dist/types/componentes/EliEntrada/tiposEntradas.d.ts
vendored
146
dist/types/componentes/EliEntrada/tiposEntradas.d.ts
vendored
|
|
@ -1,146 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos base para componentes de entrada (EliEntrada*)
|
|
||||||
*
|
|
||||||
* Objetivo:
|
|
||||||
* - Padronizar o shape de dados de todos os componentes de entrada.
|
|
||||||
* - Cada entrada possui sempre:
|
|
||||||
* 1) `value`: o valor atual (tipado)
|
|
||||||
* 2) `opcoes`: configuração do componente (rótulo, placeholder e extras por tipo)
|
|
||||||
*
|
|
||||||
* Como usar:
|
|
||||||
* - `PadroesEntradas[tipo]` retorna a tipagem completa (value + opcoes) daquele tipo.
|
|
||||||
* - `TipoEntrada` é a união com todos os tipos suportados (ex.: "texto" | "numero").
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Contrato padrão de uma entrada.
|
|
||||||
*
|
|
||||||
* @typeParam T - tipo do `value` (ex.: string | null | undefined)
|
|
||||||
* @typeParam Mais - campos adicionais dentro de `opcoes`, específicos do tipo de entrada
|
|
||||||
*/
|
|
||||||
export type tipoPadraoEntrada<T, Mais extends Record<string, unknown> = {}> = {
|
|
||||||
/** Valor atual do campo (pode aceitar null/undefined quando aplicável) */
|
|
||||||
value: T;
|
|
||||||
/** Configurações do componente (visuais + regras simples do tipo) */
|
|
||||||
opcoes: {
|
|
||||||
/** Rótulo exibido ao usuário */
|
|
||||||
rotulo: string;
|
|
||||||
/** Texto de ajuda dentro do input quando vazio */
|
|
||||||
placeholder?: string;
|
|
||||||
} & Mais;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Mapa de tipos de entrada suportados e suas configurações específicas.
|
|
||||||
*
|
|
||||||
* Observação importante:
|
|
||||||
* - As chaves deste objeto (ex.: "texto", "numero") viram o tipo `TipoEntrada`.
|
|
||||||
* - Cada item define:
|
|
||||||
* - `value`: tipo do valor
|
|
||||||
* - `opcoes`: opções comuns + extras específicas
|
|
||||||
*/
|
|
||||||
export type PadroesEntradas = {
|
|
||||||
texto: tipoPadraoEntrada<string | null | undefined, {
|
|
||||||
/** Limite máximo de caracteres permitidos (se definido) */
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
/**
|
|
||||||
* Formato/máscara aplicada ao texto.
|
|
||||||
* Obs: o `value` SEMPRE será o texto formatado (o que aparece no input).
|
|
||||||
*/
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}>;
|
|
||||||
numero: tipoPadraoEntrada<number | null | undefined, {
|
|
||||||
/** Unidade de medida (ex.: "kg", "m³") */
|
|
||||||
sufixo?: string;
|
|
||||||
/** Moéda (ex.: "R$") */
|
|
||||||
prefixo?: string;
|
|
||||||
/**
|
|
||||||
* Passo/precisão do valor numérico.
|
|
||||||
* - 1 => somente inteiros
|
|
||||||
* - 0.1 => 1 casa decimal
|
|
||||||
* - 0.01 => 2 casas decimais
|
|
||||||
*
|
|
||||||
* Dica: este conceito corresponde ao atributo HTML `step`.
|
|
||||||
*/
|
|
||||||
precisao?: number;
|
|
||||||
}>;
|
|
||||||
dataHora: tipoPadraoEntrada<string | null | undefined, {
|
|
||||||
/** Define o tipo de entrada. - `dataHora`: datetime-local - `data`: date */
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean;
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean;
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string;
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
/** Valor mínimo permitido (ISO 8601 - offset ou Z). */
|
|
||||||
min?: string;
|
|
||||||
/** Valor máximo permitido (ISO 8601 - offset ou Z). */
|
|
||||||
max?: string;
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade;
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante;
|
|
||||||
}>;
|
|
||||||
paragrafo: tipoPadraoEntrada<string | null | undefined, {
|
|
||||||
/** Quantidade de linhas visíveis no textarea (Vuetify `rows`). */
|
|
||||||
linhas?: number;
|
|
||||||
/** Limite máximo de caracteres permitidos (se definido). */
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean;
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean;
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string;
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade;
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante;
|
|
||||||
}>;
|
|
||||||
selecao: tipoPadraoEntrada<string | null | undefined, {
|
|
||||||
/**
|
|
||||||
* Carrega os itens da seleção (sincrono ou async).
|
|
||||||
* - Cada item precisa ter uma chave estável (value) e um rótulo (title).
|
|
||||||
*/
|
|
||||||
itens: () => {
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[] | Promise<{
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[]>;
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean;
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean;
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string;
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade;
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* União dos tipos de entrada suportados.
|
|
||||||
* Ex.: "texto" | "numero"
|
|
||||||
*/
|
|
||||||
export type TipoEntrada = keyof PadroesEntradas;
|
|
||||||
export type PadraoComponenteEntrada<T extends TipoEntrada> = readonly [
|
|
||||||
T,
|
|
||||||
PadroesEntradas[T]["opcoes"]
|
|
||||||
];
|
|
||||||
export type ComponenteEntrada = {
|
|
||||||
[K in TipoEntrada]: PadraoComponenteEntrada<K>;
|
|
||||||
}[TipoEntrada];
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
/** Formata CEP no padrão 00000-000 */
|
|
||||||
export declare function formatarCep(valor: string): string;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
export declare function formatarCpfCnpj(v: string): string;
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
/**
|
|
||||||
* Remove tudo que não é número
|
|
||||||
*/
|
|
||||||
export declare function sanitizeTelefone(value: string): string;
|
|
||||||
/**
|
|
||||||
* Aplica máscara dinâmica de telefone BR
|
|
||||||
*/
|
|
||||||
export declare function formatTelefone(value: string): string;
|
|
||||||
1381
dist/types/componentes/EliTabela/EliTabela.vue.d.ts
vendored
1381
dist/types/componentes/EliTabela/EliTabela.vue.d.ts
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1,186 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linhasExpandidas: {
|
|
||||||
type: PropType<Record<number, boolean>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linhas: {
|
|
||||||
type: PropType<Array<unknown>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temAcoes: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
possuiAcoes: {
|
|
||||||
type: PropType<(i: number) => boolean>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
toggleMenu: {
|
|
||||||
type: PropType<(indice: number, evento: MouseEvent) => void>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
alternarLinhaExpandida: {
|
|
||||||
type: PropType<(indice: number) => void>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
ChevronRight: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
ChevronDown: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linhasExpandidas: {
|
|
||||||
type: PropType<Record<number, boolean>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linhas: {
|
|
||||||
type: PropType<Array<unknown>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temAcoes: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
possuiAcoes: {
|
|
||||||
type: PropType<(i: number) => boolean>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
toggleMenu: {
|
|
||||||
type: PropType<(indice: number, evento: MouseEvent) => void>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
alternarLinhaExpandida: {
|
|
||||||
type: PropType<(indice: number) => void>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {
|
|
||||||
EliTabelaCelula: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
Componente: import("vue").ComputedRef<import("vue").Component>;
|
|
||||||
dadosParaComponente: import("vue").ComputedRef<{
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
EliTabelaDetalhesLinha: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {
|
|
||||||
EliTabelaCelula: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
Componente: import("vue").ComputedRef<import("vue").Component>;
|
|
||||||
dadosParaComponente: import("vue").ComputedRef<{
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
MoreVertical: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
ChevronRight: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
ChevronDown: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
exibirBusca: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
exibirBotaoColunas: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: false;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
exibirBotaoFiltroAvancado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: false;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
valorBusca: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
parametrosConsulta: {
|
|
||||||
type: PropType<any>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
acoesCabecalho: {
|
|
||||||
type: PropType<Array<{
|
|
||||||
icone?: any;
|
|
||||||
cor?: string;
|
|
||||||
rotulo: string;
|
|
||||||
acao: (params?: any) => void;
|
|
||||||
}>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
temAcoesCabecalho: import("vue").ComputedRef<boolean>;
|
|
||||||
emitBuscar: (texto: string) => void;
|
|
||||||
emitColunas: () => void;
|
|
||||||
emitFiltroAvancado: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
buscar(valor: string): boolean;
|
|
||||||
colunas(): true;
|
|
||||||
filtroAvancado(): true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
exibirBusca: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
exibirBotaoColunas: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: false;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
exibirBotaoFiltroAvancado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: false;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
valorBusca: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
parametrosConsulta: {
|
|
||||||
type: PropType<any>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
acoesCabecalho: {
|
|
||||||
type: PropType<Array<{
|
|
||||||
icone?: any;
|
|
||||||
cor?: string;
|
|
||||||
rotulo: string;
|
|
||||||
acao: (params?: any) => void;
|
|
||||||
}>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onColunas?: (() => any) | undefined;
|
|
||||||
onBuscar?: ((valor: string) => any) | undefined;
|
|
||||||
onFiltroAvancado?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
exibirBotaoColunas: boolean;
|
|
||||||
exibirBotaoFiltroAvancado: boolean;
|
|
||||||
}, {}, {
|
|
||||||
EliTabelaCaixaDeBusca: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
modelo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: false;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
texto: import("vue").Ref<string, string>;
|
|
||||||
emitirBusca: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
buscar(valor: string): boolean;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
modelo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: false;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onBuscar?: ((valor: string) => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
modelo: string;
|
|
||||||
}, {}, {
|
|
||||||
Search: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
modelo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: false;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
texto: import("vue").Ref<string, string>;
|
|
||||||
emitirBusca: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
buscar(valor: string): boolean;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
modelo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
required: false;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onBuscar?: ((valor: string) => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
modelo: string;
|
|
||||||
}, {}, {
|
|
||||||
Search: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
isDev: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuPopupPos: {
|
|
||||||
type: PropType<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
isDev: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
menuPopupPos: {
|
|
||||||
type: PropType<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunasInvisiveis: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {
|
|
||||||
EliTabelaCelula: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
Componente: import("vue").ComputedRef<import("vue").Component>;
|
|
||||||
dadosParaComponente: import("vue").ComputedRef<{
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
carregando: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
mensagemVazio: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
carregando: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
mensagemVazio: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
mensagemVazio: string | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temAcoes: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunaOrdenacao: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
direcaoOrdenacao: {
|
|
||||||
type: PropType<"asc" | "desc">;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
ArrowUp: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
ArrowDown: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
isOrdenavel: (coluna: any) => boolean;
|
|
||||||
emitAlternarOrdenacao: (chave: string) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
alternarOrdenacao(chave: string): boolean;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temAcoes: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunaOrdenacao: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
direcaoOrdenacao: {
|
|
||||||
type: PropType<"asc" | "desc">;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onAlternarOrdenacao?: ((chave: string) => any) | undefined;
|
|
||||||
}>, {}, {}, {
|
|
||||||
ArrowUp: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
ArrowDown: import("vue").FunctionalComponent<import("lucide-vue-next").LucideProps, {}, any, {}>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tipoEliTabelaAcao } from "./types-eli-tabela";
|
|
||||||
type ItemAcao<T> = {
|
|
||||||
acao: tipoEliTabelaAcao<T>;
|
|
||||||
indice: number;
|
|
||||||
visivel: boolean;
|
|
||||||
};
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
posicao: {
|
|
||||||
type: PropType<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
acoes: {
|
|
||||||
type: PropType<Array<ItemAcao<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
menuEl: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
|
|
||||||
possuiAcoes: import("vue").ComputedRef<boolean>;
|
|
||||||
emitExecutar: (item: {
|
|
||||||
acao: tipoEliTabelaAcao<any>;
|
|
||||||
}) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
executar(payload: {
|
|
||||||
acao: tipoEliTabelaAcao<any>;
|
|
||||||
linha: unknown;
|
|
||||||
}): boolean;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
menuAberto: {
|
|
||||||
type: PropType<number | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
posicao: {
|
|
||||||
type: PropType<{
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
acoes: {
|
|
||||||
type: PropType<Array<ItemAcao<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
linha: {
|
|
||||||
type: PropType<unknown | null>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onExecutar?: ((payload: {
|
|
||||||
acao: tipoEliTabelaAcao<any>;
|
|
||||||
linha: unknown;
|
|
||||||
}) => any) | undefined;
|
|
||||||
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { EliTabelaColunasConfig } from "./colunasStorage";
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela";
|
|
||||||
type OrigemLista = "visiveis" | "invisiveis";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
aberto: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
rotulosColunas: {
|
|
||||||
type: PropType<string[]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
configInicial: {
|
|
||||||
type: PropType<EliTabelaColunasConfig>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
visiveisLocal: import("vue").Ref<string[], string[]>;
|
|
||||||
invisiveisLocal: import("vue").Ref<string[], string[]>;
|
|
||||||
emitFechar: () => void;
|
|
||||||
emitSalvar: () => void;
|
|
||||||
onDragStart: (e: DragEvent, rotulo: string, origem: OrigemLista, index: number) => void;
|
|
||||||
onDropItem: (e: DragEvent, destino: OrigemLista, index: number) => void;
|
|
||||||
onDropLista: (e: DragEvent, destino: OrigemLista, _index: number | null) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
fechar(): true;
|
|
||||||
salvar(_config: EliTabelaColunasConfig): true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
aberto: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
rotulosColunas: {
|
|
||||||
type: PropType<string[]>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
configInicial: {
|
|
||||||
type: PropType<EliTabelaColunasConfig>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
colunas: {
|
|
||||||
type: PropType<Array<tipoEliColuna<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onFechar?: (() => any) | undefined;
|
|
||||||
onSalvar?: ((_config: EliTabelaColunasConfig) => any) | undefined;
|
|
||||||
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,522 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas";
|
|
||||||
import type { tipoEliTabelaConsulta } from "./types-eli-tabela";
|
|
||||||
type FiltroBase<T> = NonNullable<tipoEliTabelaConsulta<T>["filtroAvancado"]>[number];
|
|
||||||
type LinhaFiltro = {
|
|
||||||
chave: string;
|
|
||||||
entrada: ComponenteEntrada;
|
|
||||||
valor: any;
|
|
||||||
};
|
|
||||||
declare function rotuloDoFiltro(f: FiltroBase<any>): string;
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
aberto: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
filtrosBase: {
|
|
||||||
type: PropType<Array<FiltroBase<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
modelo: {
|
|
||||||
type: PropType<Array<any>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
linhas: import("vue").Ref<{
|
|
||||||
chave: string;
|
|
||||||
entrada: readonly ["texto", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
limiteCaracteres?: number | undefined;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep" | undefined;
|
|
||||||
}] | readonly ["dataHora", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
modo?: "data" | "dataHora" | undefined;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
min?: string | undefined;
|
|
||||||
max?: string | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}] | readonly ["numero", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
sufixo?: string | undefined;
|
|
||||||
prefixo?: string | undefined;
|
|
||||||
precisao?: number | undefined;
|
|
||||||
}] | readonly ["paragrafo", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
linhas?: number | undefined;
|
|
||||||
limiteCaracteres?: number | undefined;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}] | readonly ["selecao", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
itens: () => {
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[] | Promise<{
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[]>;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}];
|
|
||||||
valor: any;
|
|
||||||
}[], LinhaFiltro[] | {
|
|
||||||
chave: string;
|
|
||||||
entrada: readonly ["texto", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
limiteCaracteres?: number | undefined;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep" | undefined;
|
|
||||||
}] | readonly ["dataHora", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
modo?: "data" | "dataHora" | undefined;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
min?: string | undefined;
|
|
||||||
max?: string | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}] | readonly ["numero", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
sufixo?: string | undefined;
|
|
||||||
prefixo?: string | undefined;
|
|
||||||
precisao?: number | undefined;
|
|
||||||
}] | readonly ["paragrafo", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
linhas?: number | undefined;
|
|
||||||
limiteCaracteres?: number | undefined;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}] | readonly ["selecao", {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string | undefined;
|
|
||||||
itens: () => {
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[] | Promise<{
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
}[]>;
|
|
||||||
limpavel?: boolean | undefined;
|
|
||||||
erro?: boolean | undefined;
|
|
||||||
mensagensErro?: string | string[] | undefined;
|
|
||||||
dica?: string | undefined;
|
|
||||||
dicaPersistente?: boolean | undefined;
|
|
||||||
densidade?: import("../..").CampoDensidade | undefined;
|
|
||||||
variante?: import("../..").CampoVariante | undefined;
|
|
||||||
}];
|
|
||||||
valor: any;
|
|
||||||
}[]>;
|
|
||||||
opcoesParaAdicionar: import("vue").ComputedRef<{
|
|
||||||
chave: string;
|
|
||||||
rotulo: string;
|
|
||||||
filtro: (valor: unknown) => import("p-comuns").tipoFiltro26<any>;
|
|
||||||
entrada: ComponenteEntrada;
|
|
||||||
}[]>;
|
|
||||||
chaveParaAdicionar: import("vue").Ref<string, string>;
|
|
||||||
componenteEntrada: (entrada: ComponenteEntrada) => import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../..").CampoDensidade;
|
|
||||||
variante?: import("../..").CampoVariante;
|
|
||||||
}>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
modo: {
|
|
||||||
type: PropType<"data" | "dataHora" | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
rotulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
placeholder: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
desabilitado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
limpavel: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
mensagensErro: {
|
|
||||||
type: PropType<string | string[]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dica: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dicaPersistente: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
densidade: {
|
|
||||||
type: PropType<import("../..").CampoDensidade>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
variante: {
|
|
||||||
type: PropType<import("../..").CampoVariante>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
min: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
max: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
valor: import("vue").WritableComputedRef<string, string>;
|
|
||||||
tipoInput: import("vue").ComputedRef<"date" | "datetime-local">;
|
|
||||||
minLocal: import("vue").ComputedRef<string | undefined>;
|
|
||||||
maxLocal: import("vue").ComputedRef<string | undefined>;
|
|
||||||
opcoesEfetivas: import("vue").ComputedRef<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../..").CampoDensidade;
|
|
||||||
variante?: import("../..").CampoVariante;
|
|
||||||
}>;
|
|
||||||
desabilitadoEfetivo: import("vue").ComputedRef<boolean>;
|
|
||||||
emitCompatFocus: () => void;
|
|
||||||
emitCompatBlur: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: string | null) => true;
|
|
||||||
input: (_v: string | null) => true;
|
|
||||||
change: (_v: string | null) => true;
|
|
||||||
"update:modelValue": (_v: string | null) => true;
|
|
||||||
alterar: (_v: string | null) => true;
|
|
||||||
foco: () => true;
|
|
||||||
desfoco: () => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../..").CampoDensidade;
|
|
||||||
variante?: import("../..").CampoVariante;
|
|
||||||
}>;
|
|
||||||
required: false;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: PropType<string | null>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
modo: {
|
|
||||||
type: PropType<"data" | "dataHora" | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
rotulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
placeholder: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
desabilitado: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
limpavel: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
erro: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
mensagensErro: {
|
|
||||||
type: PropType<string | string[]>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dica: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
dicaPersistente: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
densidade: {
|
|
||||||
type: PropType<import("../..").CampoDensidade>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
variante: {
|
|
||||||
type: PropType<import("../..").CampoVariante>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
min: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
max: {
|
|
||||||
type: PropType<string | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: string | null) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
|
||||||
onChange?: ((_v: string | null) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
|
||||||
onAlterar?: ((_v: string | null) => any) | undefined;
|
|
||||||
onFoco?: (() => any) | undefined;
|
|
||||||
onDesfoco?: (() => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
modo: "data" | "dataHora" | undefined;
|
|
||||||
limpavel: boolean;
|
|
||||||
erro: boolean;
|
|
||||||
mensagensErro: string | string[];
|
|
||||||
dica: string;
|
|
||||||
dicaPersistente: boolean;
|
|
||||||
min: string | undefined;
|
|
||||||
max: string | undefined;
|
|
||||||
densidade: import("../..").CampoDensidade;
|
|
||||||
variante: import("../..").CampoVariante;
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
modo?: "data" | "dataHora";
|
|
||||||
limpavel?: boolean;
|
|
||||||
erro?: boolean;
|
|
||||||
mensagensErro?: string | string[];
|
|
||||||
dica?: string;
|
|
||||||
dicaPersistente?: boolean;
|
|
||||||
min?: string;
|
|
||||||
max?: string;
|
|
||||||
densidade?: import("../..").CampoDensidade;
|
|
||||||
variante?: import("../..").CampoVariante;
|
|
||||||
};
|
|
||||||
value: string | null | undefined;
|
|
||||||
modelValue: string | null;
|
|
||||||
rotulo: string;
|
|
||||||
placeholder: string;
|
|
||||||
desabilitado: boolean;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any> | import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<number | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
sufixo?: string;
|
|
||||||
prefixo?: string;
|
|
||||||
precisao?: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
emit: ((event: "input", _v: number | null | undefined) => void) & ((event: "update:value", _v: number | null | undefined) => void) & ((event: "change", _v: number | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void);
|
|
||||||
displayValue: import("vue").Ref<string, string>;
|
|
||||||
isInteiro: import("vue").ComputedRef<boolean>;
|
|
||||||
onUpdateModelValue: (texto: string) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: number | null | undefined) => true;
|
|
||||||
input: (_v: number | null | undefined) => true;
|
|
||||||
change: (_v: number | null | undefined) => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<number | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
sufixo?: string;
|
|
||||||
prefixo?: string;
|
|
||||||
precisao?: number;
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
onChange?: ((_v: number | null | undefined) => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
value: number | null | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any> | import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
emit: ((event: "input", _v: string | null | undefined) => void) & ((event: "update:value", _v: string | null | undefined) => void) & ((event: "change", _v: string | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void);
|
|
||||||
localValue: import("vue").WritableComputedRef<string | null | undefined, string | null | undefined>;
|
|
||||||
inputHtmlType: import("vue").ComputedRef<"text" | "email" | "url">;
|
|
||||||
inputMode: import("vue").ComputedRef<string | undefined>;
|
|
||||||
onInput: (e: Event) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: string | null | undefined) => true;
|
|
||||||
input: (_v: string | null | undefined) => true;
|
|
||||||
change: (_v: string | null | undefined) => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
value: string | null | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
opcoesEntrada: (entrada: ComponenteEntrada) => any;
|
|
||||||
adicionar: () => void;
|
|
||||||
remover: (idx: number) => void;
|
|
||||||
emitFechar: () => void;
|
|
||||||
emitSalvar: () => void;
|
|
||||||
emitLimpar: () => void;
|
|
||||||
rotuloDoFiltro: typeof rotuloDoFiltro;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
fechar: () => true;
|
|
||||||
limpar: () => true;
|
|
||||||
salvar: (_linhas: any[]) => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
aberto: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
filtrosBase: {
|
|
||||||
type: PropType<Array<FiltroBase<any>>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
modelo: {
|
|
||||||
type: PropType<Array<any>>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onFechar?: (() => any) | undefined;
|
|
||||||
onSalvar?: ((_linhas: any[]) => any) | undefined;
|
|
||||||
onLimpar?: (() => any) | undefined;
|
|
||||||
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
pagina: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
totalPaginas: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
maximoBotoes: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
acoes: {
|
|
||||||
type: PropType<Array<{
|
|
||||||
icone?: any;
|
|
||||||
cor?: string;
|
|
||||||
rotulo: string;
|
|
||||||
acao: (params?: any) => void;
|
|
||||||
}>>;
|
|
||||||
required: false;
|
|
||||||
default: () => never[];
|
|
||||||
};
|
|
||||||
parametrosConsulta: {
|
|
||||||
type: PropType<any>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
botoes: import("vue").ComputedRef<{
|
|
||||||
label: string;
|
|
||||||
pagina?: number;
|
|
||||||
ativo?: boolean;
|
|
||||||
ehEllipsis?: boolean;
|
|
||||||
}[]>;
|
|
||||||
irParaPagina: (pagina: number | undefined) => void;
|
|
||||||
anteriorDesabilitado: import("vue").ComputedRef<boolean>;
|
|
||||||
proximaDesabilitada: import("vue").ComputedRef<boolean>;
|
|
||||||
paginaAtual: import("vue").ComputedRef<number>;
|
|
||||||
totalPaginasExibidas: import("vue").ComputedRef<number>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
alterar(pagina: number): boolean;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
pagina: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
totalPaginas: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
maximoBotoes: {
|
|
||||||
type: NumberConstructor;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
acoes: {
|
|
||||||
type: PropType<Array<{
|
|
||||||
icone?: any;
|
|
||||||
cor?: string;
|
|
||||||
rotulo: string;
|
|
||||||
acao: (params?: any) => void;
|
|
||||||
}>>;
|
|
||||||
required: false;
|
|
||||||
default: () => never[];
|
|
||||||
};
|
|
||||||
parametrosConsulta: {
|
|
||||||
type: PropType<any>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onAlterar?: ((pagina: number) => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
acoes: {
|
|
||||||
icone?: any;
|
|
||||||
cor?: string;
|
|
||||||
rotulo: string;
|
|
||||||
acao: (params?: any) => void;
|
|
||||||
}[];
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import type { Component } from "vue";
|
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tipoComponenteCelula } from "../types-eli-tabela";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
Componente: import("vue").ComputedRef<Component>;
|
|
||||||
dadosParaComponente: import("vue").ComputedRef<{
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
celula: {
|
|
||||||
type: PropType<tipoComponenteCelula>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["data"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
textoData: import("vue").ComputedRef<string>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["data"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["numero"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
textoNumero: import("vue").ComputedRef<string>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["numero"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,683 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["tags"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["tags"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {
|
|
||||||
VChip: {
|
|
||||||
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"click:close": (e: MouseEvent) => true;
|
|
||||||
"update:modelValue": (value: boolean) => true;
|
|
||||||
"group:selected": (val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => true;
|
|
||||||
click: (e: KeyboardEvent | MouseEvent) => true;
|
|
||||||
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}, true, {}, import("vue").SlotsType<Partial<{
|
|
||||||
default: (arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
label: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
close: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
filter: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
||||||
P: {};
|
|
||||||
B: {};
|
|
||||||
D: {};
|
|
||||||
C: {};
|
|
||||||
M: {};
|
|
||||||
Defaults: {};
|
|
||||||
}, {
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, {}, {}, {}, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}>;
|
|
||||||
__isFragment?: undefined;
|
|
||||||
__isTeleport?: undefined;
|
|
||||||
__isSuspense?: undefined;
|
|
||||||
} & import("vue").ComponentOptionsBase<{
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"click:close": (e: MouseEvent) => true;
|
|
||||||
"update:modelValue": (value: boolean) => true;
|
|
||||||
"group:selected": (val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => true;
|
|
||||||
click: (e: KeyboardEvent | MouseEvent) => true;
|
|
||||||
}, string, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}, {}, string, import("vue").SlotsType<Partial<{
|
|
||||||
default: (arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
label: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
close: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
filter: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("vuetify/lib/util/defineComponent.mjs").FilterPropsOptions<{
|
|
||||||
theme: StringConstructor;
|
|
||||||
class: PropType<any>;
|
|
||||||
style: {
|
|
||||||
type: PropType<import("vue").StyleValue>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
density: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/density.mjs").Density>;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
};
|
|
||||||
elevation: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
validator(v: any): boolean;
|
|
||||||
};
|
|
||||||
rounded: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
tile: BooleanConstructor;
|
|
||||||
tag: Omit<{
|
|
||||||
type: PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: string;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: NonNullable<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
};
|
|
||||||
color: StringConstructor;
|
|
||||||
variant: Omit<{
|
|
||||||
type: PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: NonNullable<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
};
|
|
||||||
value: null;
|
|
||||||
disabled: BooleanConstructor;
|
|
||||||
selectedClass: StringConstructor;
|
|
||||||
size: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
href: StringConstructor;
|
|
||||||
replace: BooleanConstructor;
|
|
||||||
to: PropType<string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric>;
|
|
||||||
exact: BooleanConstructor;
|
|
||||||
activeClass: StringConstructor;
|
|
||||||
appendAvatar: StringConstructor;
|
|
||||||
appendIcon: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
baseColor: StringConstructor;
|
|
||||||
closable: BooleanConstructor;
|
|
||||||
closeIcon: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
closeLabel: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
draggable: BooleanConstructor;
|
|
||||||
filter: BooleanConstructor;
|
|
||||||
filterIcon: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
label: BooleanConstructor;
|
|
||||||
link: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
pill: BooleanConstructor;
|
|
||||||
prependAvatar: StringConstructor;
|
|
||||||
prependIcon: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
ripple: {
|
|
||||||
type: PropType<boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined>;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
text: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
onClick: PropType<(args_0: MouseEvent) => void>;
|
|
||||||
onClickOnce: PropType<(args_0: MouseEvent) => void>;
|
|
||||||
}, import("vue").ExtractPropTypes<{
|
|
||||||
theme: StringConstructor;
|
|
||||||
class: PropType<any>;
|
|
||||||
style: {
|
|
||||||
type: PropType<import("vue").StyleValue>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
density: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/density.mjs").Density>;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
};
|
|
||||||
elevation: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
validator(v: any): boolean;
|
|
||||||
};
|
|
||||||
rounded: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
tile: BooleanConstructor;
|
|
||||||
tag: Omit<{
|
|
||||||
type: PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: string;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: NonNullable<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
};
|
|
||||||
color: StringConstructor;
|
|
||||||
variant: Omit<{
|
|
||||||
type: PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: NonNullable<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
};
|
|
||||||
value: null;
|
|
||||||
disabled: BooleanConstructor;
|
|
||||||
selectedClass: StringConstructor;
|
|
||||||
size: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
href: StringConstructor;
|
|
||||||
replace: BooleanConstructor;
|
|
||||||
to: PropType<string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric>;
|
|
||||||
exact: BooleanConstructor;
|
|
||||||
activeClass: StringConstructor;
|
|
||||||
appendAvatar: StringConstructor;
|
|
||||||
appendIcon: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
baseColor: StringConstructor;
|
|
||||||
closable: BooleanConstructor;
|
|
||||||
closeIcon: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
closeLabel: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
draggable: BooleanConstructor;
|
|
||||||
filter: BooleanConstructor;
|
|
||||||
filterIcon: {
|
|
||||||
type: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
label: BooleanConstructor;
|
|
||||||
link: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
pill: BooleanConstructor;
|
|
||||||
prependAvatar: StringConstructor;
|
|
||||||
prependIcon: PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
ripple: {
|
|
||||||
type: PropType<boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined>;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
text: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
onClick: PropType<(args_0: MouseEvent) => void>;
|
|
||||||
onClickOnce: PropType<(args_0: MouseEvent) => void>;
|
|
||||||
}>>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["textoSimples"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["textoSimples"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["textoTruncado"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: PropType<tiposTabelaCelulas["textoTruncado"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
|
|
@ -1,744 +0,0 @@
|
||||||
export declare const registryTabelaCelulas: {
|
|
||||||
readonly textoSimples: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["textoSimples"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["textoSimples"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
readonly textoTruncado: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["textoTruncado"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["textoTruncado"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
readonly numero: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["numero"]>;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
numero: number;
|
|
||||||
prefixo?: string;
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
textoNumero: import("vue").ComputedRef<string>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["numero"]>;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
readonly tags: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["tags"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
} | undefined;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["tags"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {
|
|
||||||
VChip: {
|
|
||||||
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"click:close": (e: MouseEvent) => true;
|
|
||||||
"update:modelValue": (value: boolean) => true;
|
|
||||||
"group:selected": (val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => true;
|
|
||||||
click: (e: KeyboardEvent | MouseEvent) => true;
|
|
||||||
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}, true, {}, import("vue").SlotsType<Partial<{
|
|
||||||
default: (arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
label: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
close: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
filter: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
|
|
||||||
P: {};
|
|
||||||
B: {};
|
|
||||||
D: {};
|
|
||||||
C: {};
|
|
||||||
M: {};
|
|
||||||
Defaults: {};
|
|
||||||
}, {
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, {}, {}, {}, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}>;
|
|
||||||
__isFragment?: undefined;
|
|
||||||
__isTeleport?: undefined;
|
|
||||||
__isSuspense?: undefined;
|
|
||||||
} & import("vue").ComponentOptionsBase<{
|
|
||||||
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
};
|
|
||||||
modelValue: boolean;
|
|
||||||
} & {
|
|
||||||
theme?: string | undefined;
|
|
||||||
class?: any;
|
|
||||||
border?: string | number | boolean | undefined;
|
|
||||||
elevation?: string | number | undefined;
|
|
||||||
rounded?: string | number | boolean | undefined;
|
|
||||||
color?: string | undefined;
|
|
||||||
value?: any;
|
|
||||||
selectedClass?: string | undefined;
|
|
||||||
href?: string | undefined;
|
|
||||||
to?: string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric | undefined;
|
|
||||||
activeClass?: string | undefined;
|
|
||||||
appendAvatar?: string | undefined;
|
|
||||||
appendIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
baseColor?: string | undefined;
|
|
||||||
link?: boolean | undefined;
|
|
||||||
prependAvatar?: string | undefined;
|
|
||||||
prependIcon?: import("vuetify/lib/composables/icons.mjs").IconValue | undefined;
|
|
||||||
text?: string | number | boolean | undefined;
|
|
||||||
onClick?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
onClickOnce?: ((args_0: MouseEvent) => void) | undefined;
|
|
||||||
} & {
|
|
||||||
$children?: {
|
|
||||||
default?: ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | {
|
|
||||||
$stable?: boolean | undefined;
|
|
||||||
} | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | import("vue").VNodeChild;
|
|
||||||
"v-slots"?: {
|
|
||||||
default?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
label?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
prepend?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
append?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
close?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
filter?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} | undefined;
|
|
||||||
} & {
|
|
||||||
"v-slot:append"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:close"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:default"?: false | ((arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:filter"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:label"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
"v-slot:prepend"?: false | (() => import("vue").VNodeChild) | undefined;
|
|
||||||
} & {
|
|
||||||
onClick?: ((e: KeyboardEvent | MouseEvent) => any) | undefined;
|
|
||||||
"onClick:close"?: ((e: MouseEvent) => any) | undefined;
|
|
||||||
"onGroup:selected"?: ((val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => any) | undefined;
|
|
||||||
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
||||||
}, () => false | JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"click:close": (e: MouseEvent) => true;
|
|
||||||
"update:modelValue": (value: boolean) => true;
|
|
||||||
"group:selected": (val: {
|
|
||||||
value: boolean;
|
|
||||||
}) => true;
|
|
||||||
click: (e: KeyboardEvent | MouseEvent) => true;
|
|
||||||
}, string, {
|
|
||||||
style: import("vue").StyleValue;
|
|
||||||
density: import("vuetify/lib/composables/density.mjs").Density;
|
|
||||||
rounded: string | number | boolean;
|
|
||||||
tile: boolean;
|
|
||||||
tag: string | import("vuetify/lib/types.mjs").JSXComponent;
|
|
||||||
variant: "elevated" | "flat" | "outlined" | "plain" | "text" | "tonal";
|
|
||||||
disabled: boolean;
|
|
||||||
size: string | number;
|
|
||||||
replace: boolean;
|
|
||||||
exact: boolean;
|
|
||||||
closable: boolean;
|
|
||||||
closeIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
closeLabel: string;
|
|
||||||
draggable: boolean;
|
|
||||||
filter: boolean;
|
|
||||||
filterIcon: import("vuetify/lib/composables/icons.mjs").IconValue;
|
|
||||||
label: boolean;
|
|
||||||
link: boolean;
|
|
||||||
pill: boolean;
|
|
||||||
ripple: boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined;
|
|
||||||
text: string | number | boolean;
|
|
||||||
modelValue: boolean;
|
|
||||||
}, {}, string, import("vue").SlotsType<Partial<{
|
|
||||||
default: (arg: {
|
|
||||||
isSelected: boolean | undefined;
|
|
||||||
selectedClass: boolean | (string | undefined)[] | undefined;
|
|
||||||
select: ((value: boolean) => void) | undefined;
|
|
||||||
toggle: (() => void) | undefined;
|
|
||||||
value: unknown;
|
|
||||||
disabled: boolean;
|
|
||||||
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
label: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
prepend: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
append: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
close: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
filter: () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
||||||
[key: string]: any;
|
|
||||||
}>[];
|
|
||||||
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("vuetify/lib/util/defineComponent.mjs").FilterPropsOptions<{
|
|
||||||
theme: StringConstructor;
|
|
||||||
class: import("vue").PropType<any>;
|
|
||||||
style: {
|
|
||||||
type: import("vue").PropType<import("vue").StyleValue>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
density: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/density.mjs").Density>;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
};
|
|
||||||
elevation: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
validator(v: any): boolean;
|
|
||||||
};
|
|
||||||
rounded: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
tile: BooleanConstructor;
|
|
||||||
tag: Omit<{
|
|
||||||
type: import("vue").PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: string;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: import("vue").PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: NonNullable<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
};
|
|
||||||
color: StringConstructor;
|
|
||||||
variant: Omit<{
|
|
||||||
type: import("vue").PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: import("vue").PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: NonNullable<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
};
|
|
||||||
value: null;
|
|
||||||
disabled: BooleanConstructor;
|
|
||||||
selectedClass: StringConstructor;
|
|
||||||
size: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
href: StringConstructor;
|
|
||||||
replace: BooleanConstructor;
|
|
||||||
to: import("vue").PropType<string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric>;
|
|
||||||
exact: BooleanConstructor;
|
|
||||||
activeClass: StringConstructor;
|
|
||||||
appendAvatar: StringConstructor;
|
|
||||||
appendIcon: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
baseColor: StringConstructor;
|
|
||||||
closable: BooleanConstructor;
|
|
||||||
closeIcon: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
closeLabel: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
draggable: BooleanConstructor;
|
|
||||||
filter: BooleanConstructor;
|
|
||||||
filterIcon: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
label: BooleanConstructor;
|
|
||||||
link: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
pill: BooleanConstructor;
|
|
||||||
prependAvatar: StringConstructor;
|
|
||||||
prependIcon: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
ripple: {
|
|
||||||
type: import("vue").PropType<boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined>;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
text: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
onClick: import("vue").PropType<(args_0: MouseEvent) => void>;
|
|
||||||
onClickOnce: import("vue").PropType<(args_0: MouseEvent) => void>;
|
|
||||||
}, import("vue").ExtractPropTypes<{
|
|
||||||
theme: StringConstructor;
|
|
||||||
class: import("vue").PropType<any>;
|
|
||||||
style: {
|
|
||||||
type: import("vue").PropType<import("vue").StyleValue>;
|
|
||||||
default: null;
|
|
||||||
};
|
|
||||||
border: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
density: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/density.mjs").Density>;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
};
|
|
||||||
elevation: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
validator(v: any): boolean;
|
|
||||||
};
|
|
||||||
rounded: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
tile: BooleanConstructor;
|
|
||||||
tag: Omit<{
|
|
||||||
type: import("vue").PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: string;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: import("vue").PropType<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
default: NonNullable<string | import("vuetify/lib/types.mjs").JSXComponent>;
|
|
||||||
};
|
|
||||||
color: StringConstructor;
|
|
||||||
variant: Omit<{
|
|
||||||
type: import("vue").PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: string;
|
|
||||||
validator: (v: any) => boolean;
|
|
||||||
}, "default" | "type"> & {
|
|
||||||
type: import("vue").PropType<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
default: NonNullable<"elevated" | "flat" | "outlined" | "plain" | "text" | "tonal">;
|
|
||||||
};
|
|
||||||
value: null;
|
|
||||||
disabled: BooleanConstructor;
|
|
||||||
selectedClass: StringConstructor;
|
|
||||||
size: {
|
|
||||||
type: (NumberConstructor | StringConstructor)[];
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
href: StringConstructor;
|
|
||||||
replace: BooleanConstructor;
|
|
||||||
to: import("vue").PropType<string | import("vue-router").RouteLocationAsPathGeneric | import("vue-router").RouteLocationAsRelativeGeneric>;
|
|
||||||
exact: BooleanConstructor;
|
|
||||||
activeClass: StringConstructor;
|
|
||||||
appendAvatar: StringConstructor;
|
|
||||||
appendIcon: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
baseColor: StringConstructor;
|
|
||||||
closable: BooleanConstructor;
|
|
||||||
closeIcon: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
closeLabel: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
draggable: BooleanConstructor;
|
|
||||||
filter: BooleanConstructor;
|
|
||||||
filterIcon: {
|
|
||||||
type: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
label: BooleanConstructor;
|
|
||||||
link: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
pill: BooleanConstructor;
|
|
||||||
prependAvatar: StringConstructor;
|
|
||||||
prependIcon: import("vue").PropType<import("vuetify/lib/composables/icons.mjs").IconValue>;
|
|
||||||
ripple: {
|
|
||||||
type: import("vue").PropType<boolean | {
|
|
||||||
class?: string | undefined;
|
|
||||||
keys?: string[] | undefined;
|
|
||||||
} | undefined>;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
text: {
|
|
||||||
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
modelValue: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
onClick: import("vue").PropType<(args_0: MouseEvent) => void>;
|
|
||||||
onClickOnce: import("vue").PropType<(args_0: MouseEvent) => void>;
|
|
||||||
}>>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
readonly data: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["data"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
dados: {
|
|
||||||
valor: string;
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
acao?: () => void;
|
|
||||||
} | undefined;
|
|
||||||
textoData: import("vue").ComputedRef<string>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
dados: {
|
|
||||||
type: import("vue").PropType<import("./tiposTabelaCelulas").tiposTabelaCelulas["data"]>;
|
|
||||||
required: false;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
};
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipagem dos dados de entrada dos componentes de celulas
|
|
||||||
*/
|
|
||||||
import type { LucideIcon } from "lucide-vue-next";
|
|
||||||
export type tiposTabelaCelulas = {
|
|
||||||
textoSimples: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
};
|
|
||||||
textoTruncado: {
|
|
||||||
texto: string;
|
|
||||||
acao?: () => void;
|
|
||||||
};
|
|
||||||
numero: {
|
|
||||||
numero: number;
|
|
||||||
/** Texto opcional exibido antes do número (ex.: "R$", "≈"). */
|
|
||||||
prefixo?: string;
|
|
||||||
/** Texto opcional exibido depois do número (ex.: "kg", "%"). */
|
|
||||||
sufixo?: string;
|
|
||||||
acao?: () => void;
|
|
||||||
};
|
|
||||||
tags: {
|
|
||||||
opcoes: {
|
|
||||||
/** Texto exibido dentro da tag. */
|
|
||||||
rotulo: string;
|
|
||||||
/** Cor do chip (segue as cores do Vuetify, ex.: "primary", "success", "error"). */
|
|
||||||
cor?: string;
|
|
||||||
/** Ícone (Lucide) opcional exibido antes do rótulo. */
|
|
||||||
icone?: LucideIcon;
|
|
||||||
/** Ação opcional da tag. Quando existir, o chip vira clicável. */
|
|
||||||
acao?: () => void;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
data: {
|
|
||||||
/** Valor em ISO 8601 (ex.: "2026-01-09T16:15:00Z"). */
|
|
||||||
valor: string;
|
|
||||||
/** Define o formato de exibição. */
|
|
||||||
formato: "data" | "data_hora" | "relativo";
|
|
||||||
/** Ação opcional ao clicar no valor. */
|
|
||||||
acao?: () => void;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
export type tipoTabelaCelula = keyof tiposTabelaCelulas;
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
export type EliTabelaColunasConfig = {
|
|
||||||
/** Rotulos das colunas visiveis (em ordem). */
|
|
||||||
visiveis: string[];
|
|
||||||
/** Rotulos das colunas invisiveis. */
|
|
||||||
invisiveis: string[];
|
|
||||||
};
|
|
||||||
export declare function storageKeyColunas(nomeTabela: string): string;
|
|
||||||
export declare function carregarConfigColunas(nomeTabela: string): EliTabelaColunasConfig;
|
|
||||||
export declare function salvarConfigColunas(nomeTabela: string, config: EliTabelaColunasConfig): void;
|
|
||||||
export declare function limparConfigColunas(nomeTabela: string): void;
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
export type EliTabelaFiltroAvancadoSalvo<T> = Array<{
|
|
||||||
coluna: keyof T;
|
|
||||||
valor: T[keyof T];
|
|
||||||
}>;
|
|
||||||
export declare function carregarFiltroAvancado<T>(nomeTabela: string): EliTabelaFiltroAvancadoSalvo<T>;
|
|
||||||
export declare function salvarFiltroAvancado<T>(nomeTabela: string, filtros: EliTabelaFiltroAvancadoSalvo<T>): void;
|
|
||||||
export declare function limparFiltroAvancado(nomeTabela: string): void;
|
|
||||||
4
dist/types/componentes/EliTabela/index.d.ts
vendored
4
dist/types/componentes/EliTabela/index.d.ts
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
export * from "./celulas/tiposTabelaCelulas";
|
|
||||||
export { default as EliTabela } from "./EliTabela.vue";
|
|
||||||
export * from "./types-eli-tabela";
|
|
||||||
export { celulaTabela } from "./types-eli-tabela";
|
|
||||||
|
|
@ -1,127 +0,0 @@
|
||||||
import type { LucideIcon } from "lucide-vue-next";
|
|
||||||
import type { tipoFiltro26 } from "p-comuns";
|
|
||||||
export type tipoFiltro<T> = tipoFiltro26<T>;
|
|
||||||
import type { tipoResposta } from "p-respostas";
|
|
||||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas";
|
|
||||||
import type { tiposTabelaCelulas, tipoTabelaCelula } from "./celulas/tiposTabelaCelulas";
|
|
||||||
export type tipoComponenteCelulaBase<T extends tipoTabelaCelula> = readonly [
|
|
||||||
T,
|
|
||||||
tiposTabelaCelulas[T]
|
|
||||||
];
|
|
||||||
export type tipoComponenteCelula = {
|
|
||||||
[K in tipoTabelaCelula]: tipoComponenteCelulaBase<K>;
|
|
||||||
}[tipoTabelaCelula];
|
|
||||||
export declare const celulaTabela: <T extends tipoTabelaCelula>(tipo: T, dados: tiposTabelaCelulas[T]) => tipoComponenteCelulaBase<T>;
|
|
||||||
export type { tipoTabelaCelula, tiposTabelaCelulas };
|
|
||||||
export type tipoEliColuna<T> = {
|
|
||||||
/** Texto exibido no cabeçalho da coluna. */
|
|
||||||
rotulo: string;
|
|
||||||
/** Função responsável por renderizar o conteúdo da célula. */
|
|
||||||
celula: (linha: T) => tipoComponenteCelula;
|
|
||||||
/** Ação opcional disparada ao clicar na célula. */
|
|
||||||
/**
|
|
||||||
* Campo de ordenação associado à coluna. Caso informado, a coluna passa a
|
|
||||||
* exibir controles de ordenação e utiliza o valor como chave para o backend.
|
|
||||||
*/
|
|
||||||
coluna_ordem?: keyof T;
|
|
||||||
/**
|
|
||||||
* indica que a coluna será visivel, se false incia em detalhe
|
|
||||||
* Caso já tenha salvo a propriedade de visibilidade será adotado a propriedade salva
|
|
||||||
*/
|
|
||||||
visivel: boolean;
|
|
||||||
};
|
|
||||||
export type tipoEliConsultaPaginada<T> = {
|
|
||||||
/** Registros retornados na consulta. */
|
|
||||||
valores: T[];
|
|
||||||
/** Total de registros disponíveis no backend. */
|
|
||||||
quantidade: number;
|
|
||||||
};
|
|
||||||
export type tipoEliTabelaAcao<T> = {
|
|
||||||
/** Ícone (Lucide) exibido para representar a ação. */
|
|
||||||
icone: LucideIcon;
|
|
||||||
/** Cor aplicada ao ícone e rótulo. */
|
|
||||||
cor: string;
|
|
||||||
/** Texto descritivo da ação. */
|
|
||||||
rotulo: string;
|
|
||||||
/** Função executada quando o usuário ativa a ação. */
|
|
||||||
acao: (linha: T) => void;
|
|
||||||
/**
|
|
||||||
* Define se a ação deve ser exibida para a linha. Pode ser um booleano fixo
|
|
||||||
* ou uma função (sincrona/assíncrona) que recebe a linha para decisão dinâmica.
|
|
||||||
*/
|
|
||||||
exibir?: boolean | ((linha: T) => Promise<boolean> | boolean);
|
|
||||||
};
|
|
||||||
export type parametrosConsulta<T> = {
|
|
||||||
filtros?: tipoFiltro26<T>[];
|
|
||||||
coluna_ordem?: keyof T;
|
|
||||||
direcao_ordem?: "asc" | "desc";
|
|
||||||
offSet?: number;
|
|
||||||
limit?: number;
|
|
||||||
/** Texto digitado na caixa de busca, quando habilitada. */
|
|
||||||
texto_busca?: string;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Estrutura de dados para uma tabela alimentada por uma consulta.
|
|
||||||
*
|
|
||||||
* - `colunas`: definição de colunas e como renderizar cada célula
|
|
||||||
* - `consulta`: função que recupera os dados, com suporte a ordenação/paginação
|
|
||||||
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
|
||||||
*/
|
|
||||||
export type tipoEliTabelaConsulta<T> = {
|
|
||||||
/** nome da tabela, um identificador unico */
|
|
||||||
nome: string;
|
|
||||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
|
||||||
mostrarCaixaDeBusca?: boolean;
|
|
||||||
/** Lista de colunas da tabela. */
|
|
||||||
colunas: tipoEliColuna<T>[];
|
|
||||||
/** Quantidade de registros solicitados por consulta (padrão `10`). */
|
|
||||||
registros_por_consulta?: number;
|
|
||||||
/**
|
|
||||||
* Função responsável por buscar os dados. Recebe parâmetros opcionais de
|
|
||||||
* ordenação (`coluna_ordem`/`direcao_ordem`) e paginação (`offSet`/`limit`).
|
|
||||||
*/
|
|
||||||
consulta: (parametrosConsulta?: parametrosConsulta<T>) => Promise<tipoResposta<tipoEliConsultaPaginada<T>>>;
|
|
||||||
/** Quantidade máxima de botões exibidos na paginação (padrão `7`). */
|
|
||||||
maximo_botoes_paginacao?: number;
|
|
||||||
/** Mensagem exibida quando a consulta retorna ok porém sem dados. */
|
|
||||||
mensagemVazio?: string;
|
|
||||||
/** Ações exibidas à direita de cada linha. */
|
|
||||||
acoesLinha?: tipoEliTabelaAcao<T>[];
|
|
||||||
/**
|
|
||||||
* Configurações dos botões que serão inseridos a direita da caixa de busca.
|
|
||||||
* Seu uso mais comum será para criar novos registros, mas poderá ter outras utilidades.
|
|
||||||
*/
|
|
||||||
acoesTabela?: {
|
|
||||||
/** superio será exibido a direita da caixa de busca, inferior a direita da paginação */
|
|
||||||
posicao: "superior" | "inferior";
|
|
||||||
/** Ícone (Lucide) exibido no botão */
|
|
||||||
icone?: LucideIcon;
|
|
||||||
/** Cor aplicada ao botão. */
|
|
||||||
cor?: string;
|
|
||||||
/** Texto descritivo da ação. */
|
|
||||||
rotulo: string;
|
|
||||||
/** Função executada ao clicar no botão. */
|
|
||||||
acao: (parametrosConsulta: parametrosConsulta<T> & {
|
|
||||||
/**
|
|
||||||
* Callback opcional para forçar atualização da consulta.
|
|
||||||
* Observação: o componente `EliTabela` pode ignorar isso dependendo do modo de uso.
|
|
||||||
*/
|
|
||||||
atualizarConsulta: () => Promise<void>;
|
|
||||||
/**
|
|
||||||
* Callback opcional para permitir editar a lista localmente (sem refazer consulta).
|
|
||||||
* Observação: o componente `EliTabela` pode ignorar isso dependendo do modo de uso.
|
|
||||||
*/
|
|
||||||
editarLista: (lista: T[]) => Promise<T[]>;
|
|
||||||
}) => void;
|
|
||||||
}[];
|
|
||||||
filtroAvancado?: {
|
|
||||||
/** Identificador único do filtro (usado para persistência) */
|
|
||||||
chave: string;
|
|
||||||
/** Rótulo exibido no select de adicionar filtro */
|
|
||||||
rotulo: string;
|
|
||||||
/** vai gerar filtro e mescla com os filtros já existentes */
|
|
||||||
filtro: (valor: unknown) => tipoFiltro26<T>;
|
|
||||||
/** componente de entrada que vai receber o valor para o filtro */
|
|
||||||
entrada: ComponenteEntrada;
|
|
||||||
}[];
|
|
||||||
};
|
|
||||||
53
dist/types/componentes/botao/EliBotao.vue.d.ts
vendored
53
dist/types/componentes/botao/EliBotao.vue.d.ts
vendored
|
|
@ -1,53 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { BotaoTamanho, BotaoVariante } from "../../tipos";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
variant: {
|
|
||||||
type: PropType<BotaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
size: {
|
|
||||||
type: PropType<BotaoTamanho>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
disabled: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
loading: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
variant: {
|
|
||||||
type: PropType<BotaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
size: {
|
|
||||||
type: PropType<BotaoTamanho>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
disabled: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
loading: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
color: string;
|
|
||||||
variant: BotaoVariante;
|
|
||||||
size: BotaoTamanho;
|
|
||||||
disabled: boolean;
|
|
||||||
loading: boolean;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
1
dist/types/componentes/botao/index.d.ts
vendored
1
dist/types/componentes/botao/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
||||||
export { default as EliBotao } from "./EliBotao.vue";
|
|
||||||
148
dist/types/componentes/cartao/EliCartao.vue.d.ts
vendored
148
dist/types/componentes/cartao/EliCartao.vue.d.ts
vendored
|
|
@ -1,148 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { CartaoStatus } from "../../tipos";
|
|
||||||
type CartaoVariante = "outlined" | "flat" | "elevated" | "tonal";
|
|
||||||
/**
|
|
||||||
* EliCartao
|
|
||||||
*
|
|
||||||
* Um cartão de domínio para listas/pipelines (ex.: oportunidades/propostas) com:
|
|
||||||
* - título
|
|
||||||
* - status padronizado (novo/rascunho/vendido/cancelado)
|
|
||||||
* - slot padrão para conteúdo
|
|
||||||
* - slot opcional para ações
|
|
||||||
*/
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
/** Título de fallback caso o slot `titulo` não seja usado. */
|
|
||||||
titulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Status semântico do cartão.
|
|
||||||
* Usado para cor/label e para permitir filtros por status.
|
|
||||||
*/
|
|
||||||
status: {
|
|
||||||
type: PropType<CartaoStatus>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
/** Variante visual do v-card (Vuetify). */
|
|
||||||
variant: {
|
|
||||||
type: PropType<CartaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
rotuloStatus: import("vue").ComputedRef<CartaoStatus>;
|
|
||||||
corStatus: import("vue").ComputedRef<"primary" | "secondary" | "success" | "error">;
|
|
||||||
classeStatus: import("vue").ComputedRef<string>;
|
|
||||||
onClick: () => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
/** Emit opcional para padronizar clique no cartão. */
|
|
||||||
clicar: (_status: CartaoStatus) => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
/** Título de fallback caso o slot `titulo` não seja usado. */
|
|
||||||
titulo: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Status semântico do cartão.
|
|
||||||
* Usado para cor/label e para permitir filtros por status.
|
|
||||||
*/
|
|
||||||
status: {
|
|
||||||
type: PropType<CartaoStatus>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
/** Variante visual do v-card (Vuetify). */
|
|
||||||
variant: {
|
|
||||||
type: PropType<CartaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onClicar?: ((_status: CartaoStatus) => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
variant: CartaoVariante;
|
|
||||||
titulo: string;
|
|
||||||
}, {}, {
|
|
||||||
EliBadge: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: PropType<import("../..").IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: PropType<import("../..").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: PropType<import("../..").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
radius: {
|
|
||||||
type: PropType<import("../..").IndicadorPresetRaio | import("../..").CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
showBadge: import("vue").ComputedRef<boolean>;
|
|
||||||
badgeStyle: import("vue").ComputedRef<{
|
|
||||||
"--eli-badge-radius": string;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: PropType<import("../..").IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: PropType<import("../..").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: PropType<import("../..").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
radius: {
|
|
||||||
type: PropType<import("../..").IndicadorPresetRaio | import("../..").CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
color: string;
|
|
||||||
location: import("../..").IndicadorLocalizacao;
|
|
||||||
offsetX: import("../..").IndicadorOffset;
|
|
||||||
offsetY: import("../..").IndicadorOffset;
|
|
||||||
dot: boolean;
|
|
||||||
visible: boolean;
|
|
||||||
badge: string | number | undefined;
|
|
||||||
radius: import("../..").IndicadorPresetRaio | import("../..").CssLength;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
1
dist/types/componentes/cartao/index.d.ts
vendored
1
dist/types/componentes/cartao/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
||||||
export { default as EliCartao } from "./EliCartao.vue";
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
import { type PropType } from "vue";
|
|
||||||
import type { CssLength, IndicadorLocalizacao, IndicadorOffset, IndicadorPresetRaio } from "../../tipos";
|
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: PropType<IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: PropType<IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: PropType<IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
/** 🔥 NOVO: controla só o radius */
|
|
||||||
radius: {
|
|
||||||
type: PropType<IndicadorPresetRaio | CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
showBadge: import("vue").ComputedRef<boolean>;
|
|
||||||
badgeStyle: import("vue").ComputedRef<{
|
|
||||||
"--eli-badge-radius": string;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: PropType<IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: PropType<IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: PropType<IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
/** 🔥 NOVO: controla só o radius */
|
|
||||||
radius: {
|
|
||||||
type: PropType<IndicadorPresetRaio | CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
color: string;
|
|
||||||
location: IndicadorLocalizacao;
|
|
||||||
offsetX: IndicadorOffset;
|
|
||||||
offsetY: IndicadorOffset;
|
|
||||||
dot: boolean;
|
|
||||||
visible: boolean;
|
|
||||||
badge: string | number | undefined;
|
|
||||||
radius: IndicadorPresetRaio | CssLength;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
1
dist/types/componentes/indicador/index.d.ts
vendored
1
dist/types/componentes/indicador/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
||||||
export { default as EliBadge } from "./EliBadge.vue";
|
|
||||||
|
|
@ -1,194 +0,0 @@
|
||||||
declare const _default: typeof __VLS_export;
|
|
||||||
export default _default;
|
|
||||||
declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|
||||||
nome: import("vue").Ref<string, string>;
|
|
||||||
email: import("vue").Ref<string, string>;
|
|
||||||
documento: import("vue").Ref<string, string>;
|
|
||||||
telefone: import("vue").Ref<string, string>;
|
|
||||||
cep: import("vue").Ref<string, string>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {
|
|
||||||
EliBotao: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
variant: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").BotaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
size: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").BotaoTamanho>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
disabled: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
loading: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
variant: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").BotaoVariante>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
size: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").BotaoTamanho>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
disabled: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
loading: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
color: string;
|
|
||||||
variant: import("../../index.js").BotaoVariante;
|
|
||||||
size: import("../../index.js").BotaoTamanho;
|
|
||||||
disabled: boolean;
|
|
||||||
loading: boolean;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
EliBadge: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: import("vue").PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
radius: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorPresetRaio | import("../../index.js").CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
showBadge: import("vue").ComputedRef<boolean>;
|
|
||||||
badgeStyle: import("vue").ComputedRef<{
|
|
||||||
"--eli-badge-radius": string;
|
|
||||||
}>;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
color: {
|
|
||||||
type: StringConstructor;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
location: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorLocalizacao>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetX: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
offsetY: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorOffset>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
dot: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
visible: {
|
|
||||||
type: BooleanConstructor;
|
|
||||||
default: boolean;
|
|
||||||
};
|
|
||||||
badge: {
|
|
||||||
type: import("vue").PropType<string | number | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
radius: {
|
|
||||||
type: import("vue").PropType<import("../../index.js").IndicadorPresetRaio | import("../../index.js").CssLength>;
|
|
||||||
default: string;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{}>, {
|
|
||||||
color: string;
|
|
||||||
location: import("../../index.js").IndicadorLocalizacao;
|
|
||||||
offsetX: import("../../index.js").IndicadorOffset;
|
|
||||||
offsetY: import("../../index.js").IndicadorOffset;
|
|
||||||
dot: boolean;
|
|
||||||
visible: boolean;
|
|
||||||
badge: string | number | undefined;
|
|
||||||
radius: import("../../index.js").IndicadorPresetRaio | import("../../index.js").CssLength;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
EliEntradaTexto: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: import("vue").PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: import("vue").PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>, {
|
|
||||||
attrs: {
|
|
||||||
[x: string]: unknown;
|
|
||||||
};
|
|
||||||
emit: ((event: "input", _v: string | null | undefined) => void) & ((event: "update:value", _v: string | null | undefined) => void) & ((event: "change", _v: string | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void);
|
|
||||||
localValue: import("vue").WritableComputedRef<string | null | undefined, string | null | undefined>;
|
|
||||||
inputHtmlType: import("vue").ComputedRef<"text" | "email" | "url">;
|
|
||||||
inputMode: import("vue").ComputedRef<string | undefined>;
|
|
||||||
onInput: (e: Event) => void;
|
|
||||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
||||||
"update:value": (_v: string | null | undefined) => true;
|
|
||||||
input: (_v: string | null | undefined) => true;
|
|
||||||
change: (_v: string | null | undefined) => true;
|
|
||||||
focus: () => true;
|
|
||||||
blur: () => true;
|
|
||||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
||||||
value: {
|
|
||||||
type: import("vue").PropType<string | null | undefined>;
|
|
||||||
default: undefined;
|
|
||||||
};
|
|
||||||
opcoes: {
|
|
||||||
type: import("vue").PropType<{
|
|
||||||
rotulo: string;
|
|
||||||
placeholder?: string;
|
|
||||||
} & {
|
|
||||||
limiteCaracteres?: number;
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
|
||||||
}>;
|
|
||||||
required: true;
|
|
||||||
};
|
|
||||||
}>> & Readonly<{
|
|
||||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
|
||||||
onFocus?: (() => any) | undefined;
|
|
||||||
onBlur?: (() => any) | undefined;
|
|
||||||
}>, {
|
|
||||||
value: string | null | undefined;
|
|
||||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
||||||
1
dist/types/componentes/ola_mundo/index.d.ts
vendored
1
dist/types/componentes/ola_mundo/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
||||||
export { default as EliOlaMundo } from "./EliOlaMundo.vue";
|
|
||||||
1
dist/types/constantes.d.ts
vendored
1
dist/types/constantes.d.ts
vendored
|
|
@ -1 +0,0 @@
|
||||||
export declare const gif_quero_quero = "https://paiol.idz.one/estaticos/quero-quero.gif";
|
|
||||||
16
dist/types/index.d.ts
vendored
16
dist/types/index.d.ts
vendored
|
|
@ -1,16 +0,0 @@
|
||||||
import type { Plugin } from "vue";
|
|
||||||
import "./styles/eli-vue-fonts.css";
|
|
||||||
import { EliBotao } from "./componentes/botao";
|
|
||||||
import { EliCartao } from "./componentes/cartao";
|
|
||||||
import { EliBadge } from "./componentes/indicador";
|
|
||||||
import { EliOlaMundo } from "./componentes/ola_mundo";
|
|
||||||
export { EliOlaMundo };
|
|
||||||
export { EliBotao };
|
|
||||||
export { EliBadge };
|
|
||||||
export { EliCartao };
|
|
||||||
export { criarFiltro26 } from "p-comuns";
|
|
||||||
export * from "./componentes/EliEntrada";
|
|
||||||
export * from "./componentes/EliTabela";
|
|
||||||
export * from "./tipos";
|
|
||||||
declare const EliVue: Plugin;
|
|
||||||
export default EliVue;
|
|
||||||
6
dist/types/tipos/botao.d.ts
vendored
6
dist/types/tipos/botao.d.ts
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos do componente EliBotao.
|
|
||||||
* Mantidos separados do componente para facilitar reuso e padronização.
|
|
||||||
*/
|
|
||||||
export type BotaoVariante = "elevated" | "flat" | "outlined" | "text" | "tonal";
|
|
||||||
export type BotaoTamanho = "x-small" | "small" | "default" | "large";
|
|
||||||
4
dist/types/tipos/cartao.d.ts
vendored
4
dist/types/tipos/cartao.d.ts
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos do componente EliCartao.
|
|
||||||
*/
|
|
||||||
export type CartaoStatus = "novo" | "rascunho" | "vendido" | "cancelado";
|
|
||||||
9
dist/types/tipos/entrada.d.ts
vendored
9
dist/types/tipos/entrada.d.ts
vendored
|
|
@ -1,9 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos compartilhados para componentes de entrada (EliEntrada*).
|
|
||||||
*
|
|
||||||
* OBS: Estes tipos existiam anteriormente em `tipos/campo.ts` junto do componente
|
|
||||||
* `EliInput`. Como o `EliInput` foi removido, mantemos aqui apenas o que ainda
|
|
||||||
* é relevante para padronização visual/props do Vuetify.
|
|
||||||
*/
|
|
||||||
export type CampoVariante = "outlined" | "filled" | "plain" | "solo" | "solo-filled" | "solo-inverted" | "underlined";
|
|
||||||
export type CampoDensidade = "default" | "comfortable" | "compact";
|
|
||||||
4
dist/types/tipos/index.d.ts
vendored
4
dist/types/tipos/index.d.ts
vendored
|
|
@ -1,4 +0,0 @@
|
||||||
export * from "./botao";
|
|
||||||
export * from "./cartao";
|
|
||||||
export * from "./entrada";
|
|
||||||
export * from "./indicador";
|
|
||||||
7
dist/types/tipos/indicador.d.ts
vendored
7
dist/types/tipos/indicador.d.ts
vendored
|
|
@ -1,7 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos do componente EliBadge (indicador).
|
|
||||||
*/
|
|
||||||
export type IndicadorLocalizacao = "top right" | "right center" | "bottom right" | "top center" | "bottom center" | "top left" | "left center" | "bottom left";
|
|
||||||
export type IndicadorOffset = "-20" | "-15" | "-10" | "-5" | "0" | "20" | "15" | "10" | "5";
|
|
||||||
export type IndicadorPresetRaio = "suave" | "pill";
|
|
||||||
export type CssLength = `${number}px` | `${number}rem` | `${number}%` | "0";
|
|
||||||
26
package.json
26
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "eli-vue",
|
"name": "eli-vue",
|
||||||
"version": "0.1.105",
|
"version": "0.1.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "./dist/eli-vue.umd.js",
|
"main": "./dist/eli-vue.umd.js",
|
||||||
"module": "./dist/eli-vue.es.js",
|
"module": "./dist/eli-vue.es.js",
|
||||||
|
|
@ -12,40 +12,28 @@
|
||||||
"require": "./dist/eli-vue.umd.js"
|
"require": "./dist/eli-vue.umd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"biome": "pnpm exec biome check --write",
|
|
||||||
"check": "pnpm run biome && npx tsc --noEmit",
|
|
||||||
"prebuild": "npm version patch --no-git-tag-version",
|
|
||||||
"build:types": "vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly",
|
"build:types": "vue-tsc -p tsconfig.build.json --declaration --emitDeclarationOnly",
|
||||||
"build": "pnpm run biome && vite build && npm run build:types",
|
"build": "vite build && npm run build:types",
|
||||||
"dev": "pnpm run biome && pnpm run fechar && vite",
|
"dev": "vite",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview"
|
||||||
"fechar": "fuser -k 5555/tcp || true"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"vuetify": "^3.0.0"
|
"vuetify": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "2.4.0",
|
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
"@vitejs/plugin-vue": "^5.0.0",
|
"@vitejs/plugin-vue": "^5.0.0",
|
||||||
"sass": "^1.94.2",
|
"sass": "^1.94.2",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^6.0.0",
|
"vite": "^6.0.0",
|
||||||
"vite-plugin-css-injected-by-js": "^3.5.2",
|
|
||||||
"vite-plugin-vuetify": "^2.1.2",
|
"vite-plugin-vuetify": "^2.1.2",
|
||||||
"vue": "^3.4.0",
|
"vue": "^3.4.0",
|
||||||
"vue-tsc": "^3.1.6",
|
"vue-tsc": "^3.1.6",
|
||||||
"vuetify": "^3.11.2"
|
"vuetify": "^3.11.2"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"cross-fetch": "^4.1.0",
|
|
||||||
"dayjs": "^1.11.19",
|
|
||||||
"lucide-vue-next": "^0.563.0",
|
|
||||||
"p-comuns": "git+https://git2.idz.one/publico/_comuns.git",
|
|
||||||
"p-respostas": "git+https://git2.idz.one/publico/_respostas.git",
|
|
||||||
"uuid": "^13.0.0",
|
|
||||||
"zod": "^4.3.6"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
897
pnpm-lock.yaml
generated
897
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 MiB |
|
|
@ -1,227 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-data-hora">
|
|
||||||
<v-text-field
|
|
||||||
v-model="valor"
|
|
||||||
:type="tipoInput"
|
|
||||||
:label="opcoesEfetivas.rotulo"
|
|
||||||
:placeholder="opcoesEfetivas.placeholder"
|
|
||||||
:disabled="desabilitadoEfetivo"
|
|
||||||
:clearable="Boolean(opcoesEfetivas.limpavel)"
|
|
||||||
:error="Boolean(opcoesEfetivas.erro)"
|
|
||||||
:error-messages="opcoesEfetivas.mensagensErro"
|
|
||||||
:hint="opcoesEfetivas.dica"
|
|
||||||
:persistent-hint="Boolean(opcoesEfetivas.dicaPersistente)"
|
|
||||||
:density="opcoesEfetivas.densidade ?? 'comfortable'"
|
|
||||||
:variant="opcoesEfetivas.variante ?? 'outlined'"
|
|
||||||
:min="minLocal"
|
|
||||||
:max="maxLocal"
|
|
||||||
v-bind="attrs"
|
|
||||||
@focus="emitCompatFocus"
|
|
||||||
@blur="emitCompatBlur"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { dayjsbr } from "p-comuns"
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import type { CampoDensidade, CampoVariante } from "../../tipos"
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas"
|
|
||||||
|
|
||||||
type EntradaDataHora = PadroesEntradas["dataHora"]
|
|
||||||
|
|
||||||
type PropsAntigas = {
|
|
||||||
modo?: "data" | "dataHora"
|
|
||||||
rotulo?: string
|
|
||||||
placeholder?: string
|
|
||||||
desabilitado?: boolean
|
|
||||||
limpavel?: boolean
|
|
||||||
erro?: boolean
|
|
||||||
mensagensErro?: string | string[]
|
|
||||||
dica?: string
|
|
||||||
dicaPersistente?: boolean
|
|
||||||
densidade?: CampoDensidade
|
|
||||||
variante?: CampoVariante
|
|
||||||
min?: string
|
|
||||||
max?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliEntradaDataHora",
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
// --- Novo padrão EliEntrada ---
|
|
||||||
value: {
|
|
||||||
type: String as PropType<EntradaDataHora["value"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
opcoes: {
|
|
||||||
type: Object as PropType<EntradaDataHora["opcoes"]>,
|
|
||||||
required: false,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
|
|
||||||
// --- Compatibilidade com componente antigo EliDataHora ---
|
|
||||||
modelValue: {
|
|
||||||
type: String as PropType<string | null>,
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
modo: {
|
|
||||||
type: String as PropType<PropsAntigas["modo"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
rotulo: { type: String, default: undefined },
|
|
||||||
placeholder: { type: String, default: undefined },
|
|
||||||
desabilitado: { type: Boolean, default: undefined },
|
|
||||||
limpavel: { type: Boolean, default: undefined },
|
|
||||||
erro: { type: Boolean, default: undefined },
|
|
||||||
mensagensErro: {
|
|
||||||
type: [String, Array] as PropType<string | string[]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
dica: { type: String, default: undefined },
|
|
||||||
dicaPersistente: { type: Boolean, default: undefined },
|
|
||||||
densidade: { type: String as PropType<CampoDensidade>, default: undefined },
|
|
||||||
variante: { type: String as PropType<CampoVariante>, default: undefined },
|
|
||||||
min: { type: String as PropType<string | undefined>, default: undefined },
|
|
||||||
max: { type: String as PropType<string | undefined>, default: undefined },
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
// Novo padrão
|
|
||||||
"update:value": (_v: string | null) => true,
|
|
||||||
input: (_v: string | null) => true, // compat Vue2
|
|
||||||
change: (_v: string | null) => true,
|
|
||||||
|
|
||||||
// Compat antigo
|
|
||||||
"update:modelValue": (_v: string | null) => true,
|
|
||||||
alterar: (_v: string | null) => true,
|
|
||||||
foco: () => true,
|
|
||||||
desfoco: () => true,
|
|
||||||
focus: () => true,
|
|
||||||
blur: () => true,
|
|
||||||
},
|
|
||||||
setup(props, { emit, attrs }) {
|
|
||||||
const opcoesEfetivas = computed<EntradaDataHora["opcoes"]>(() => {
|
|
||||||
// 1) se veio `opcoes` (novo), usa
|
|
||||||
if (props.opcoes) return props.opcoes
|
|
||||||
|
|
||||||
// 2) fallback: constrói a partir das props antigas
|
|
||||||
return {
|
|
||||||
rotulo: props.rotulo ?? "Data e hora",
|
|
||||||
placeholder: props.placeholder ?? "",
|
|
||||||
modo: props.modo ?? "dataHora",
|
|
||||||
limpavel: props.limpavel,
|
|
||||||
erro: props.erro,
|
|
||||||
mensagensErro: props.mensagensErro,
|
|
||||||
dica: props.dica,
|
|
||||||
dicaPersistente: props.dicaPersistente,
|
|
||||||
densidade: props.densidade,
|
|
||||||
variante: props.variante,
|
|
||||||
min: props.min,
|
|
||||||
max: props.max,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const modoEfetivo = computed<"data" | "dataHora">(
|
|
||||||
() => opcoesEfetivas.value.modo ?? "dataHora",
|
|
||||||
)
|
|
||||||
|
|
||||||
const desabilitadoEfetivo = computed<boolean>(() =>
|
|
||||||
Boolean(props.desabilitado),
|
|
||||||
)
|
|
||||||
|
|
||||||
const tipoInput = computed<"date" | "datetime-local">(() =>
|
|
||||||
modoEfetivo.value === "data" ? "date" : "datetime-local",
|
|
||||||
)
|
|
||||||
|
|
||||||
function isoParaInputDatetime(valorIso: string): string {
|
|
||||||
if (modoEfetivo.value === "data") {
|
|
||||||
return dayjsbr(valorIso).format("YYYY-MM-DD")
|
|
||||||
}
|
|
||||||
return dayjsbr(valorIso).format("YYYY-MM-DDTHH:mm")
|
|
||||||
}
|
|
||||||
|
|
||||||
function inputDatetimeParaIsoLocal(valorInput: string): string {
|
|
||||||
if (modoEfetivo.value === "data") {
|
|
||||||
return dayjsbr(`${valorInput}T00:00`).format()
|
|
||||||
}
|
|
||||||
return dayjsbr(valorInput).format()
|
|
||||||
}
|
|
||||||
|
|
||||||
const effectiveModelValue = computed<string | null>(() => {
|
|
||||||
// Prioridade: value (novo) se vier definido; senão usa modelValue (antigo)
|
|
||||||
return props.value !== undefined
|
|
||||||
? (props.value ?? null)
|
|
||||||
: props.modelValue
|
|
||||||
})
|
|
||||||
|
|
||||||
const valor = computed<string>({
|
|
||||||
get: () => {
|
|
||||||
if (!effectiveModelValue.value) return ""
|
|
||||||
return isoParaInputDatetime(effectiveModelValue.value)
|
|
||||||
},
|
|
||||||
set: (v) => {
|
|
||||||
const normalizado = v && v.length > 0 ? v : null
|
|
||||||
if (!normalizado) {
|
|
||||||
emit("update:value", null)
|
|
||||||
emit("input", null)
|
|
||||||
emit("change", null)
|
|
||||||
|
|
||||||
emit("update:modelValue", null)
|
|
||||||
emit("alterar", null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const valorEmitido = inputDatetimeParaIsoLocal(normalizado)
|
|
||||||
|
|
||||||
emit("update:value", valorEmitido)
|
|
||||||
emit("input", valorEmitido)
|
|
||||||
emit("change", valorEmitido)
|
|
||||||
|
|
||||||
emit("update:modelValue", valorEmitido)
|
|
||||||
emit("alterar", valorEmitido)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const minLocal = computed<string | undefined>(() => {
|
|
||||||
const min = opcoesEfetivas.value.min
|
|
||||||
if (!min) return undefined
|
|
||||||
return isoParaInputDatetime(min)
|
|
||||||
})
|
|
||||||
|
|
||||||
const maxLocal = computed<string | undefined>(() => {
|
|
||||||
const max = opcoesEfetivas.value.max
|
|
||||||
if (!max) return undefined
|
|
||||||
return isoParaInputDatetime(max)
|
|
||||||
})
|
|
||||||
|
|
||||||
function emitCompatFocus() {
|
|
||||||
emit("foco")
|
|
||||||
emit("focus")
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitCompatBlur() {
|
|
||||||
emit("desfoco")
|
|
||||||
emit("blur")
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
attrs,
|
|
||||||
valor,
|
|
||||||
tipoInput,
|
|
||||||
minLocal,
|
|
||||||
maxLocal,
|
|
||||||
opcoesEfetivas,
|
|
||||||
desabilitadoEfetivo,
|
|
||||||
emitCompatFocus,
|
|
||||||
emitCompatBlur,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-data-hora {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,247 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-text-field
|
|
||||||
:model-value="displayValue"
|
|
||||||
:label="opcoes?.rotulo"
|
|
||||||
:placeholder="opcoes?.placeholder"
|
|
||||||
:type="isInteiro ? 'number' : 'text'"
|
|
||||||
:inputmode="isInteiro ? 'numeric' : 'decimal'"
|
|
||||||
:pattern="isInteiro ? '[0-9]*' : '[0-9.,]*'"
|
|
||||||
v-bind="attrs"
|
|
||||||
@update:model-value="onUpdateModelValue"
|
|
||||||
@focus="() => emit('focus')"
|
|
||||||
@blur="() => emit('blur')"
|
|
||||||
>
|
|
||||||
<!--
|
|
||||||
Em alguns cenários (ex.: type="number"), o prop `suffix` do Vuetify pode não aparecer.
|
|
||||||
Usamos slots para garantir exibição consistente de prefixo/sufixo.
|
|
||||||
-->
|
|
||||||
<template v-if="opcoes?.prefixo" #prepend-inner>
|
|
||||||
<span class="eli-entrada__prefixo">{{ opcoes.prefixo }}</span>
|
|
||||||
</template>
|
|
||||||
<template v-if="opcoes?.sufixo" #append-inner>
|
|
||||||
<span class="eli-entrada__sufixo">{{ opcoes.sufixo }}</span>
|
|
||||||
</template>
|
|
||||||
</v-text-field>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType, ref, watch } from "vue"
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas"
|
|
||||||
|
|
||||||
type EntradaNumero = PadroesEntradas["numero"]
|
|
||||||
|
|
||||||
function casasDecimaisFromPrecisao(precisao: number): number {
|
|
||||||
if (!Number.isFinite(precisao) || precisao <= 0) return 0
|
|
||||||
if (precisao >= 1) return 0
|
|
||||||
|
|
||||||
// Preferência por contar casas decimais na representação (ex.: 0.01 -> 2)
|
|
||||||
const texto = precisao.toString()
|
|
||||||
if (texto.includes("e-")) {
|
|
||||||
const [, exp] = texto.split("e-")
|
|
||||||
const n = Number(exp)
|
|
||||||
return Number.isFinite(n) ? n : 0
|
|
||||||
}
|
|
||||||
const idx = texto.indexOf(".")
|
|
||||||
if (idx === -1) return 0
|
|
||||||
const dec = texto.slice(idx + 1).replace(/0+$/, "")
|
|
||||||
return dec.length
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseNumero(texto: string): number | null {
|
|
||||||
const normalizado = (texto ?? "").trim().replace(/,/g, ".")
|
|
||||||
if (!normalizado) return null
|
|
||||||
const n = Number(normalizado)
|
|
||||||
if (Number.isNaN(n)) return null
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatarNumero(
|
|
||||||
value: number | null | undefined,
|
|
||||||
casas: number | null,
|
|
||||||
) {
|
|
||||||
if (value === null || value === undefined) return ""
|
|
||||||
if (casas === null) return String(value)
|
|
||||||
|
|
||||||
// Garantimos que o texto visual corresponda ao value (fixed).
|
|
||||||
const fixed = Number(value).toFixed(Math.max(0, casas))
|
|
||||||
// Exibe com vírgula (pt-BR)
|
|
||||||
return fixed.replace(/\./g, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
function somenteNumeros(texto: string) {
|
|
||||||
return (texto ?? "").replace(/\D+/g, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
function somenteNumerosESeparadorDecimal(texto: string) {
|
|
||||||
// Mantém apenas números e UM separador decimal ("," ou "."), sem sinais.
|
|
||||||
// Implementação baseada em regex + colapso de separadores.
|
|
||||||
const limpo = (texto ?? "").replace(/[^0-9.,]+/g, "")
|
|
||||||
const matchSep = limpo.match(/[.,]/)
|
|
||||||
if (!matchSep) return limpo
|
|
||||||
|
|
||||||
const sep = matchSep[0]
|
|
||||||
const idx = limpo.indexOf(sep)
|
|
||||||
const antesRaw = limpo.slice(0, idx).replace(/[.,]/g, "")
|
|
||||||
const depois = limpo.slice(idx + 1).replace(/[.,]/g, "")
|
|
||||||
|
|
||||||
// Se o usuário começa pelo separador (",4"), normalizamos para "0,4".
|
|
||||||
const antes = antesRaw.length ? antesRaw : "0"
|
|
||||||
return `${antes}${sep}${depois}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function limitarCasasDecimais(texto: string, casas: number | null) {
|
|
||||||
if (casas === null) return texto
|
|
||||||
if (casas <= 0) return texto.replace(/[.,]/g, "")
|
|
||||||
|
|
||||||
const matchSep = texto.match(/[.,]/)
|
|
||||||
if (!matchSep) return texto
|
|
||||||
const sep = matchSep[0]
|
|
||||||
const idx = texto.indexOf(sep)
|
|
||||||
|
|
||||||
const inteiro = texto.slice(0, idx)
|
|
||||||
const frac = texto.slice(idx + 1)
|
|
||||||
return `${inteiro}${sep}${frac.slice(0, casas)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function valorParcialDecimal(texto: string): number | null {
|
|
||||||
// Regra (B): se o usuário digitou "1," ou "1." emite 1.
|
|
||||||
const m = texto.match(/^(\d+)[.,]$/)
|
|
||||||
if (!m) return null
|
|
||||||
const n = Number(m[1])
|
|
||||||
return Number.isNaN(n) ? null : n
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliEntradaNumero",
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: [Number, null] as unknown as PropType<EntradaNumero["value"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
opcoes: {
|
|
||||||
type: Object as PropType<EntradaNumero["opcoes"]>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
"update:value": (_v: EntradaNumero["value"]) => true,
|
|
||||||
/** Compat Vue2 (v-model padrão: value + input) */
|
|
||||||
input: (_v: EntradaNumero["value"]) => true,
|
|
||||||
change: (_v: EntradaNumero["value"]) => true,
|
|
||||||
focus: () => true,
|
|
||||||
blur: () => true,
|
|
||||||
},
|
|
||||||
setup(props, { attrs, emit }) {
|
|
||||||
// Se `precisao` não existir => não limitamos casas (mas ainda bloqueamos caracteres inválidos).
|
|
||||||
const casasDecimais = computed<number | null>(() => {
|
|
||||||
const p = props.opcoes?.precisao
|
|
||||||
if (p === undefined || p === null) return null
|
|
||||||
return casasDecimaisFromPrecisao(p)
|
|
||||||
})
|
|
||||||
|
|
||||||
const isInteiro = computed(() => {
|
|
||||||
// quando não existe precisão, tratamos como decimal livre
|
|
||||||
return casasDecimais.value === 0
|
|
||||||
})
|
|
||||||
|
|
||||||
const isFixedPoint = computed(() => {
|
|
||||||
// Quando precisao existe e é < 1, controlamos a vírgula automaticamente.
|
|
||||||
const casas = casasDecimais.value
|
|
||||||
return casas !== null && casas > 0
|
|
||||||
})
|
|
||||||
|
|
||||||
// Controle do texto exibido: impede o campo de ficar com caracteres inválidos.
|
|
||||||
const displayValue = ref<string>("")
|
|
||||||
const ultimoEmitido = ref<EntradaNumero["value"] | undefined>(undefined)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.value,
|
|
||||||
(v) => {
|
|
||||||
// Se foi uma atualização resultante do que acabamos de emitir, não sobrescreve.
|
|
||||||
// Isso evita o efeito de "apagar" o texto ao digitar algo parcial (ex.: "1,")
|
|
||||||
// quando o valor emitido é `1` ou `null`.
|
|
||||||
if (v === ultimoEmitido.value) return
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic format
|
|
||||||
displayValue.value = formatarNumero(v as any, casasDecimais.value)
|
|
||||||
ultimoEmitido.value = v
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
function onUpdateModelValue(texto: string) {
|
|
||||||
// Modo fixed-point: usuário digita números continuamente e a vírgula é inserida automaticamente.
|
|
||||||
if (isFixedPoint.value) {
|
|
||||||
const casas = casasDecimais.value ?? 0
|
|
||||||
const digitos = somenteNumeros(texto)
|
|
||||||
// ex.: casas=2, "1" => 0.01 ; "123" => 1.23
|
|
||||||
const baseInt = digitos ? Number(digitos) : 0
|
|
||||||
const divisor = 10 ** casas
|
|
||||||
const n = digitos ? baseInt / divisor : null
|
|
||||||
|
|
||||||
const out = (n === null ? null : n) as EntradaNumero["value"]
|
|
||||||
ultimoEmitido.value = out
|
|
||||||
emit("update:value", out)
|
|
||||||
emit("input", out)
|
|
||||||
emit("change", out)
|
|
||||||
|
|
||||||
// display deve ser sempre o reflexo do value
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic format
|
|
||||||
displayValue.value = formatarNumero(out as any, casas)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Modo livre (sem precisao) ou inteiro: aceita números e 1 separador (no caso livre)
|
|
||||||
const base = isInteiro.value
|
|
||||||
? somenteNumeros(texto)
|
|
||||||
: somenteNumerosESeparadorDecimal(texto)
|
|
||||||
const textoFiltrado = isInteiro.value
|
|
||||||
? base
|
|
||||||
: limitarCasasDecimais(base, casasDecimais.value)
|
|
||||||
|
|
||||||
// Emissão:
|
|
||||||
// - vazio => null
|
|
||||||
// - decimal parcial ("1,") => 1 (regra B)
|
|
||||||
// - caso geral => parse normal
|
|
||||||
let out: EntradaNumero["value"] = null
|
|
||||||
if (textoFiltrado) {
|
|
||||||
const parcial = isInteiro.value
|
|
||||||
? null
|
|
||||||
: valorParcialDecimal(textoFiltrado)
|
|
||||||
const n = parcial ?? parseNumero(textoFiltrado)
|
|
||||||
out = (n === null ? null : n) as EntradaNumero["value"]
|
|
||||||
}
|
|
||||||
|
|
||||||
ultimoEmitido.value = out
|
|
||||||
|
|
||||||
emit("update:value", out)
|
|
||||||
emit("input", out)
|
|
||||||
emit("change", out)
|
|
||||||
|
|
||||||
// display deve sempre corresponder ao value final
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic format
|
|
||||||
displayValue.value = formatarNumero(out as any, casasDecimais.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { attrs, emit, displayValue, isInteiro, onUpdateModelValue }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-entrada__prefixo,
|
|
||||||
.eli-entrada__sufixo {
|
|
||||||
opacity: 0.75;
|
|
||||||
font-size: 0.9em;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-entrada__prefixo {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-entrada__sufixo {
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-textarea
|
|
||||||
v-model="localValue"
|
|
||||||
:label="opcoes?.rotulo"
|
|
||||||
:placeholder="opcoes?.placeholder"
|
|
||||||
:rows="opcoes?.linhas ?? 4"
|
|
||||||
:counter="opcoes?.limiteCaracteres"
|
|
||||||
:maxlength="opcoes?.limiteCaracteres"
|
|
||||||
:clearable="Boolean(opcoes?.limpavel)"
|
|
||||||
:error="Boolean(opcoes?.erro)"
|
|
||||||
:error-messages="opcoes?.mensagensErro"
|
|
||||||
:hint="opcoes?.dica"
|
|
||||||
:persistent-hint="Boolean(opcoes?.dicaPersistente)"
|
|
||||||
:density="opcoes?.densidade ?? 'comfortable'"
|
|
||||||
:variant="opcoes?.variante ?? 'outlined'"
|
|
||||||
auto-grow
|
|
||||||
v-bind="attrs"
|
|
||||||
@focus="() => emit('focus')"
|
|
||||||
@blur="() => emit('blur')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import { VTextarea } from "vuetify/components"
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas"
|
|
||||||
|
|
||||||
type EntradaParagrafo = PadroesEntradas["paragrafo"]
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliEntradaParagrafo",
|
|
||||||
components: { VTextarea },
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: [String, null] as unknown as PropType<EntradaParagrafo["value"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
opcoes: {
|
|
||||||
type: Object as PropType<EntradaParagrafo["opcoes"]>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
"update:value": (_v: EntradaParagrafo["value"]) => true,
|
|
||||||
input: (_v: EntradaParagrafo["value"]) => true,
|
|
||||||
change: (_v: EntradaParagrafo["value"]) => true,
|
|
||||||
focus: () => true,
|
|
||||||
blur: () => true,
|
|
||||||
},
|
|
||||||
setup(props, { attrs, emit }) {
|
|
||||||
const localValue = computed<EntradaParagrafo["value"]>({
|
|
||||||
get: () => props.value,
|
|
||||||
set: (v) => {
|
|
||||||
emit("update:value", v)
|
|
||||||
emit("input", v)
|
|
||||||
emit("change", v)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return { attrs, emit, localValue }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-select
|
|
||||||
v-model="localValue"
|
|
||||||
:label="opcoes?.rotulo"
|
|
||||||
:placeholder="opcoes?.placeholder"
|
|
||||||
:items="itens"
|
|
||||||
item-title="rotulo"
|
|
||||||
item-value="chave"
|
|
||||||
:loading="carregando"
|
|
||||||
:disabled="carregando"
|
|
||||||
:menu-props="{ maxHeight: 320 }"
|
|
||||||
:clearable="Boolean(opcoes?.limpavel)"
|
|
||||||
:error="Boolean(opcoes?.erro)"
|
|
||||||
:error-messages="opcoes?.mensagensErro"
|
|
||||||
:hint="opcoes?.dica"
|
|
||||||
:persistent-hint="Boolean(opcoes?.dicaPersistente)"
|
|
||||||
:density="opcoes?.densidade ?? 'comfortable'"
|
|
||||||
:variant="opcoes?.variante ?? 'outlined'"
|
|
||||||
v-bind="attrs"
|
|
||||||
@focus="() => emit('focus')"
|
|
||||||
@blur="() => emit('blur')"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import {
|
|
||||||
computed,
|
|
||||||
defineComponent,
|
|
||||||
onMounted,
|
|
||||||
type PropType,
|
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
} from "vue"
|
|
||||||
import { VSelect } from "vuetify/components"
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas"
|
|
||||||
|
|
||||||
type EntradaSelecao = PadroesEntradas["selecao"]
|
|
||||||
type ItemSelecao = { chave: string; rotulo: string }
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliEntradaSelecao",
|
|
||||||
components: { VSelect },
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
value: {
|
|
||||||
type: [String, null] as unknown as PropType<EntradaSelecao["value"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
opcoes: {
|
|
||||||
type: Object as PropType<EntradaSelecao["opcoes"]>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
"update:value": (_v: EntradaSelecao["value"]) => true,
|
|
||||||
input: (_v: EntradaSelecao["value"]) => true,
|
|
||||||
change: (_v: EntradaSelecao["value"]) => true,
|
|
||||||
focus: () => true,
|
|
||||||
blur: () => true,
|
|
||||||
},
|
|
||||||
setup(props, { attrs, emit }) {
|
|
||||||
const itens = ref<ItemSelecao[]>([])
|
|
||||||
const carregando = ref(false)
|
|
||||||
|
|
||||||
const localValue = computed<EntradaSelecao["value"]>({
|
|
||||||
get: () => props.value,
|
|
||||||
set: (v) => {
|
|
||||||
emit("update:value", v)
|
|
||||||
emit("input", v)
|
|
||||||
emit("change", v)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
async function carregarItens() {
|
|
||||||
carregando.value = true
|
|
||||||
try {
|
|
||||||
const resultado = await props.opcoes.itens()
|
|
||||||
const lista = Array.isArray(resultado) ? resultado : []
|
|
||||||
|
|
||||||
// Força reatividade mesmo quando Vuetify mantém cache interno.
|
|
||||||
// (garante que `items` mude de referência)
|
|
||||||
itens.value = [...lista]
|
|
||||||
} finally {
|
|
||||||
carregando.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recarrega quando muda a função (caso o consumidor troque dinamicamente).
|
|
||||||
watch(
|
|
||||||
() => props.opcoes.itens,
|
|
||||||
() => {
|
|
||||||
void carregarItens()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
void carregarItens()
|
|
||||||
})
|
|
||||||
|
|
||||||
// Debug (playground): ajuda a identificar se os itens chegaram.
|
|
||||||
watch(
|
|
||||||
itens,
|
|
||||||
(v) => {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.debug("[EliEntradaSelecao] itens:", v)
|
|
||||||
},
|
|
||||||
{ deep: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
return { attrs, emit, localValue, itens, carregando }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-text-field
|
|
||||||
v-model="localValue"
|
|
||||||
:type="inputHtmlType"
|
|
||||||
:inputmode="inputMode"
|
|
||||||
:label="opcoes?.rotulo"
|
|
||||||
:placeholder="opcoes?.placeholder"
|
|
||||||
:counter="opcoes?.limiteCaracteres"
|
|
||||||
:maxlength="opcoes?.limiteCaracteres"
|
|
||||||
v-bind="attrs"
|
|
||||||
@focus="() => emit('focus')"
|
|
||||||
@blur="() => emit('blur')"
|
|
||||||
@input="onInput"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import type { PadroesEntradas } from "./tiposEntradas"
|
|
||||||
import { formatarCep } from "./utils/cep"
|
|
||||||
import { formatarCpfCnpj } from "./utils/cpfCnpj"
|
|
||||||
import { formatTelefone } from "./utils/telefone"
|
|
||||||
|
|
||||||
type EntradaTexto = PadroesEntradas["texto"]
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliEntradaTexto",
|
|
||||||
inheritAttrs: false,
|
|
||||||
props: {
|
|
||||||
/** Interface padrão (EliEntrada): value + opcoes. */
|
|
||||||
value: {
|
|
||||||
type: [String, null] as unknown as PropType<EntradaTexto["value"]>,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
opcoes: {
|
|
||||||
type: Object as PropType<EntradaTexto["opcoes"]>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
"update:value": (_v: EntradaTexto["value"]) => true,
|
|
||||||
/** Compat Vue2 (v-model padrão: value + input) */
|
|
||||||
input: (_v: EntradaTexto["value"]) => true,
|
|
||||||
change: (_v: EntradaTexto["value"]) => true,
|
|
||||||
focus: () => true,
|
|
||||||
blur: () => true,
|
|
||||||
},
|
|
||||||
setup(props, { attrs, emit }) {
|
|
||||||
const formato = computed(() => props.opcoes?.formato ?? "texto")
|
|
||||||
|
|
||||||
const localValue = computed<EntradaTexto["value"]>({
|
|
||||||
get: () => props.value,
|
|
||||||
set: (v) => {
|
|
||||||
emit("update:value", v)
|
|
||||||
emit("input", v)
|
|
||||||
emit("change", v)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const inputHtmlType = computed(() => {
|
|
||||||
if (formato.value === "email") return "email"
|
|
||||||
if (formato.value === "url") return "url"
|
|
||||||
return "text"
|
|
||||||
})
|
|
||||||
|
|
||||||
const inputMode = computed<string | undefined>(() => {
|
|
||||||
if (formato.value === "telefone") return "tel"
|
|
||||||
if (formato.value === "cpfCnpj" || formato.value === "cep")
|
|
||||||
return "numeric"
|
|
||||||
return undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
function aplicarFormato(valor: string) {
|
|
||||||
switch (formato.value) {
|
|
||||||
case "telefone":
|
|
||||||
return formatTelefone(valor)
|
|
||||||
case "cpfCnpj":
|
|
||||||
return formatarCpfCnpj(valor)
|
|
||||||
case "cep":
|
|
||||||
return formatarCep(valor)
|
|
||||||
default:
|
|
||||||
return valor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onInput(e: Event) {
|
|
||||||
const target = e.target as HTMLInputElement
|
|
||||||
const resultado = aplicarFormato(target.value)
|
|
||||||
|
|
||||||
// garante que o input mostre o valor formatado
|
|
||||||
target.value = resultado
|
|
||||||
|
|
||||||
// regra do projeto: value sempre igual ao que aparece
|
|
||||||
localValue.value = resultado
|
|
||||||
}
|
|
||||||
|
|
||||||
return { attrs, emit, localValue, inputHtmlType, inputMode, onInput }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
||||||
|
|
@ -1,254 +0,0 @@
|
||||||
# EliEntrada (Padrão de Entradas)
|
|
||||||
|
|
||||||
Esta pasta define o **padrão EliEntrada**: um conjunto de componentes de entrada (inputs) com uma **API uniforme**.
|
|
||||||
|
|
||||||
> TL;DR
|
|
||||||
> - Toda entrada recebe **`value`** (estado) e **`opcoes`** (configuração).
|
|
||||||
> - O padrão de uso é **`v-model:value`**.
|
|
||||||
> - Mantemos compatibilidade com Vue 2 via evento **`input`**.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Para humanos (uso no dia-a-dia)
|
|
||||||
|
|
||||||
### Conceito
|
|
||||||
|
|
||||||
Um componente **EliEntrada** recebe **duas propriedades**:
|
|
||||||
|
|
||||||
- `value`: o valor atual do campo (entrada e saída)
|
|
||||||
- `opcoes`: um objeto que configura o componente (rótulo, placeholder e opções específicas do tipo)
|
|
||||||
|
|
||||||
Essa padronização facilita:
|
|
||||||
- gerar formulários dinamicamente
|
|
||||||
- trocar tipos de entrada com o mínimo de refactor
|
|
||||||
- documentar e tipar de forma previsível
|
|
||||||
|
|
||||||
### Tipos e contratos
|
|
||||||
|
|
||||||
Os contratos ficam em: [`tiposEntradas.ts`](./tiposEntradas.ts)
|
|
||||||
|
|
||||||
- `PadroesEntradas`: mapa de tipos suportados (ex.: `texto`, `numero`, `dataHora`)
|
|
||||||
- `TipoEntrada`: união das chaves do mapa (ex.: `"texto" | "numero" | "dataHora"`)
|
|
||||||
|
|
||||||
### Componentes disponíveis
|
|
||||||
|
|
||||||
#### 1) `EliEntradaTexto`
|
|
||||||
|
|
||||||
**Value**: `string | null | undefined`
|
|
||||||
|
|
||||||
**Opções** (além de `rotulo`/`placeholder`):
|
|
||||||
- `limiteCaracteres?: number`
|
|
||||||
|
|
||||||
Exemplo:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<template>
|
|
||||||
<EliEntradaTexto
|
|
||||||
v-model:value="nome"
|
|
||||||
:opcoes="{ rotulo: 'Nome', placeholder: 'Digite seu nome', limiteCaracteres: 50 }"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { EliEntradaTexto } from '@/index'
|
|
||||||
|
|
||||||
const nome = ref<string | null>(null)
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 2) `EliEntradaNumero`
|
|
||||||
|
|
||||||
**Value**: `number | null | undefined`
|
|
||||||
|
|
||||||
**Opções**:
|
|
||||||
- `precisao?: number`
|
|
||||||
- `1` => inteiro
|
|
||||||
- `0.1` => 1 casa decimal
|
|
||||||
- `0.01` => 2 casas decimais
|
|
||||||
- `prefixo?: string` (ex.: `"R$"`)
|
|
||||||
- `sufixo?: string` (ex.: `"kg"`)
|
|
||||||
|
|
||||||
Comportamento:
|
|
||||||
- Quando `precisao < 1` o componente entra em modo **fixed-point**: você digita números continuamente e ele insere a vírgula automaticamente.
|
|
||||||
- O que é exibido sempre corresponde ao `value` emitido.
|
|
||||||
|
|
||||||
Exemplos:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliEntradaNumero
|
|
||||||
v-model:value="quantidade"
|
|
||||||
:opcoes="{ rotulo: 'Quantidade', placeholder: 'Ex: 10', precisao: 1, sufixo: 'kg' }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EliEntradaNumero
|
|
||||||
v-model:value="preco"
|
|
||||||
:opcoes="{ rotulo: 'Preço', placeholder: 'Digite', precisao: 0.01, prefixo: 'R$' }"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 3) `EliEntradaDataHora`
|
|
||||||
|
|
||||||
**Value**: `string | null | undefined` (ISO 8601 com offset ou `Z`)
|
|
||||||
|
|
||||||
**Opções**:
|
|
||||||
- `modo?: "data" | "dataHora"` (default: `dataHora`)
|
|
||||||
- `min?: string` (ISO)
|
|
||||||
- `max?: string` (ISO)
|
|
||||||
- `limpavel?: boolean`
|
|
||||||
- `erro?: boolean`
|
|
||||||
- `mensagensErro?: string | string[]`
|
|
||||||
- `dica?: string`
|
|
||||||
- `dicaPersistente?: boolean`
|
|
||||||
- `densidade?: CampoDensidade`
|
|
||||||
- `variante?: CampoVariante`
|
|
||||||
|
|
||||||
Importante:
|
|
||||||
- O input nativo `datetime-local` não carrega timezone.
|
|
||||||
- O componente converte ISO (Z/offset) para **local** para exibir.
|
|
||||||
- Ao alterar, emite ISO 8601 com o **offset local**.
|
|
||||||
|
|
||||||
Exemplo:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliEntradaDataHora
|
|
||||||
v-model:value="agendamento"
|
|
||||||
:opcoes="{ rotulo: 'Agendar', modo: 'dataHora', min, max, limpavel: true }"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 4) `EliEntradaParagrafo`
|
|
||||||
|
|
||||||
Entrada de texto multi-linha (equivalente a um **textarea**).
|
|
||||||
|
|
||||||
**Value**: `string | null | undefined`
|
|
||||||
|
|
||||||
**Opções** (além de `rotulo`/`placeholder`):
|
|
||||||
|
|
||||||
- `linhas?: number` (default: `4`)
|
|
||||||
- `limiteCaracteres?: number`
|
|
||||||
- `limpavel?: boolean`
|
|
||||||
- `erro?: boolean`
|
|
||||||
- `mensagensErro?: string | string[]`
|
|
||||||
- `dica?: string`
|
|
||||||
- `dicaPersistente?: boolean`
|
|
||||||
- `densidade?: CampoDensidade`
|
|
||||||
- `variante?: CampoVariante`
|
|
||||||
|
|
||||||
Exemplo:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliEntradaParagrafo
|
|
||||||
v-model:value="descricao"
|
|
||||||
:opcoes="{
|
|
||||||
rotulo: 'Descrição',
|
|
||||||
placeholder: 'Digite uma descrição mais longa...',
|
|
||||||
linhas: 5,
|
|
||||||
limiteCaracteres: 300,
|
|
||||||
limpavel: true,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
#### 5) `EliEntradaSelecao`
|
|
||||||
|
|
||||||
Entrada de seleção (select) com carregamento de itens via função.
|
|
||||||
|
|
||||||
**Value**: `string | null | undefined` (chave do item selecionado)
|
|
||||||
|
|
||||||
**Opções** (além de `rotulo`/`placeholder`):
|
|
||||||
|
|
||||||
- `itens: () => {chave: string; rotulo: string}[] | Promise<{chave: string; rotulo: string}[]>`
|
|
||||||
- `limpavel?: boolean`
|
|
||||||
- `erro?: boolean`
|
|
||||||
- `mensagensErro?: string | string[]`
|
|
||||||
- `dica?: string`
|
|
||||||
- `dicaPersistente?: boolean`
|
|
||||||
- `densidade?: CampoDensidade`
|
|
||||||
- `variante?: CampoVariante`
|
|
||||||
|
|
||||||
Comportamento:
|
|
||||||
- Ao montar, o componente chama `opcoes.itens()`.
|
|
||||||
- Enquanto carrega, o select fica em `loading` e desabilitado.
|
|
||||||
|
|
||||||
Exemplo:
|
|
||||||
|
|
||||||
```vue
|
|
||||||
<EliEntradaSelecao
|
|
||||||
v-model:value="categoria"
|
|
||||||
:opcoes="{
|
|
||||||
rotulo: 'Categoria',
|
|
||||||
placeholder: 'Selecione...',
|
|
||||||
limpavel: true,
|
|
||||||
itens: async () => {
|
|
||||||
await new Promise((r) => setTimeout(r, 300));
|
|
||||||
return [
|
|
||||||
{ chave: 'a', rotulo: 'Categoria A' },
|
|
||||||
{ chave: 'b', rotulo: 'Categoria B' },
|
|
||||||
];
|
|
||||||
},
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compatibilidade Vue 2 / Vue 3
|
|
||||||
|
|
||||||
Padrão recomendado (Vue 3):
|
|
||||||
- `v-model:value`
|
|
||||||
|
|
||||||
Compat Vue 2:
|
|
||||||
- todos os EliEntradas também emitem `input`.
|
|
||||||
- isso permite consumir com o padrão `value + input` quando necessário.
|
|
||||||
|
|
||||||
### Playground
|
|
||||||
|
|
||||||
- Entradas: `src/playground/entradas.playground.vue`
|
|
||||||
- Data/hora: `src/playground/data_hora.playground.vue`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Para IA (contratos, invariantes e padrões de evolução)
|
|
||||||
|
|
||||||
### Contratos (não quebrar)
|
|
||||||
|
|
||||||
1) **Todo EliEntrada tem**:
|
|
||||||
- prop `value`
|
|
||||||
- prop `opcoes`
|
|
||||||
- evento `update:value`
|
|
||||||
|
|
||||||
2) **Compatibilidade**:
|
|
||||||
- emitir `input` (compat Vue 2) é obrigatório
|
|
||||||
|
|
||||||
3) **Tipagem**:
|
|
||||||
- `PadroesEntradas` é a fonte única do contrato (value/opcoes)
|
|
||||||
- `TipoEntrada = keyof PadroesEntradas`
|
|
||||||
|
|
||||||
4) **Sanitização/Normalização**:
|
|
||||||
- `EliEntradaNumero` deve bloquear caracteres inválidos e manter display coerente com `value`
|
|
||||||
- `EliEntradaDataHora` deve receber/emitir ISO e converter para local apenas para exibição
|
|
||||||
|
|
||||||
### Como adicionar uma nova entrada (checklist)
|
|
||||||
|
|
||||||
1) Adicionar chave em `PadroesEntradas` em `tiposEntradas.ts`
|
|
||||||
2) Criar `EliEntradaX.vue` seguindo o padrão:
|
|
||||||
- `value` + `opcoes`
|
|
||||||
- emite `update:value`, `input`, `change`
|
|
||||||
3) Exportar no `src/componentes/EliEntrada/index.ts`
|
|
||||||
4) Registrar no `src/componentes/EliEntrada/registryEliEntradas.ts`
|
|
||||||
5) Criar/atualizar playground (`src/playground/*.playground.vue`)
|
|
||||||
6) Validar `pnpm -s run build:types` e `pnpm -s run build`
|
|
||||||
|
|
||||||
### Padrões de mudança (refactors seguros)
|
|
||||||
|
|
||||||
- Se precisar mudar o contrato, faça **migração incremental**:
|
|
||||||
- manter props/eventos antigos como fallback temporário
|
|
||||||
- atualizar playground e exemplos
|
|
||||||
- rodar `build:types` para garantir geração de `.d.ts`
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import EliEntradaDataHora from "./EliEntradaDataHora.vue"
|
|
||||||
import EliEntradaNumero from "./EliEntradaNumero.vue"
|
|
||||||
import EliEntradaParagrafo from "./EliEntradaParagrafo.vue"
|
|
||||||
import EliEntradaSelecao from "./EliEntradaSelecao.vue"
|
|
||||||
import EliEntradaTexto from "./EliEntradaTexto.vue"
|
|
||||||
|
|
||||||
export {
|
|
||||||
EliEntradaTexto,
|
|
||||||
EliEntradaNumero,
|
|
||||||
EliEntradaDataHora,
|
|
||||||
EliEntradaParagrafo,
|
|
||||||
EliEntradaSelecao,
|
|
||||||
}
|
|
||||||
export type { PadroesEntradas, TipoEntrada } from "./tiposEntradas"
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import type { Component } from "vue"
|
|
||||||
import EliEntradaDataHora from "./EliEntradaDataHora.vue"
|
|
||||||
import EliEntradaNumero from "./EliEntradaNumero.vue"
|
|
||||||
import EliEntradaParagrafo from "./EliEntradaParagrafo.vue"
|
|
||||||
import EliEntradaSelecao from "./EliEntradaSelecao.vue"
|
|
||||||
import EliEntradaTexto from "./EliEntradaTexto.vue"
|
|
||||||
|
|
||||||
import type { TipoEntrada } from "./tiposEntradas"
|
|
||||||
|
|
||||||
export const registryTabelaCelulas = {
|
|
||||||
texto: EliEntradaTexto,
|
|
||||||
numero: EliEntradaNumero,
|
|
||||||
dataHora: EliEntradaDataHora,
|
|
||||||
paragrafo: EliEntradaParagrafo,
|
|
||||||
selecao: EliEntradaSelecao,
|
|
||||||
} as const satisfies Record<TipoEntrada, Component>
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipos base para componentes de entrada (EliEntrada*)
|
|
||||||
*
|
|
||||||
* Objetivo:
|
|
||||||
* - Padronizar o shape de dados de todos os componentes de entrada.
|
|
||||||
* - Cada entrada possui sempre:
|
|
||||||
* 1) `value`: o valor atual (tipado)
|
|
||||||
* 2) `opcoes`: configuração do componente (rótulo, placeholder e extras por tipo)
|
|
||||||
*
|
|
||||||
* Como usar:
|
|
||||||
* - `PadroesEntradas[tipo]` retorna a tipagem completa (value + opcoes) daquele tipo.
|
|
||||||
* - `TipoEntrada` é a união com todos os tipos suportados (ex.: "texto" | "numero").
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contrato padrão de uma entrada.
|
|
||||||
*
|
|
||||||
* @typeParam T - tipo do `value` (ex.: string | null | undefined)
|
|
||||||
* @typeParam Mais - campos adicionais dentro de `opcoes`, específicos do tipo de entrada
|
|
||||||
*/
|
|
||||||
export type tipoPadraoEntrada<T, Mais extends Record<string, unknown> = {}> = {
|
|
||||||
/** Valor atual do campo (pode aceitar null/undefined quando aplicável) */
|
|
||||||
value: T
|
|
||||||
|
|
||||||
/** Configurações do componente (visuais + regras simples do tipo) */
|
|
||||||
opcoes: {
|
|
||||||
/** Rótulo exibido ao usuário */
|
|
||||||
rotulo: string
|
|
||||||
|
|
||||||
/** Texto de ajuda dentro do input quando vazio */
|
|
||||||
placeholder?: string
|
|
||||||
} & Mais
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapa de tipos de entrada suportados e suas configurações específicas.
|
|
||||||
*
|
|
||||||
* Observação importante:
|
|
||||||
* - As chaves deste objeto (ex.: "texto", "numero") viram o tipo `TipoEntrada`.
|
|
||||||
* - Cada item define:
|
|
||||||
* - `value`: tipo do valor
|
|
||||||
* - `opcoes`: opções comuns + extras específicas
|
|
||||||
*/
|
|
||||||
export type PadroesEntradas = {
|
|
||||||
texto: tipoPadraoEntrada<
|
|
||||||
string | null | undefined,
|
|
||||||
{
|
|
||||||
/** Limite máximo de caracteres permitidos (se definido) */
|
|
||||||
limiteCaracteres?: number
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Formato/máscara aplicada ao texto.
|
|
||||||
* Obs: o `value` SEMPRE será o texto formatado (o que aparece no input).
|
|
||||||
*/
|
|
||||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
numero: tipoPadraoEntrada<
|
|
||||||
number | null | undefined,
|
|
||||||
{
|
|
||||||
/** Unidade de medida (ex.: "kg", "m³") */
|
|
||||||
sufixo?: string
|
|
||||||
|
|
||||||
/** Moéda (ex.: "R$") */
|
|
||||||
prefixo?: string
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Passo/precisão do valor numérico.
|
|
||||||
* - 1 => somente inteiros
|
|
||||||
* - 0.1 => 1 casa decimal
|
|
||||||
* - 0.01 => 2 casas decimais
|
|
||||||
*
|
|
||||||
* Dica: este conceito corresponde ao atributo HTML `step`.
|
|
||||||
*/
|
|
||||||
precisao?: number
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
dataHora: tipoPadraoEntrada<
|
|
||||||
string | null | undefined,
|
|
||||||
{
|
|
||||||
/** Define o tipo de entrada. - `dataHora`: datetime-local - `data`: date */
|
|
||||||
modo?: "data" | "dataHora"
|
|
||||||
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean
|
|
||||||
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean
|
|
||||||
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[]
|
|
||||||
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string
|
|
||||||
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean
|
|
||||||
|
|
||||||
/** Valor mínimo permitido (ISO 8601 - offset ou Z). */
|
|
||||||
min?: string
|
|
||||||
|
|
||||||
/** Valor máximo permitido (ISO 8601 - offset ou Z). */
|
|
||||||
max?: string
|
|
||||||
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade
|
|
||||||
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
paragrafo: tipoPadraoEntrada<
|
|
||||||
string | null | undefined,
|
|
||||||
{
|
|
||||||
/** Quantidade de linhas visíveis no textarea (Vuetify `rows`). */
|
|
||||||
linhas?: number
|
|
||||||
|
|
||||||
/** Limite máximo de caracteres permitidos (se definido). */
|
|
||||||
limiteCaracteres?: number
|
|
||||||
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean
|
|
||||||
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean
|
|
||||||
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[]
|
|
||||||
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string
|
|
||||||
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean
|
|
||||||
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade
|
|
||||||
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
selecao: tipoPadraoEntrada<
|
|
||||||
string | null | undefined,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Carrega os itens da seleção (sincrono ou async).
|
|
||||||
* - Cada item precisa ter uma chave estável (value) e um rótulo (title).
|
|
||||||
*/
|
|
||||||
itens: () =>
|
|
||||||
| { chave: string; rotulo: string }[]
|
|
||||||
| Promise<{ chave: string; rotulo: string }[]>
|
|
||||||
|
|
||||||
/** Se true, mostra ícone para limpar o valor (Vuetify clearable). */
|
|
||||||
limpavel?: boolean
|
|
||||||
|
|
||||||
/** Estado de erro (visual). */
|
|
||||||
erro?: boolean
|
|
||||||
|
|
||||||
/** Mensagens de erro. */
|
|
||||||
mensagensErro?: string | string[]
|
|
||||||
|
|
||||||
/** Texto de apoio. */
|
|
||||||
dica?: string
|
|
||||||
|
|
||||||
/** Mantém a dica sempre visível. */
|
|
||||||
dicaPersistente?: boolean
|
|
||||||
|
|
||||||
/** Densidade do campo (Vuetify). */
|
|
||||||
densidade?: import("../../tipos").CampoDensidade
|
|
||||||
|
|
||||||
/** Variante do v-text-field (Vuetify). */
|
|
||||||
variante?: import("../../tipos").CampoVariante
|
|
||||||
}
|
|
||||||
>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* União dos tipos de entrada suportados.
|
|
||||||
* Ex.: "texto" | "numero"
|
|
||||||
*/
|
|
||||||
export type TipoEntrada = keyof PadroesEntradas
|
|
||||||
|
|
||||||
export type PadraoComponenteEntrada<T extends TipoEntrada> = readonly [
|
|
||||||
T,
|
|
||||||
PadroesEntradas[T]["opcoes"],
|
|
||||||
]
|
|
||||||
|
|
||||||
export type ComponenteEntrada = {
|
|
||||||
[K in TipoEntrada]: PadraoComponenteEntrada<K>
|
|
||||||
}[TipoEntrada]
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
function somenteNumeros(valor: string) {
|
|
||||||
return valor.replace(/\D+/g, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Formata CEP no padrão 00000-000 */
|
|
||||||
export function formatarCep(valor: string) {
|
|
||||||
const digitos = somenteNumeros(valor)
|
|
||||||
if (!digitos) return ""
|
|
||||||
return digitos.replace(/^(\d{5})(\d)/, "$1-$2").slice(0, 9)
|
|
||||||
}
|
|
||||||
|
|
@ -1,397 +0,0 @@
|
||||||
.eli-tabela {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: separate;
|
|
||||||
border-spacing: 0;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
||||||
border-radius: 12px;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__tbody {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__tbody .eli-tabela__tr--zebra .eli-tabela__td {
|
|
||||||
background: rgba(15, 23, 42, 0.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th,
|
|
||||||
.eli-tabela__td {
|
|
||||||
padding: 10px 12px;
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th {
|
|
||||||
text-align: left;
|
|
||||||
font-weight: 600;
|
|
||||||
background: rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th--ordenavel {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th--ordenavel .eli-tabela__th-botao {
|
|
||||||
padding: 10px 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-botao {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
font: inherit;
|
|
||||||
color: inherit;
|
|
||||||
cursor: pointer;
|
|
||||||
text-align: left;
|
|
||||||
transition: color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-botao:hover,
|
|
||||||
.eli-tabela__th-botao:focus-visible {
|
|
||||||
color: rgba(15, 23, 42, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-botao:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-botao--ativo {
|
|
||||||
color: rgba(37, 99, 235, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-texto {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-icone {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th-icone--oculto {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__tr:last-child .eli-tabela__td {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__td--clicavel {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__td--clicavel:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.03);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.eli-tabela--erro {
|
|
||||||
border: 1px solid rgba(220, 53, 69, 0.35);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela--carregando {
|
|
||||||
border: 1px dashed rgba(0, 0, 0, 0.25);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 12px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__erro-titulo {
|
|
||||||
font-weight: 700;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__erro-mensagem {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela--vazio {
|
|
||||||
border: 1px dashed rgba(0, 0, 0, 0.25);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 12px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__th--acoes {
|
|
||||||
text-align: right;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__td--acoes {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-container--aberto {
|
|
||||||
z-index: 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__rodape {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 12px;
|
|
||||||
margin-top: 12px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__paginacao {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 12px;
|
|
||||||
margin-top: 0;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-inferiores {
|
|
||||||
display: inline-flex;
|
|
||||||
gap: 8px;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__cabecalho {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 12px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
/* Altura padrão para controles do cabeçalho (busca e botões)
|
|
||||||
* - Mantém alinhamento visual entre input de busca e ações
|
|
||||||
* - Pode ser sobrescrita via CSS no consumidor, se necessário
|
|
||||||
*/
|
|
||||||
--eli-tabela-cabecalho-controle-altura: 34px;
|
|
||||||
|
|
||||||
/* Borda dos controles do cabeçalho: menos "pílula", mais quadrado.
|
|
||||||
* Ajuste fino via CSS no consumidor, se necessário.
|
|
||||||
*/
|
|
||||||
--eli-tabela-cabecalho-controle-radius: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho {
|
|
||||||
display: inline-flex;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho-botao {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
height: var(--eli-tabela-cabecalho-controle-altura);
|
|
||||||
padding: 0 14px;
|
|
||||||
border-radius: var(--eli-tabela-cabecalho-controle-radius);
|
|
||||||
border: none;
|
|
||||||
background: rgba(37, 99, 235, 0.12);
|
|
||||||
color: rgba(37, 99, 235, 0.95);
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho-botao:hover,
|
|
||||||
.eli-tabela__acoes-cabecalho-botao:focus-visible {
|
|
||||||
background: rgba(37, 99, 235, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho-botao:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.35);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho-icone {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-cabecalho-rotulo {
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-toggle {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 9999px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: rgba(15, 23, 42, 0.72);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-toggle-icone {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-toggle:hover,
|
|
||||||
.eli-tabela__acoes-toggle:focus-visible {
|
|
||||||
background-color: rgba(15, 23, 42, 0.08);
|
|
||||||
color: rgba(15, 23, 42, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-toggle:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-toggle:disabled {
|
|
||||||
cursor: default;
|
|
||||||
color: rgba(148, 163, 184, 0.8);
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-menu {
|
|
||||||
min-width: 180px;
|
|
||||||
padding: 6px 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
background: #ffffff;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.18);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item-botao {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
padding: 8px 12px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item-botao:hover,
|
|
||||||
.eli-tabela__acoes-item-botao:focus-visible {
|
|
||||||
background-color: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item-botao:focus-visible {
|
|
||||||
outline: 2px solid currentColor;
|
|
||||||
outline-offset: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item-icone {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acoes-item-texto {
|
|
||||||
flex: 1;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* Expander (colunas invisíveis)
|
|
||||||
* ========================= */
|
|
||||||
|
|
||||||
.eli-tabela__th--expander,
|
|
||||||
.eli-tabela__td--expander {
|
|
||||||
width: 42px;
|
|
||||||
padding: 6px 8px;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__expander-botao {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 9999px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: rgba(15, 23, 42, 0.72);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__expander-botao:hover,
|
|
||||||
.eli-tabela__expander-botao:focus-visible {
|
|
||||||
background-color: rgba(15, 23, 42, 0.08);
|
|
||||||
color: rgba(15, 23, 42, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__expander-botao:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__expander-botao--ativo {
|
|
||||||
background-color: rgba(15, 23, 42, 0.06);
|
|
||||||
color: rgba(15, 23, 42, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__td--detalhes {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__tr--detalhes .eli-tabela__td {
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__detalhes {
|
|
||||||
display: grid;
|
|
||||||
gap: 10px;
|
|
||||||
padding-left: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__detalhe {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 180px 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__detalhe-rotulo {
|
|
||||||
font-weight: 600;
|
|
||||||
color: rgba(15, 23, 42, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__detalhe-valor {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
|
||||||
.eli-tabela__detalhe {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,889 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela">
|
|
||||||
<EliTabelaDebug :isDev="isDev" :menuAberto="menuAberto" :menuPopupPos="menuPopupPos">
|
|
||||||
<div>paginaAtual: {{ paginaAtual }}</div>
|
|
||||||
<div>limit: {{ registrosPorConsulta }}</div>
|
|
||||||
<div>texto_busca: {{ (valorBusca || '').trim() }}</div>
|
|
||||||
<div>filtrosAvancadosAtivos: {{ JSON.stringify(filtrosAvancadosAtivos) }}</div>
|
|
||||||
<div>quantidadeTotal: {{ quantidade }}</div>
|
|
||||||
</EliTabelaDebug>
|
|
||||||
|
|
||||||
<EliTabelaCabecalho
|
|
||||||
v-if="exibirBusca || temAcoesSuperiores"
|
|
||||||
:exibirBusca="exibirBusca"
|
|
||||||
:exibirBotaoFiltroAvancado="exibirFiltroAvancado"
|
|
||||||
:valorBusca="valorBusca"
|
|
||||||
:acoesCabecalho="acoesSuperiores"
|
|
||||||
:parametrosConsulta="parametrosConsultaAtuais"
|
|
||||||
@buscar="atualizarBusca"
|
|
||||||
@colunas="abrirModalColunas"
|
|
||||||
@filtroAvancado="abrirModalFiltro"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EliTabelaModalColunas
|
|
||||||
:aberto="modalColunasAberto"
|
|
||||||
:rotulosColunas="rotulosColunas"
|
|
||||||
:configInicial="configColunas"
|
|
||||||
:colunas="tabela.colunas"
|
|
||||||
@fechar="fecharModalColunas"
|
|
||||||
@salvar="salvarModalColunas"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EliTabelaModalFiltroAvancado
|
|
||||||
:aberto="modalFiltroAberto"
|
|
||||||
:filtrosBase="tabela.filtroAvancado ?? []"
|
|
||||||
:modelo="filtrosUi"
|
|
||||||
@fechar="fecharModalFiltro"
|
|
||||||
@limpar="limparFiltrosAvancados"
|
|
||||||
@salvar="salvarFiltrosAvancados"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<table class="eli-tabela__table">
|
|
||||||
<EliTabelaHead
|
|
||||||
:colunas="colunasEfetivas"
|
|
||||||
:temAcoes="temAcoes"
|
|
||||||
:temColunasInvisiveis="temColunasInvisiveis"
|
|
||||||
:colunaOrdenacao="colunaOrdenacao"
|
|
||||||
:direcaoOrdenacao="direcaoOrdenacao"
|
|
||||||
@alternar-ordenacao="alternarOrdenacao"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<tbody v-if="carregando || Boolean(erro) || !linhas.length">
|
|
||||||
<tr>
|
|
||||||
<td :colspan="totalColunas" style="padding: 0;">
|
|
||||||
<EliTabelaEstados
|
|
||||||
:carregando="carregando"
|
|
||||||
:erro="erro"
|
|
||||||
:mensagemVazio="tabela.mensagemVazio"
|
|
||||||
style="border: none; border-radius: 0;"
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
<EliTabelaBody
|
|
||||||
v-else
|
|
||||||
:colunas="colunasEfetivas"
|
|
||||||
:colunasInvisiveis="colunasInvisiveisEfetivas"
|
|
||||||
:temColunasInvisiveis="temColunasInvisiveis"
|
|
||||||
:linhasExpandidas="linhasExpandidas"
|
|
||||||
:linhas="linhasPaginadas"
|
|
||||||
:temAcoes="temAcoes"
|
|
||||||
:menuAberto="menuAberto"
|
|
||||||
:possuiAcoes="possuiAcoes"
|
|
||||||
:toggleMenu="toggleMenu"
|
|
||||||
:alternarLinhaExpandida="alternarLinhaExpandida"
|
|
||||||
/>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<EliTabelaMenuAcoes
|
|
||||||
ref="menuPopup"
|
|
||||||
:menuAberto="menuAberto"
|
|
||||||
:posicao="menuPopupPos"
|
|
||||||
:acoes="menuAberto === null ? [] : acoesDisponiveisPorLinha(menuAberto)"
|
|
||||||
:linha="menuAberto === null ? null : linhasPaginadas[menuAberto]"
|
|
||||||
@executar="({ acao, linha }) => { menuAberto = null; acao.acao(linha as never); }"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EliTabelaPaginacao
|
|
||||||
v-if="(totalPaginas > 1 && quantidadeFiltrada > 0) || temAcoesInferiores"
|
|
||||||
:pagina="paginaAtual"
|
|
||||||
:totalPaginas="totalPaginas"
|
|
||||||
:maximoBotoes="tabela.maximo_botoes_paginacao"
|
|
||||||
:acoes="acoesInferiores"
|
|
||||||
:parametrosConsulta="parametrosConsultaAtuais"
|
|
||||||
@alterar="irParaPagina"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
/**
|
|
||||||
* EliTabela
|
|
||||||
* Componente de tabela consultável com busca, paginação, ordenação e ações por linha.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Enum de códigos de resposta utilizado na consulta */
|
|
||||||
import { codigosResposta } from "p-respostas"
|
|
||||||
/** Dependências do Vue (Composition API) */
|
|
||||||
import {
|
|
||||||
computed,
|
|
||||||
defineComponent,
|
|
||||||
onBeforeUnmount,
|
|
||||||
onMounted,
|
|
||||||
type PropType,
|
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
} from "vue"
|
|
||||||
// operadores usados no tipo de configuração; o operador aplicado vem travado no filtroAvancado.
|
|
||||||
import {
|
|
||||||
carregarConfigColunas,
|
|
||||||
type EliTabelaColunasConfig,
|
|
||||||
salvarConfigColunas,
|
|
||||||
} from "./colunasStorage"
|
|
||||||
import EliTabelaBody from "./EliTabelaBody.vue"
|
|
||||||
/** Componentes auxiliares */
|
|
||||||
import EliTabelaCabecalho from "./EliTabelaCabecalho.vue"
|
|
||||||
import EliTabelaDebug from "./EliTabelaDebug.vue"
|
|
||||||
import EliTabelaEstados from "./EliTabelaEstados.vue"
|
|
||||||
import EliTabelaHead from "./EliTabelaHead.vue"
|
|
||||||
import EliTabelaMenuAcoes from "./EliTabelaMenuAcoes.vue"
|
|
||||||
import EliTabelaModalColunas from "./EliTabelaModalColunas.vue"
|
|
||||||
import EliTabelaModalFiltroAvancado from "./EliTabelaModalFiltroAvancado.vue"
|
|
||||||
import EliTabelaPaginacao from "./EliTabelaPaginacao.vue"
|
|
||||||
import {
|
|
||||||
carregarFiltroAvancado,
|
|
||||||
limparFiltroAvancado,
|
|
||||||
salvarFiltroAvancado,
|
|
||||||
} from "./filtroAvancadoStorage"
|
|
||||||
/** Tipos da configuração/contrato da tabela */
|
|
||||||
import type {
|
|
||||||
parametrosConsulta,
|
|
||||||
tipoEliColuna,
|
|
||||||
tipoEliTabelaConsulta,
|
|
||||||
tipoFiltro,
|
|
||||||
} from "./types-eli-tabela"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabela",
|
|
||||||
inheritAttrs: false,
|
|
||||||
components: {
|
|
||||||
EliTabelaCabecalho,
|
|
||||||
EliTabelaEstados,
|
|
||||||
EliTabelaDebug,
|
|
||||||
EliTabelaHead,
|
|
||||||
EliTabelaBody,
|
|
||||||
EliTabelaMenuAcoes,
|
|
||||||
EliTabelaPaginacao,
|
|
||||||
EliTabelaModalColunas,
|
|
||||||
EliTabelaModalFiltroAvancado,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
/** Configuração principal da tabela (colunas, consulta e ações) */
|
|
||||||
tabela: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic table
|
|
||||||
type: Object as PropType<tipoEliTabelaConsulta<any>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
/** Flag para habilitar elementos de debug */
|
|
||||||
const isDev = import.meta.env.DEV
|
|
||||||
/** Estados de carregamento/erro e dados retornados */
|
|
||||||
const carregando = ref(false)
|
|
||||||
const erro = ref<string | null>(null)
|
|
||||||
const linhas = ref<unknown[]>([])
|
|
||||||
const quantidade = ref<number>(0)
|
|
||||||
|
|
||||||
/** Controle de visibilidade das ações por linha */
|
|
||||||
const acoesVisiveis = ref<boolean[][]>([])
|
|
||||||
/** Estado do menu de ações (aberto, elemento e posição) */
|
|
||||||
const menuAberto = ref<number | null>(null)
|
|
||||||
// O componente EliTabelaMenuAcoes expõe `menuEl` (ref do elemento <ul>)
|
|
||||||
const menuPopup = ref<{ menuEl: { value: HTMLElement | null } } | null>(
|
|
||||||
null,
|
|
||||||
)
|
|
||||||
const menuPopupPos = ref({ top: 0, left: 0 })
|
|
||||||
|
|
||||||
/** Filtros e ordenação */
|
|
||||||
const valorBusca = ref<string>("")
|
|
||||||
const paginaAtual = ref(1)
|
|
||||||
const colunaOrdenacao = ref<string | null>(null)
|
|
||||||
const direcaoOrdenacao = ref<"asc" | "desc">("asc")
|
|
||||||
|
|
||||||
/** Filtro avançado (config + estado modal) */
|
|
||||||
const modalFiltroAberto = ref(false)
|
|
||||||
type LinhaFiltroUI = {
|
|
||||||
chave: string
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
|
||||||
valor: any
|
|
||||||
}
|
|
||||||
const filtrosUi = ref<Array<LinhaFiltroUI>>(
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic load
|
|
||||||
carregarFiltroAvancado<any>(props.tabela.nome) as any,
|
|
||||||
)
|
|
||||||
|
|
||||||
function abrirModalFiltro() {
|
|
||||||
modalFiltroAberto.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function fecharModalFiltro() {
|
|
||||||
modalFiltroAberto.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function limparFiltrosAvancados() {
|
|
||||||
filtrosUi.value = []
|
|
||||||
limparFiltroAvancado(props.tabela.nome)
|
|
||||||
modalFiltroAberto.value = false
|
|
||||||
// Se o usuário estiver usando filtro avançado, a busca deixa de ter efeito.
|
|
||||||
// Mantemos a regra combinatória (busca tem prioridade), então limpamos a busca.
|
|
||||||
valorBusca.value = ""
|
|
||||||
if (paginaAtual.value !== 1) paginaAtual.value = 1
|
|
||||||
else void carregar()
|
|
||||||
}
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic ui
|
|
||||||
function salvarFiltrosAvancados(novo: any[]) {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic ui
|
|
||||||
filtrosUi.value = (novo ?? []) as any
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic storage
|
|
||||||
salvarFiltroAvancado(props.tabela.nome, (novo ?? []) as any)
|
|
||||||
modalFiltroAberto.value = false
|
|
||||||
// Ao aplicar filtros, limpamos a busca para garantir que os filtros sejam efetivos.
|
|
||||||
// (busca tem prioridade sobre filtros)
|
|
||||||
valorBusca.value = ""
|
|
||||||
if (paginaAtual.value !== 1) paginaAtual.value = 1
|
|
||||||
else void carregar()
|
|
||||||
}
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
|
||||||
const filtrosAvancadosAtivos = computed<tipoFiltro<any>[]>(() => {
|
|
||||||
const base = props.tabela.filtroAvancado ?? []
|
|
||||||
|
|
||||||
return (
|
|
||||||
(filtrosUi.value ?? [])
|
|
||||||
.filter((f) => f && f.chave !== undefined)
|
|
||||||
.map((f) => {
|
|
||||||
const b = base.find((x) => String(x.chave) === String(f.chave))
|
|
||||||
if (!b) return null
|
|
||||||
|
|
||||||
// O filtro já vem pronto da função definida na configuração
|
|
||||||
return b.filtro(f.valor)
|
|
||||||
})
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
|
||||||
.filter(Boolean) as tipoFiltro<any>[]
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Alias reativo da prop tabela */
|
|
||||||
const tabela = computed(() => props.tabela)
|
|
||||||
|
|
||||||
/** Exibição da busca e ações do cabeçalho */
|
|
||||||
const exibirBusca = computed(() =>
|
|
||||||
Boolean(props.tabela.mostrarCaixaDeBusca),
|
|
||||||
)
|
|
||||||
const acoesSuperiores = computed(() =>
|
|
||||||
(props.tabela.acoesTabela ?? []).filter((a) => a.posicao === "superior"),
|
|
||||||
)
|
|
||||||
const acoesInferiores = computed(() =>
|
|
||||||
(props.tabela.acoesTabela ?? []).filter((a) => a.posicao === "inferior"),
|
|
||||||
)
|
|
||||||
const temAcoesSuperiores = computed(() => acoesSuperiores.value.length > 0)
|
|
||||||
const temAcoesInferiores = computed(() => acoesInferiores.value.length > 0)
|
|
||||||
|
|
||||||
const parametrosConsultaAtuais = computed(() => {
|
|
||||||
const limite = Math.max(1, registrosPorConsulta.value)
|
|
||||||
const offset = (paginaAtual.value - 1) * limite
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic params
|
|
||||||
const params: parametrosConsulta<any> = {
|
|
||||||
offSet: offset,
|
|
||||||
limit: limite,
|
|
||||||
}
|
|
||||||
|
|
||||||
const busca = (valorBusca.value ?? "").trim()
|
|
||||||
if (busca) {
|
|
||||||
params.texto_busca = busca
|
|
||||||
} else {
|
|
||||||
const filtros = filtrosAvancadosAtivos.value
|
|
||||||
if (filtros.length) params.filtros = filtros
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colunaOrdenacao.value) {
|
|
||||||
params.coluna_ordem = colunaOrdenacao.value
|
|
||||||
params.direcao_ordem = direcaoOrdenacao.value
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...params,
|
|
||||||
atualizarConsulta: async () => {
|
|
||||||
await carregar()
|
|
||||||
},
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic list update
|
|
||||||
editarLista: async (novaLista: any[]) => {
|
|
||||||
linhas.value = novaLista
|
|
||||||
return novaLista
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Colunas: visibilidade/ordem com persistência */
|
|
||||||
const modalColunasAberto = ref(false)
|
|
||||||
const configColunas = ref<EliTabelaColunasConfig>(
|
|
||||||
carregarConfigColunas(props.tabela.nome),
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Linhas expandidas (para exibir colunas invisíveis) */
|
|
||||||
const linhasExpandidas = ref<Record<number, boolean>>({})
|
|
||||||
|
|
||||||
const rotulosColunas = computed(() =>
|
|
||||||
props.tabela.colunas.map((c) => c.rotulo),
|
|
||||||
)
|
|
||||||
|
|
||||||
const colunasInvisiveisEfetivas = computed(() => {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
const colunas = props.tabela.colunas as Array<tipoEliColuna<any>>
|
|
||||||
|
|
||||||
const configTemDados =
|
|
||||||
(configColunas.value.visiveis?.length ?? 0) > 0 ||
|
|
||||||
(configColunas.value.invisiveis?.length ?? 0) > 0
|
|
||||||
|
|
||||||
const invisiveisBaseRotulos = configTemDados
|
|
||||||
? (configColunas.value.invisiveis ?? [])
|
|
||||||
: colunas.filter((c) => c.visivel === false).map((c) => c.rotulo)
|
|
||||||
|
|
||||||
const invisiveisSet = new Set(invisiveisBaseRotulos)
|
|
||||||
const base = colunas.filter((c) => invisiveisSet.has(c.rotulo))
|
|
||||||
|
|
||||||
// ordenação: usa a lista (salva ou derivada do default) e adiciona novas ao final
|
|
||||||
const ordemSalva = invisiveisBaseRotulos
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic map
|
|
||||||
const mapa = new Map<string, tipoEliColuna<any>>()
|
|
||||||
for (const c of base) {
|
|
||||||
if (!mapa.has(c.rotulo)) mapa.set(c.rotulo, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
const ordenadas: Array<tipoEliColuna<any>> = []
|
|
||||||
for (const r of ordemSalva) {
|
|
||||||
const c = mapa.get(r)
|
|
||||||
if (c) ordenadas.push(c)
|
|
||||||
}
|
|
||||||
for (const c of base) {
|
|
||||||
if (!ordenadas.includes(c)) ordenadas.push(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ordenadas
|
|
||||||
})
|
|
||||||
|
|
||||||
const temColunasInvisiveis = computed(
|
|
||||||
() => colunasInvisiveisEfetivas.value.length > 0,
|
|
||||||
)
|
|
||||||
|
|
||||||
const colunasEfetivas = computed(() => {
|
|
||||||
const colunas = props.tabela.colunas
|
|
||||||
const todosRotulos = rotulosColunas.value
|
|
||||||
|
|
||||||
const configTemDados =
|
|
||||||
(configColunas.value.visiveis?.length ?? 0) > 0 ||
|
|
||||||
(configColunas.value.invisiveis?.length ?? 0) > 0
|
|
||||||
|
|
||||||
const invisiveisBaseRotulos = configTemDados
|
|
||||||
? (configColunas.value.invisiveis ?? [])
|
|
||||||
: // biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
(props.tabela.colunas as Array<tipoEliColuna<any>>)
|
|
||||||
.filter((c) => c.visivel === false)
|
|
||||||
.map((c) => c.rotulo)
|
|
||||||
|
|
||||||
const invisiveisSet = new Set(invisiveisBaseRotulos)
|
|
||||||
|
|
||||||
// base visiveis: remove invisiveis
|
|
||||||
const visiveisBaseRotulos = todosRotulos.filter(
|
|
||||||
(r) => !invisiveisSet.has(r),
|
|
||||||
)
|
|
||||||
const visiveisSet = new Set(visiveisBaseRotulos)
|
|
||||||
|
|
||||||
// aplica ordem salva; novas (sem definicao) entram no fim, respeitando ordem original
|
|
||||||
const ordemSalva = configTemDados
|
|
||||||
? (configColunas.value.visiveis ?? [])
|
|
||||||
: []
|
|
||||||
const ordemFinal: string[] = []
|
|
||||||
|
|
||||||
for (const r of ordemSalva) {
|
|
||||||
if (visiveisSet.has(r)) ordemFinal.push(r)
|
|
||||||
}
|
|
||||||
for (const r of visiveisBaseRotulos) {
|
|
||||||
if (!ordemFinal.includes(r)) ordemFinal.push(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mapeia rótulo -> coluna, preservando duplicatas (se existirem) pelo primeiro match.
|
|
||||||
// OBS: pressupoe rotulo unico; se repetir, comportamento fica indefinido.
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic map
|
|
||||||
const mapa = new Map<string, any>()
|
|
||||||
for (const c of colunas) {
|
|
||||||
if (!mapa.has(c.rotulo)) mapa.set(c.rotulo, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ordemFinal.map((r) => mapa.get(r)).filter(Boolean)
|
|
||||||
})
|
|
||||||
|
|
||||||
const totalColunas = computed(() => {
|
|
||||||
return (
|
|
||||||
colunasEfetivas.value.length +
|
|
||||||
(temAcoes.value ? 1 : 0) +
|
|
||||||
(temColunasInvisiveis.value ? 1 : 0)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
function abrirModalColunas() {
|
|
||||||
modalColunasAberto.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function fecharModalColunas() {
|
|
||||||
modalColunasAberto.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function salvarModalColunas(cfg: EliTabelaColunasConfig) {
|
|
||||||
configColunas.value = cfg
|
|
||||||
salvarConfigColunas(props.tabela.nome, cfg)
|
|
||||||
modalColunasAberto.value = false
|
|
||||||
|
|
||||||
// ao mudar colunas, fecha detalhes expandidos
|
|
||||||
linhasExpandidas.value = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function alternarLinhaExpandida(indice: number) {
|
|
||||||
const atual = Boolean(linhasExpandidas.value[indice])
|
|
||||||
linhasExpandidas.value = {
|
|
||||||
...linhasExpandidas.value,
|
|
||||||
[indice]: !atual,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Registros por consulta (normaliza para inteiro positivo) */
|
|
||||||
const registrosPorConsulta = computed(() => {
|
|
||||||
const valor = props.tabela.registros_por_consulta
|
|
||||||
if (typeof valor === "number" && valor > 0) {
|
|
||||||
return Math.floor(valor)
|
|
||||||
}
|
|
||||||
return 10
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Total de páginas calculado com base no total retornado pela API */
|
|
||||||
const totalPaginas = computed(() => {
|
|
||||||
const limite = registrosPorConsulta.value
|
|
||||||
if (!limite || limite <= 0) return 1
|
|
||||||
const total = quantidade.value ?? 0
|
|
||||||
if (!total) return 1
|
|
||||||
return Math.max(1, Math.ceil(total / limite))
|
|
||||||
})
|
|
||||||
|
|
||||||
/** As linhas já vêm paginadas do backend */
|
|
||||||
const linhasPaginadas = computed(() => linhas.value ?? [])
|
|
||||||
|
|
||||||
/** Quantidade exibida é a quantidade total retornada pela consulta */
|
|
||||||
const quantidadeFiltrada = computed(() => quantidade.value ?? 0)
|
|
||||||
|
|
||||||
/** Indica se existem ações por linha */
|
|
||||||
const temAcoes = computed(() => (props.tabela.acoesLinha ?? []).length > 0)
|
|
||||||
|
|
||||||
const exibirFiltroAvancado = computed(
|
|
||||||
() => (props.tabela.filtroAvancado ?? []).length > 0,
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Sequencial para evitar race conditions entre consultas */
|
|
||||||
let carregamentoSequencial = 0
|
|
||||||
|
|
||||||
/** Calcula a posição do menu de ações na viewport */
|
|
||||||
function atualizarPosicaoMenu(anchor: HTMLElement) {
|
|
||||||
const rect = anchor.getBoundingClientRect()
|
|
||||||
const gap = 8
|
|
||||||
|
|
||||||
// Alinha no canto inferior direito do botão.
|
|
||||||
// Se estourar a tela para baixo, abre para cima.
|
|
||||||
const alturaMenu = menuPopup.value?.menuEl?.value?.offsetHeight ?? 0
|
|
||||||
const larguraMenu = menuPopup.value?.menuEl?.value?.offsetWidth ?? 180
|
|
||||||
|
|
||||||
let top = rect.bottom + gap
|
|
||||||
const left = rect.right - larguraMenu
|
|
||||||
|
|
||||||
if (alturaMenu && top + alturaMenu > window.innerHeight - gap) {
|
|
||||||
top = rect.top - gap - alturaMenu
|
|
||||||
}
|
|
||||||
|
|
||||||
menuPopupPos.value = {
|
|
||||||
top: Math.max(gap, Math.round(top)),
|
|
||||||
left: Math.max(gap, Math.round(left)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Fecha o menu quando ocorre clique fora */
|
|
||||||
function handleClickFora(evento: MouseEvent) {
|
|
||||||
if (menuAberto.value === null) return
|
|
||||||
|
|
||||||
const alvo = evento.target as Node
|
|
||||||
if (menuPopup.value?.menuEl?.value?.contains(alvo)) return
|
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("[EliTabela] click fora => fechar menu", {
|
|
||||||
menuAberto: menuAberto.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
menuAberto.value = null
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Alterna ordenação e recarrega os dados */
|
|
||||||
function alternarOrdenacao(chave?: string) {
|
|
||||||
if (!chave) return
|
|
||||||
|
|
||||||
if (colunaOrdenacao.value === chave) {
|
|
||||||
direcaoOrdenacao.value =
|
|
||||||
direcaoOrdenacao.value === "asc" ? "desc" : "asc"
|
|
||||||
void carregar()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
colunaOrdenacao.value = chave
|
|
||||||
direcaoOrdenacao.value = "asc"
|
|
||||||
if (paginaAtual.value !== 1) {
|
|
||||||
paginaAtual.value = 1
|
|
||||||
} else {
|
|
||||||
void carregar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Atualiza a busca e reinicia paginação, se necessário */
|
|
||||||
function atualizarBusca(texto: string) {
|
|
||||||
if (valorBusca.value === texto) return
|
|
||||||
|
|
||||||
valorBusca.value = texto
|
|
||||||
if (paginaAtual.value !== 1) {
|
|
||||||
paginaAtual.value = 1
|
|
||||||
} else {
|
|
||||||
void carregar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Navega para a página solicitada com limites */
|
|
||||||
function irParaPagina(pagina: number) {
|
|
||||||
const alvo = Math.min(Math.max(1, pagina), totalPaginas.value)
|
|
||||||
if (alvo !== paginaAtual.value) {
|
|
||||||
paginaAtual.value = alvo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lista ações visíveis por linha, respeitando regras sync/async de `exibir`.
|
|
||||||
*/
|
|
||||||
function acoesDisponiveisPorLinha(i: number) {
|
|
||||||
const acoesLinha = props.tabela.acoesLinha ?? []
|
|
||||||
const visibilidade = acoesVisiveis.value[i] ?? []
|
|
||||||
|
|
||||||
return acoesLinha
|
|
||||||
.map((acao, indice) => {
|
|
||||||
const fallbackVisivel =
|
|
||||||
acao.exibir === undefined
|
|
||||||
? true
|
|
||||||
: typeof acao.exibir === "boolean"
|
|
||||||
? acao.exibir
|
|
||||||
: false
|
|
||||||
|
|
||||||
return {
|
|
||||||
acao,
|
|
||||||
indice,
|
|
||||||
visivel: visibilidade[indice] ?? fallbackVisivel,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter((item) => item.visivel)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Informa se a linha possui ações disponíveis */
|
|
||||||
function possuiAcoes(i: number) {
|
|
||||||
return acoesDisponiveisPorLinha(i).length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Abre/fecha o menu de ações da linha e posiciona o popup */
|
|
||||||
function toggleMenu(i: number, evento?: MouseEvent) {
|
|
||||||
if (!possuiAcoes(i)) return
|
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("[EliTabela] toggleMenu (antes)", {
|
|
||||||
i,
|
|
||||||
atual: menuAberto.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (menuAberto.value === i) {
|
|
||||||
menuAberto.value = null
|
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("[EliTabela] toggleMenu => fechou", { i })
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
menuAberto.value = i
|
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("[EliTabela] toggleMenu => abriu", { i })
|
|
||||||
}
|
|
||||||
|
|
||||||
// posiciona assim que abrir
|
|
||||||
const anchor = (evento?.currentTarget as HTMLElement | null) ?? null
|
|
||||||
if (anchor) {
|
|
||||||
// primeiro posicionamento (antes do menu medir)
|
|
||||||
atualizarPosicaoMenu(anchor)
|
|
||||||
// reposiciona no próximo frame para pegar altura real
|
|
||||||
requestAnimationFrame(() => atualizarPosicaoMenu(anchor))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executa consulta, aplica filtros e resolve visibilidade de ações.
|
|
||||||
* Usa o contador sequencial para ignorar respostas antigas.
|
|
||||||
*/
|
|
||||||
async function carregar() {
|
|
||||||
const idCarregamento = ++carregamentoSequencial
|
|
||||||
carregando.value = true
|
|
||||||
erro.value = null
|
|
||||||
acoesVisiveis.value = []
|
|
||||||
menuAberto.value = null
|
|
||||||
linhasExpandidas.value = {}
|
|
||||||
|
|
||||||
const limite = Math.max(1, registrosPorConsulta.value)
|
|
||||||
const offset = (paginaAtual.value - 1) * limite
|
|
||||||
|
|
||||||
const parametrosConsulta: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: generic
|
|
||||||
filtros?: tipoFiltro<any>[]
|
|
||||||
coluna_ordem?: never
|
|
||||||
direcao_ordem?: "asc" | "desc"
|
|
||||||
offSet: number
|
|
||||||
limit: number
|
|
||||||
texto_busca?: string
|
|
||||||
} = {
|
|
||||||
offSet: offset,
|
|
||||||
limit: limite,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regra combinatória definida: busca tem prioridade.
|
|
||||||
const busca = (valorBusca.value ?? "").trim()
|
|
||||||
if (busca) {
|
|
||||||
parametrosConsulta.texto_busca = busca
|
|
||||||
} else {
|
|
||||||
const filtros = filtrosAvancadosAtivos.value
|
|
||||||
if (filtros.length) parametrosConsulta.filtros = filtros
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colunaOrdenacao.value) {
|
|
||||||
parametrosConsulta.coluna_ordem = colunaOrdenacao.value as never
|
|
||||||
parametrosConsulta.direcao_ordem = direcaoOrdenacao.value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("[EliTabela] consulta(parametros)", parametrosConsulta)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const tabelaConfig = props.tabela
|
|
||||||
const res = await tabelaConfig.consulta(parametrosConsulta)
|
|
||||||
|
|
||||||
if (idCarregamento !== carregamentoSequencial) return
|
|
||||||
|
|
||||||
if (res.cod !== codigosResposta.sucesso) {
|
|
||||||
linhas.value = []
|
|
||||||
quantidade.value = 0
|
|
||||||
erro.value = res.mensagem
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const valores = res.valor?.valores ?? []
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic response
|
|
||||||
const total = (res.valor as any)?.quantidade ?? valores.length
|
|
||||||
|
|
||||||
linhas.value = valores
|
|
||||||
quantidade.value = Number(total) || 0
|
|
||||||
|
|
||||||
const totalPaginasRecalculado = Math.max(
|
|
||||||
1,
|
|
||||||
Math.ceil((quantidade.value || 0) / limite),
|
|
||||||
)
|
|
||||||
if (paginaAtual.value > totalPaginasRecalculado)
|
|
||||||
paginaAtual.value = totalPaginasRecalculado
|
|
||||||
|
|
||||||
const acoesLinhaConfiguradas = tabelaConfig.acoesLinha ?? []
|
|
||||||
if (!acoesLinhaConfiguradas.length) {
|
|
||||||
acoesVisiveis.value = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const preResultado = valores.map(() =>
|
|
||||||
acoesLinhaConfiguradas.map((acao) => {
|
|
||||||
if (acao.exibir === undefined) return true
|
|
||||||
if (typeof acao.exibir === "boolean") return acao.exibir
|
|
||||||
return false
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
acoesVisiveis.value = preResultado
|
|
||||||
|
|
||||||
const visibilidade = await Promise.all(
|
|
||||||
valores.map(async (linha) =>
|
|
||||||
Promise.all(
|
|
||||||
acoesLinhaConfiguradas.map(async (acao) => {
|
|
||||||
if (acao.exibir === undefined) return true
|
|
||||||
if (typeof acao.exibir === "boolean") return acao.exibir
|
|
||||||
|
|
||||||
try {
|
|
||||||
const resultado = acao.exibir(linha as never)
|
|
||||||
return Boolean(await Promise.resolve(resultado))
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (idCarregamento === carregamentoSequencial) {
|
|
||||||
acoesVisiveis.value = visibilidade
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (idCarregamento !== carregamentoSequencial) return
|
|
||||||
|
|
||||||
linhas.value = []
|
|
||||||
quantidade.value = 0
|
|
||||||
erro.value = e instanceof Error ? e.message : "Erro ao carregar dados."
|
|
||||||
} finally {
|
|
||||||
if (idCarregamento === carregamentoSequencial) {
|
|
||||||
carregando.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Ciclo de vida: registra listener global e carrega dados iniciais */
|
|
||||||
onMounted(() => {
|
|
||||||
document.addEventListener("click", handleClickFora)
|
|
||||||
void carregar()
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Ciclo de vida: remove listener global */
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
document.removeEventListener("click", handleClickFora)
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Watch: ao desabilitar busca, limpa termo e recarrega */
|
|
||||||
watch(
|
|
||||||
() => props.tabela.mostrarCaixaDeBusca,
|
|
||||||
(mostrar) => {
|
|
||||||
if (!mostrar && valorBusca.value) {
|
|
||||||
valorBusca.value = ""
|
|
||||||
if (paginaAtual.value !== 1) {
|
|
||||||
paginaAtual.value = 1
|
|
||||||
} else {
|
|
||||||
void carregar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Watch: mudança de página dispara nova consulta */
|
|
||||||
watch(paginaAtual, (nova, antiga) => {
|
|
||||||
if (nova !== antiga) void carregar()
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Watch: troca de configuração reseta estados e recarrega */
|
|
||||||
watch(
|
|
||||||
() => props.tabela,
|
|
||||||
() => {
|
|
||||||
menuAberto.value = null
|
|
||||||
colunaOrdenacao.value = null
|
|
||||||
direcaoOrdenacao.value = "asc"
|
|
||||||
valorBusca.value = ""
|
|
||||||
modalColunasAberto.value = false
|
|
||||||
modalFiltroAberto.value = false
|
|
||||||
configColunas.value = carregarConfigColunas(props.tabela.nome)
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic reload
|
|
||||||
filtrosUi.value = carregarFiltroAvancado<any>(props.tabela.nome) as any
|
|
||||||
linhasExpandidas.value = {}
|
|
||||||
if (paginaAtual.value !== 1) {
|
|
||||||
paginaAtual.value = 1
|
|
||||||
} else {
|
|
||||||
void carregar()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Watch: alteração do limite de registros reinicia paginação */
|
|
||||||
watch(
|
|
||||||
() => props.tabela.registros_por_consulta,
|
|
||||||
() => {
|
|
||||||
if (paginaAtual.value !== 1) {
|
|
||||||
paginaAtual.value = 1
|
|
||||||
} else {
|
|
||||||
void carregar()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
/** Watch: mudança nas linhas fecha o menu aberto */
|
|
||||||
watch(linhas, () => {
|
|
||||||
menuAberto.value = null
|
|
||||||
linhasExpandidas.value = {}
|
|
||||||
})
|
|
||||||
|
|
||||||
/** Exposição para o template (state, computed, helpers e actions) */
|
|
||||||
return {
|
|
||||||
// state
|
|
||||||
isDev,
|
|
||||||
tabela,
|
|
||||||
carregando,
|
|
||||||
erro,
|
|
||||||
linhas,
|
|
||||||
linhasPaginadas,
|
|
||||||
filtrosAvancadosAtivos,
|
|
||||||
quantidadeFiltrada,
|
|
||||||
quantidade,
|
|
||||||
menuAberto,
|
|
||||||
valorBusca,
|
|
||||||
paginaAtual,
|
|
||||||
colunaOrdenacao,
|
|
||||||
direcaoOrdenacao,
|
|
||||||
totalPaginas,
|
|
||||||
registrosPorConsulta,
|
|
||||||
|
|
||||||
// computed
|
|
||||||
exibirBusca,
|
|
||||||
exibirFiltroAvancado,
|
|
||||||
acoesSuperiores,
|
|
||||||
temAcoesSuperiores,
|
|
||||||
acoesInferiores,
|
|
||||||
temAcoesInferiores,
|
|
||||||
parametrosConsultaAtuais,
|
|
||||||
temAcoes,
|
|
||||||
totalColunas,
|
|
||||||
colunasEfetivas,
|
|
||||||
rotulosColunas,
|
|
||||||
modalColunasAberto,
|
|
||||||
configColunas,
|
|
||||||
|
|
||||||
temColunasInvisiveis,
|
|
||||||
colunasInvisiveisEfetivas,
|
|
||||||
linhasExpandidas,
|
|
||||||
|
|
||||||
abrirModalColunas,
|
|
||||||
abrirModalFiltro,
|
|
||||||
fecharModalColunas,
|
|
||||||
salvarModalColunas,
|
|
||||||
|
|
||||||
modalFiltroAberto,
|
|
||||||
filtrosUi,
|
|
||||||
salvarFiltrosAvancados,
|
|
||||||
limparFiltrosAvancados,
|
|
||||||
fecharModalFiltro,
|
|
||||||
|
|
||||||
alternarLinhaExpandida,
|
|
||||||
|
|
||||||
// actions
|
|
||||||
alternarOrdenacao,
|
|
||||||
atualizarBusca,
|
|
||||||
irParaPagina,
|
|
||||||
acoesDisponiveisPorLinha,
|
|
||||||
possuiAcoes,
|
|
||||||
toggleMenu,
|
|
||||||
|
|
||||||
// popup
|
|
||||||
menuPopup,
|
|
||||||
menuPopupPos,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style src="./EliTabela.css"></style>
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
<template>
|
|
||||||
<tbody class="eli-tabela__tbody">
|
|
||||||
<template v-for="(linha, i) in linhas" :key="`grp-${i}`">
|
|
||||||
<tr
|
|
||||||
class="eli-tabela__tr"
|
|
||||||
:class="[i % 2 === 1 ? 'eli-tabela__tr--zebra' : undefined]"
|
|
||||||
>
|
|
||||||
<td v-if="temColunasInvisiveis" class="eli-tabela__td eli-tabela__td--expander" :key="`td-${i}-exp`">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__expander-botao"
|
|
||||||
:class="[linhasExpandidas?.[i] ? 'eli-tabela__expander-botao--ativo' : undefined]"
|
|
||||||
:aria-expanded="linhasExpandidas?.[i] ? 'true' : 'false'"
|
|
||||||
:aria-label="linhasExpandidas?.[i] ? 'Ocultar colunas ocultas' : 'Mostrar colunas ocultas'"
|
|
||||||
:title="linhasExpandidas?.[i] ? 'Ocultar detalhes' : 'Mostrar detalhes'"
|
|
||||||
@click.stop="alternarLinhaExpandida(i)"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="linhasExpandidas?.[i] ? ChevronDown : ChevronRight"
|
|
||||||
class="eli-tabela__expander-icone"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td
|
|
||||||
v-for="(coluna, j) in colunas"
|
|
||||||
:key="`td-${i}-${j}`"
|
|
||||||
class="eli-tabela__td"
|
|
||||||
>
|
|
||||||
<EliTabelaCelula :celula="(coluna.celula(linha as never) as never)" />
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td v-if="temAcoes" class="eli-tabela__td eli-tabela__td--acoes" :key="`td-${i}-acoes`">
|
|
||||||
<div
|
|
||||||
class="eli-tabela__acoes-container"
|
|
||||||
:class="[menuAberto === i ? 'eli-tabela__acoes-container--aberto' : undefined]"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="eli-tabela__acoes-toggle"
|
|
||||||
type="button"
|
|
||||||
:id="`eli-tabela-acoes-toggle-${i}`"
|
|
||||||
:disabled="!possuiAcoes(i)"
|
|
||||||
:aria-haspopup="'menu'"
|
|
||||||
:aria-expanded="menuAberto === i ? 'true' : 'false'"
|
|
||||||
:aria-controls="possuiAcoes(i) ? `eli-tabela-acoes-menu-${i}` : undefined"
|
|
||||||
:aria-label="possuiAcoes(i) ? 'Ações da linha' : 'Nenhuma ação disponível'"
|
|
||||||
:title="possuiAcoes(i) ? 'Ações' : 'Nenhuma ação disponível'"
|
|
||||||
@click.stop="toggleMenu(i, $event)"
|
|
||||||
>
|
|
||||||
<MoreVertical class="eli-tabela__acoes-toggle-icone" :size="18" :stroke-width="2" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr
|
|
||||||
v-if="temColunasInvisiveis && Boolean(linhasExpandidas?.[i])"
|
|
||||||
class="eli-tabela__tr eli-tabela__tr--detalhes"
|
|
||||||
:class="[i % 2 === 1 ? 'eli-tabela__tr--zebra' : undefined]"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="eli-tabela__td eli-tabela__td--detalhes"
|
|
||||||
:colspan="(temColunasInvisiveis ? 1 : 0) + colunas.length + (temAcoes ? 1 : 0)"
|
|
||||||
>
|
|
||||||
<EliTabelaDetalhesLinha :linha="linha" :colunasInvisiveis="colunasInvisiveis" />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
|
||||||
</tbody>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ChevronDown, ChevronRight, MoreVertical } from "lucide-vue-next"
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import EliTabelaCelula from "./celulas/EliTabelaCelula.vue"
|
|
||||||
import EliTabelaDetalhesLinha from "./EliTabelaDetalhesLinha.vue"
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaBody",
|
|
||||||
components: {
|
|
||||||
EliTabelaCelula,
|
|
||||||
EliTabelaDetalhesLinha,
|
|
||||||
MoreVertical,
|
|
||||||
ChevronRight,
|
|
||||||
ChevronDown,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
colunas: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
type: Array as PropType<Array<tipoEliColuna<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
colunasInvisiveis: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
type: Array as PropType<Array<tipoEliColuna<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
linhasExpandidas: {
|
|
||||||
type: Object as PropType<Record<number, boolean>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
linhas: {
|
|
||||||
type: Array as PropType<Array<unknown>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
temAcoes: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
menuAberto: {
|
|
||||||
type: Number as PropType<number | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
possuiAcoes: {
|
|
||||||
type: Function as PropType<(i: number) => boolean>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
toggleMenu: {
|
|
||||||
type: Function as PropType<(indice: number, evento: MouseEvent) => void>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
alternarLinhaExpandida: {
|
|
||||||
type: Function as PropType<(indice: number) => void>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup() {
|
|
||||||
return {
|
|
||||||
ChevronRight,
|
|
||||||
ChevronDown,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela__cabecalho">
|
|
||||||
<!-- Grupo de busca: botão de colunas (à esquerda) + input de busca -->
|
|
||||||
<div v-if="exibirBusca" class="eli-tabela__busca-grupo">
|
|
||||||
<button
|
|
||||||
v-if="exibirBotaoColunas"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__acoes-cabecalho-botao eli-tabela__acoes-cabecalho-botao--colunas"
|
|
||||||
@click="emitColunas"
|
|
||||||
>
|
|
||||||
Colunas
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-if="exibirBotaoFiltroAvancado"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__acoes-cabecalho-botao eli-tabela__acoes-cabecalho-botao--filtro"
|
|
||||||
@click="emitFiltroAvancado"
|
|
||||||
>
|
|
||||||
Filtro
|
|
||||||
</button>
|
|
||||||
<EliTabelaCaixaDeBusca :modelo="valorBusca" @buscar="emitBuscar" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Ações do cabeçalho: ações globais da tabela -->
|
|
||||||
<div v-if="temAcoesCabecalho" class="eli-tabela__acoes-cabecalho">
|
|
||||||
<button
|
|
||||||
v-for="(botao, indice) in acoesCabecalho"
|
|
||||||
:key="`${botao.rotulo}-${indice}`"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__acoes-cabecalho-botao"
|
|
||||||
:style="botao.cor ? { backgroundColor: botao.cor, color: '#fff' } : undefined"
|
|
||||||
@click="botao.acao(parametrosConsulta)"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
v-if="botao.icone"
|
|
||||||
:is="botao.icone"
|
|
||||||
class="eli-tabela__acoes-cabecalho-icone"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
/>
|
|
||||||
<span class="eli-tabela__acoes-cabecalho-rotulo">{{ botao.rotulo }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import EliTabelaCaixaDeBusca from "./EliTabelaCaixaDeBusca.vue"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCabecalho",
|
|
||||||
components: { EliTabelaCaixaDeBusca },
|
|
||||||
props: {
|
|
||||||
exibirBusca: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
exibirBotaoColunas: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
exibirBotaoFiltroAvancado: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
valorBusca: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
parametrosConsulta: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic params
|
|
||||||
type: Object as PropType<any>,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
acoesCabecalho: {
|
|
||||||
type: Array as PropType<
|
|
||||||
Array<{
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic icon
|
|
||||||
icone?: any
|
|
||||||
cor?: string
|
|
||||||
rotulo: string
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic action
|
|
||||||
acao: (params?: any) => void
|
|
||||||
}>
|
|
||||||
>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
buscar(valor: string) {
|
|
||||||
return typeof valor === "string"
|
|
||||||
},
|
|
||||||
colunas() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
filtroAvancado() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const temAcoesCabecalho = computed(() => props.acoesCabecalho.length > 0)
|
|
||||||
|
|
||||||
function emitBuscar(texto: string) {
|
|
||||||
emit("buscar", texto)
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitColunas() {
|
|
||||||
emit("colunas")
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitFiltroAvancado() {
|
|
||||||
emit("filtroAvancado")
|
|
||||||
}
|
|
||||||
|
|
||||||
return { temAcoesCabecalho, emitBuscar, emitColunas, emitFiltroAvancado }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__busca-grupo {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela__busca">
|
|
||||||
<div class="eli-tabela__busca-input-wrapper">
|
|
||||||
<input
|
|
||||||
id="eli-tabela-busca"
|
|
||||||
v-model="texto"
|
|
||||||
type="search"
|
|
||||||
class="eli-tabela__busca-input"
|
|
||||||
placeholder="Digite termos para filtrar"
|
|
||||||
@keyup.enter="emitirBusca"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__busca-botao"
|
|
||||||
aria-label="Buscar"
|
|
||||||
title="Buscar"
|
|
||||||
@click="emitirBusca"
|
|
||||||
>
|
|
||||||
<Search class="eli-tabela__busca-botao-icone" :size="16" :stroke-width="2" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { Search } from "lucide-vue-next"
|
|
||||||
import { defineComponent, ref, watch } from "vue"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCaixaDeBusca",
|
|
||||||
components: { Search },
|
|
||||||
props: {
|
|
||||||
modelo: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
buscar(valor: string) {
|
|
||||||
return typeof valor === "string"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
/**
|
|
||||||
* Estado local da entrada para que o usuário possa digitar livremente antes
|
|
||||||
* de disparar uma nova consulta.
|
|
||||||
*/
|
|
||||||
const texto = ref(props.modelo ?? "")
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelo,
|
|
||||||
(novo) => {
|
|
||||||
if (novo !== undefined && novo !== texto.value) {
|
|
||||||
texto.value = novo
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
function emitirBusca() {
|
|
||||||
emit("buscar", texto.value.trim())
|
|
||||||
}
|
|
||||||
|
|
||||||
return { texto, emitirBusca }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__busca {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 8px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.eli-tabela__busca-input-wrapper {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: stretch;
|
|
||||||
border-radius: var(--eli-tabela-cabecalho-controle-radius, 8px);
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.15);
|
|
||||||
overflow: hidden;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
/* Herda do container do cabeçalho (.eli-tabela__cabecalho) quando presente. */
|
|
||||||
height: var(--eli-tabela-cabecalho-controle-altura, 34px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-input {
|
|
||||||
/* Mantém o input com a mesma altura do botão e dos botões de ação do cabeçalho. */
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 12px;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
color: rgba(15, 23, 42, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-input::-webkit-search-cancel-button,
|
|
||||||
.eli-tabela__busca-input::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-input::placeholder {
|
|
||||||
color: rgba(107, 114, 128, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-botao {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: none;
|
|
||||||
background: rgba(37, 99, 235, 0.12);
|
|
||||||
color: rgba(37, 99, 235, 0.95);
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-botao-icone {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-botao:hover,
|
|
||||||
.eli-tabela__busca-botao:focus-visible {
|
|
||||||
background: rgba(37, 99, 235, 0.2);
|
|
||||||
color: rgba(37, 99, 235, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__busca-botao:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.35);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<template>
|
|
||||||
<!-- Debug visual (somente DEV): expõe estados internos úteis para testes e diagnóstico -->
|
|
||||||
<div
|
|
||||||
v-if="isDev"
|
|
||||||
style="position: fixed; left: 8px; bottom: 8px; z-index: 999999; background: rgba(185,28,28,0.9); color: #fff; padding: 6px 10px; border-radius: 8px; font-size: 12px; max-width: 500px;"
|
|
||||||
>
|
|
||||||
<div><b>EliTabela debug</b></div>
|
|
||||||
<div>menuAberto: {{ menuAberto }}</div>
|
|
||||||
<div>menuPos: top={{ menuPopupPos.top }}, left={{ menuPopupPos.left }}</div>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaDebug",
|
|
||||||
props: {
|
|
||||||
isDev: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
menuAberto: {
|
|
||||||
type: Number as PropType<number | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
menuPopupPos: {
|
|
||||||
type: Object as PropType<{ top: number; left: number }>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela__detalhes">
|
|
||||||
<div v-for="(coluna, idx) in colunasInvisiveis" :key="`det-${idx}-${coluna.rotulo}`" class="eli-tabela__detalhe">
|
|
||||||
<div class="eli-tabela__detalhe-rotulo">{{ coluna.rotulo }}</div>
|
|
||||||
<div class="eli-tabela__detalhe-valor">
|
|
||||||
<EliTabelaCelula :celula="(coluna.celula(linha as never) as never)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import EliTabelaCelula from "./celulas/EliTabelaCelula.vue"
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaDetalhesLinha",
|
|
||||||
components: { EliTabelaCelula },
|
|
||||||
props: {
|
|
||||||
linha: {
|
|
||||||
type: null as unknown as PropType<unknown>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
colunasInvisiveis: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
type: Array as PropType<Array<tipoEliColuna<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* estilos base ficam no EliTabela.css (global do componente) */
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<template>
|
|
||||||
<!-- Estado de carregamento: consulta em andamento -->
|
|
||||||
<div v-if="carregando" class="eli-tabela eli-tabela--carregando" aria-busy="true">
|
|
||||||
Carregando...
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Estado de erro: mostra mensagem retornada pela consulta -->
|
|
||||||
<div v-else-if="erro" class="eli-tabela eli-tabela--erro" role="alert">
|
|
||||||
<div class="eli-tabela__erro-titulo">Erro</div>
|
|
||||||
<div class="eli-tabela__erro-mensagem">{{ erro }}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Estado vazio: consulta sem registros -->
|
|
||||||
<div v-else class="eli-tabela eli-tabela--vazio">
|
|
||||||
{{ mensagemVazio ?? "Nenhum registro encontrado." }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaEstados",
|
|
||||||
props: {
|
|
||||||
carregando: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
erro: {
|
|
||||||
type: String as PropType<string | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
mensagemVazio: {
|
|
||||||
type: String as PropType<string | undefined>,
|
|
||||||
required: false,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
<template>
|
|
||||||
<thead class="eli-tabela__thead">
|
|
||||||
<tr class="eli-tabela__tr eli-tabela__tr--header">
|
|
||||||
<th v-if="temColunasInvisiveis" class="eli-tabela__th eli-tabela__th--expander" scope="col"></th>
|
|
||||||
|
|
||||||
<th
|
|
||||||
v-for="(coluna, idx) in colunas"
|
|
||||||
:key="`th-${idx}`"
|
|
||||||
class="eli-tabela__th"
|
|
||||||
:class="[isOrdenavel(coluna) ? 'eli-tabela__th--ordenavel' : undefined]"
|
|
||||||
scope="col"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-if="isOrdenavel(coluna)"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__th-botao"
|
|
||||||
:class="[
|
|
||||||
colunaOrdenacao === String(coluna.coluna_ordem) ? 'eli-tabela__th-botao--ativo' : undefined,
|
|
||||||
]"
|
|
||||||
@click="emitAlternarOrdenacao(String(coluna.coluna_ordem))"
|
|
||||||
>
|
|
||||||
<span class="eli-tabela__th-texto">{{ coluna.rotulo }}</span>
|
|
||||||
|
|
||||||
<component
|
|
||||||
v-if="colunaOrdenacao === String(coluna.coluna_ordem)"
|
|
||||||
:is="direcaoOrdenacao === 'asc' ? ArrowUp : ArrowDown"
|
|
||||||
class="eli-tabela__th-icone"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
<ArrowUp
|
|
||||||
v-else
|
|
||||||
class="eli-tabela__th-icone eli-tabela__th-icone--oculto"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<span v-else class="eli-tabela__th-label">{{ coluna.rotulo }}</span>
|
|
||||||
</th>
|
|
||||||
|
|
||||||
<th v-if="temAcoes" class="eli-tabela__th eli-tabela__th--acoes" scope="col">
|
|
||||||
Ações
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { ArrowDown, ArrowUp } from "lucide-vue-next"
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaHead",
|
|
||||||
components: { ArrowUp, ArrowDown },
|
|
||||||
props: {
|
|
||||||
colunas: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
type: Array as PropType<Array<tipoEliColuna<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
temAcoes: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
temColunasInvisiveis: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
colunaOrdenacao: {
|
|
||||||
type: String as PropType<string | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
direcaoOrdenacao: {
|
|
||||||
type: String as PropType<"asc" | "desc">,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
alternarOrdenacao(chave: string) {
|
|
||||||
return typeof chave === "string" && chave.length > 0
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(_props, { emit }) {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
|
||||||
function isOrdenavel(coluna: any) {
|
|
||||||
return coluna?.coluna_ordem !== undefined && coluna?.coluna_ordem !== null
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitAlternarOrdenacao(chave: string) {
|
|
||||||
emit("alternarOrdenacao", chave)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
ArrowUp,
|
|
||||||
ArrowDown,
|
|
||||||
isOrdenavel,
|
|
||||||
emitAlternarOrdenacao,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
<template>
|
|
||||||
<Teleport to="body">
|
|
||||||
<ul
|
|
||||||
v-if="menuAberto !== null && possuiAcoes"
|
|
||||||
:id="`eli-tabela-acoes-menu-${menuAberto}`"
|
|
||||||
ref="menuEl"
|
|
||||||
class="eli-tabela__acoes-menu"
|
|
||||||
role="menu"
|
|
||||||
:aria-labelledby="`eli-tabela-acoes-toggle-${menuAberto}`"
|
|
||||||
:style="{
|
|
||||||
position: 'fixed',
|
|
||||||
top: `${posicao.top}px`,
|
|
||||||
left: `${posicao.left}px`,
|
|
||||||
zIndex: 999999,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<li
|
|
||||||
v-for="item in acoes"
|
|
||||||
:key="`acao-${menuAberto}-${item.indice}`"
|
|
||||||
class="eli-tabela__acoes-item"
|
|
||||||
role="none"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__acoes-item-botao"
|
|
||||||
:style="{ color: item.acao.cor }"
|
|
||||||
role="menuitem"
|
|
||||||
:aria-label="item.acao.rotulo"
|
|
||||||
:title="item.acao.rotulo"
|
|
||||||
@click.stop="emitExecutar(item)"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="item.acao.icone"
|
|
||||||
class="eli-tabela__acoes-item-icone"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
/>
|
|
||||||
<span class="eli-tabela__acoes-item-texto">{{ item.acao.rotulo }}</span>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</Teleport>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType, ref } from "vue"
|
|
||||||
import type { tipoEliTabelaAcao } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
type ItemAcao<T> = {
|
|
||||||
acao: tipoEliTabelaAcao<T>
|
|
||||||
indice: number
|
|
||||||
visivel: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaMenuAcoes",
|
|
||||||
props: {
|
|
||||||
menuAberto: {
|
|
||||||
type: Number as PropType<number | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
posicao: {
|
|
||||||
type: Object as PropType<{ top: number; left: number }>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
acoes: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
|
||||||
type: Array as PropType<Array<ItemAcao<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
linha: {
|
|
||||||
// Aceita qualquer tipo de linha (objeto, string, etc.) sem validação runtime.
|
|
||||||
type: null as unknown as PropType<unknown | null>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
|
||||||
executar(payload: { acao: tipoEliTabelaAcao<any>; linha: unknown }) {
|
|
||||||
return payload !== null && typeof payload === "object"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props, { emit, expose }) {
|
|
||||||
const menuEl = ref<HTMLElement | null>(null)
|
|
||||||
expose({ menuEl })
|
|
||||||
|
|
||||||
const possuiAcoes = computed(() => props.acoes.length > 0)
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
|
||||||
function emitExecutar(item: { acao: tipoEliTabelaAcao<any> }) {
|
|
||||||
if (!props.linha) return
|
|
||||||
emit("executar", { acao: item.acao, linha: props.linha })
|
|
||||||
}
|
|
||||||
|
|
||||||
return { menuEl, possuiAcoes, emitExecutar }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,438 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-if="aberto" class="eli-tabela-modal-colunas__overlay" role="presentation" @click.self="emitFechar">
|
|
||||||
<div
|
|
||||||
class="eli-tabela-modal-colunas__modal"
|
|
||||||
role="dialog"
|
|
||||||
aria-modal="true"
|
|
||||||
aria-label="Configurar colunas"
|
|
||||||
>
|
|
||||||
<header class="eli-tabela-modal-colunas__header">
|
|
||||||
<h3 class="eli-tabela-modal-colunas__titulo">Colunas</h3>
|
|
||||||
<button type="button" class="eli-tabela-modal-colunas__fechar" aria-label="Fechar" @click="emitFechar">
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="eli-tabela-modal-colunas__conteudo">
|
|
||||||
<div class="eli-tabela-modal-colunas__coluna">
|
|
||||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Visíveis</div>
|
|
||||||
<div
|
|
||||||
class="eli-tabela-modal-colunas__lista"
|
|
||||||
@dragover.prevent
|
|
||||||
@drop="(e) => onDropLista(e, 'visiveis', null)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="(rotulo, idx) in visiveisLocal"
|
|
||||||
:key="`vis-${rotulo}`"
|
|
||||||
class="eli-tabela-modal-colunas__item"
|
|
||||||
draggable="true"
|
|
||||||
@dragstart="(e) => onDragStart(e, rotulo, 'visiveis', idx)"
|
|
||||||
@dragover.prevent
|
|
||||||
@drop="(e) => onDropItem(e, 'visiveis', idx)"
|
|
||||||
>
|
|
||||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
|
||||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="eli-tabela-modal-colunas__coluna">
|
|
||||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Invisíveis</div>
|
|
||||||
<div
|
|
||||||
class="eli-tabela-modal-colunas__lista"
|
|
||||||
@dragover.prevent
|
|
||||||
@drop="(e) => onDropLista(e, 'invisiveis', null)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-for="(rotulo, idx) in invisiveisLocal"
|
|
||||||
:key="`inv-${rotulo}`"
|
|
||||||
class="eli-tabela-modal-colunas__item"
|
|
||||||
draggable="true"
|
|
||||||
@dragstart="(e) => onDragStart(e, rotulo, 'invisiveis', idx)"
|
|
||||||
@dragover.prevent
|
|
||||||
@drop="(e) => onDropItem(e, 'invisiveis', idx)"
|
|
||||||
>
|
|
||||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
|
||||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="eli-tabela-modal-colunas__footer">
|
|
||||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--sec" @click="emitFechar">
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--prim" @click="emitSalvar">
|
|
||||||
Salvar
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType, ref, watch } from "vue"
|
|
||||||
import type { EliTabelaColunasConfig } from "./colunasStorage"
|
|
||||||
import type { tipoEliColuna } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
type OrigemLista = "visiveis" | "invisiveis"
|
|
||||||
|
|
||||||
type DragPayload = {
|
|
||||||
rotulo: string
|
|
||||||
origem: OrigemLista
|
|
||||||
index: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const DRAG_MIME = "application/x-eli-tabela-coluna"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaModalColunas",
|
|
||||||
props: {
|
|
||||||
aberto: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
rotulosColunas: {
|
|
||||||
type: Array as PropType<string[]>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
configInicial: {
|
|
||||||
type: Object as PropType<EliTabelaColunasConfig>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
colunas: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
|
||||||
type: Array as PropType<Array<tipoEliColuna<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
fechar() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
salvar(_config: EliTabelaColunasConfig) {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const visiveisLocal = ref<string[]>([])
|
|
||||||
const invisiveisLocal = ref<string[]>([])
|
|
||||||
|
|
||||||
function sincronizarEstado() {
|
|
||||||
const todos = props.rotulosColunas
|
|
||||||
const configTemDados =
|
|
||||||
(props.configInicial.visiveis?.length ?? 0) > 0 ||
|
|
||||||
(props.configInicial.invisiveis?.length ?? 0) > 0
|
|
||||||
|
|
||||||
const invisiveisPadraoSet = new Set(
|
|
||||||
props.colunas.filter((c) => c.visivel === false).map((c) => c.rotulo),
|
|
||||||
)
|
|
||||||
|
|
||||||
const invisiveisSet = configTemDados
|
|
||||||
? new Set(props.configInicial.invisiveis ?? [])
|
|
||||||
: invisiveisPadraoSet
|
|
||||||
|
|
||||||
const baseVisiveis = todos.filter((r) => !invisiveisSet.has(r))
|
|
||||||
|
|
||||||
// ordenação: aplica ordem salva (visiveis) e adiciona novas ao final
|
|
||||||
const ordemSalva = props.configInicial.visiveis ?? []
|
|
||||||
const setVis = new Set(baseVisiveis)
|
|
||||||
const ordenadas: string[] = []
|
|
||||||
|
|
||||||
for (const r of ordemSalva) {
|
|
||||||
if (setVis.has(r)) ordenadas.push(r)
|
|
||||||
}
|
|
||||||
for (const r of baseVisiveis) {
|
|
||||||
if (!ordenadas.includes(r)) ordenadas.push(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
visiveisLocal.value = ordenadas
|
|
||||||
|
|
||||||
// invisíveis: somente as que existem na tabela
|
|
||||||
invisiveisLocal.value = todos.filter((r) => invisiveisSet.has(r))
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() =>
|
|
||||||
[
|
|
||||||
props.aberto,
|
|
||||||
props.rotulosColunas,
|
|
||||||
props.configInicial,
|
|
||||||
props.colunas,
|
|
||||||
] as const,
|
|
||||||
() => {
|
|
||||||
if (props.aberto) sincronizarEstado()
|
|
||||||
},
|
|
||||||
{ deep: true, immediate: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
function emitFechar() {
|
|
||||||
emit("fechar")
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitSalvar() {
|
|
||||||
emit("salvar", {
|
|
||||||
visiveis: [...visiveisLocal.value],
|
|
||||||
invisiveis: [...invisiveisLocal.value],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeDragData(e: DragEvent, payload: DragPayload) {
|
|
||||||
try {
|
|
||||||
e.dataTransfer?.setData(DRAG_MIME, JSON.stringify(payload))
|
|
||||||
e.dataTransfer?.setData("text/plain", payload.rotulo)
|
|
||||||
if (e.dataTransfer) {
|
|
||||||
e.dataTransfer.effectAllowed = "move"
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function readDragData(e: DragEvent): DragPayload | null {
|
|
||||||
try {
|
|
||||||
const raw = e.dataTransfer?.getData(DRAG_MIME)
|
|
||||||
if (!raw) return null
|
|
||||||
const parsed = JSON.parse(raw)
|
|
||||||
if (
|
|
||||||
!parsed ||
|
|
||||||
typeof parsed.rotulo !== "string" ||
|
|
||||||
(parsed.origem !== "visiveis" && parsed.origem !== "invisiveis")
|
|
||||||
) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return parsed as DragPayload
|
|
||||||
} catch {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removerDaOrigem(payload: DragPayload) {
|
|
||||||
const origemArr =
|
|
||||||
payload.origem === "visiveis"
|
|
||||||
? visiveisLocal.value
|
|
||||||
: invisiveisLocal.value
|
|
||||||
const idx = origemArr.indexOf(payload.rotulo)
|
|
||||||
if (idx >= 0) origemArr.splice(idx, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function inserirNoDestino(
|
|
||||||
destino: OrigemLista,
|
|
||||||
rotulo: string,
|
|
||||||
index: number | null,
|
|
||||||
) {
|
|
||||||
const arr =
|
|
||||||
destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
|
||||||
// remove duplicatas
|
|
||||||
const existing = arr.indexOf(rotulo)
|
|
||||||
if (existing >= 0) arr.splice(existing, 1)
|
|
||||||
|
|
||||||
if (index === null || index < 0 || index > arr.length) {
|
|
||||||
arr.push(rotulo)
|
|
||||||
} else {
|
|
||||||
arr.splice(index, 0, rotulo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDragStart(
|
|
||||||
e: DragEvent,
|
|
||||||
rotulo: string,
|
|
||||||
origem: OrigemLista,
|
|
||||||
index: number,
|
|
||||||
) {
|
|
||||||
writeDragData(e, { rotulo, origem, index })
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDropItem(e: DragEvent, destino: OrigemLista, index: number) {
|
|
||||||
const payload = readDragData(e)
|
|
||||||
if (!payload) return
|
|
||||||
|
|
||||||
// remove da origem e insere no destino na posição do item
|
|
||||||
removerDaOrigem(payload)
|
|
||||||
inserirNoDestino(destino, payload.rotulo, index)
|
|
||||||
|
|
||||||
// garante que uma coluna não fique nos 2 lados
|
|
||||||
if (destino === "visiveis") {
|
|
||||||
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo)
|
|
||||||
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1)
|
|
||||||
} else {
|
|
||||||
const idxVis = visiveisLocal.value.indexOf(payload.rotulo)
|
|
||||||
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDropLista(
|
|
||||||
e: DragEvent,
|
|
||||||
destino: OrigemLista,
|
|
||||||
_index: number | null,
|
|
||||||
) {
|
|
||||||
const payload = readDragData(e)
|
|
||||||
if (!payload) return
|
|
||||||
|
|
||||||
removerDaOrigem(payload)
|
|
||||||
inserirNoDestino(destino, payload.rotulo, null)
|
|
||||||
|
|
||||||
if (destino === "visiveis") {
|
|
||||||
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo)
|
|
||||||
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1)
|
|
||||||
} else {
|
|
||||||
const idxVis = visiveisLocal.value.indexOf(payload.rotulo)
|
|
||||||
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
visiveisLocal,
|
|
||||||
invisiveisLocal,
|
|
||||||
emitFechar,
|
|
||||||
emitSalvar,
|
|
||||||
onDragStart,
|
|
||||||
onDropItem,
|
|
||||||
onDropLista,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela-modal-colunas__overlay {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
background: rgba(15, 23, 42, 0.35);
|
|
||||||
z-index: 4000;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__modal {
|
|
||||||
width: min(860px, 100%);
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 14px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.1);
|
|
||||||
box-shadow: 0 18px 60px rgba(15, 23, 42, 0.25);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-bottom: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__titulo {
|
|
||||||
font-size: 1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__fechar {
|
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 22px;
|
|
||||||
line-height: 1;
|
|
||||||
color: rgba(15, 23, 42, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__fechar:hover,
|
|
||||||
.eli-tabela-modal-colunas__fechar:focus-visible {
|
|
||||||
background: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__conteudo {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 12px;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__coluna-titulo {
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__lista {
|
|
||||||
min-height: 260px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 10px;
|
|
||||||
background: rgba(15, 23, 42, 0.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 10px 10px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
background: #fff;
|
|
||||||
cursor: grab;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__item + .eli-tabela-modal-colunas__item {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__item:active {
|
|
||||||
cursor: grabbing;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__item-handle {
|
|
||||||
color: rgba(15, 23, 42, 0.55);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__item-texto {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-top: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__botao {
|
|
||||||
height: 34px;
|
|
||||||
padding: 0 14px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
background: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__botao--sec:hover,
|
|
||||||
.eli-tabela-modal-colunas__botao--sec:focus-visible {
|
|
||||||
background: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__botao--prim {
|
|
||||||
border: none;
|
|
||||||
background: rgba(37, 99, 235, 0.95);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-colunas__botao--prim:hover,
|
|
||||||
.eli-tabela-modal-colunas__botao--prim:focus-visible {
|
|
||||||
background: rgba(37, 99, 235, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
|
||||||
.eli-tabela-modal-colunas__conteudo {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,403 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-if="aberto" class="eli-tabela-modal-filtro__overlay" role="presentation" @click.self="emitFechar">
|
|
||||||
<div class="eli-tabela-modal-filtro__modal" role="dialog" aria-modal="true" aria-label="Filtro avançado">
|
|
||||||
<header class="eli-tabela-modal-filtro__header">
|
|
||||||
<h3 class="eli-tabela-modal-filtro__titulo">Filtro avançado</h3>
|
|
||||||
<button type="button" class="eli-tabela-modal-filtro__fechar" aria-label="Fechar" @click="emitFechar">
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="eli-tabela-modal-filtro__conteudo">
|
|
||||||
<div v-if="!filtrosBase.length" class="eli-tabela-modal-filtro__vazio">
|
|
||||||
Nenhum filtro configurado na tabela.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else class="eli-tabela-modal-filtro__lista">
|
|
||||||
<div v-for="(linha, idx) in linhas" :key="String(linha.chave)" class="eli-tabela-modal-filtro__linha">
|
|
||||||
<div class="eli-tabela-modal-filtro__entrada">
|
|
||||||
<component
|
|
||||||
:is="componenteEntrada(linha.entrada)"
|
|
||||||
:value="linha.valor"
|
|
||||||
@update:value="(v: any) => (linha.valor = v)"
|
|
||||||
@input="(v: any) => (linha.valor = v)"
|
|
||||||
:opcoes="opcoesEntrada(linha.entrada)"
|
|
||||||
density="compact"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela-modal-filtro__remover"
|
|
||||||
title="Remover"
|
|
||||||
aria-label="Remover"
|
|
||||||
@click="remover(idx)"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="eli-tabela-modal-filtro__acoes">
|
|
||||||
<select
|
|
||||||
v-model="chaveParaAdicionar"
|
|
||||||
class="eli-tabela-modal-filtro__select"
|
|
||||||
:disabled="!opcoesParaAdicionar.length"
|
|
||||||
>
|
|
||||||
<option disabled value="">Selecione um filtro…</option>
|
|
||||||
<option v-for="o in opcoesParaAdicionar" :key="String(o.chave)" :value="String(o.chave)">
|
|
||||||
{{ rotuloDoFiltro(o) }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela-modal-filtro__botao"
|
|
||||||
@click="adicionar"
|
|
||||||
:disabled="!chaveParaAdicionar"
|
|
||||||
>
|
|
||||||
Adicionar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer class="eli-tabela-modal-filtro__footer">
|
|
||||||
<button type="button" class="eli-tabela-modal-filtro__botao eli-tabela-modal-filtro__botao--sec" @click="emitLimpar">
|
|
||||||
Limpar
|
|
||||||
</button>
|
|
||||||
<button type="button" class="eli-tabela-modal-filtro__botao eli-tabela-modal-filtro__botao--sec" @click="emitFechar">
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
<button type="button" class="eli-tabela-modal-filtro__botao eli-tabela-modal-filtro__botao--prim" @click="emitSalvar">
|
|
||||||
Aplicar
|
|
||||||
</button>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType, ref, watch } from "vue"
|
|
||||||
import {
|
|
||||||
EliEntradaDataHora,
|
|
||||||
EliEntradaNumero,
|
|
||||||
EliEntradaTexto,
|
|
||||||
} from "../EliEntrada"
|
|
||||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas"
|
|
||||||
import type { tipoEliTabelaConsulta } from "./types-eli-tabela"
|
|
||||||
|
|
||||||
type FiltroBase<T> = NonNullable<
|
|
||||||
tipoEliTabelaConsulta<T>["filtroAvancado"]
|
|
||||||
>[number]
|
|
||||||
|
|
||||||
type LinhaFiltro = {
|
|
||||||
chave: string
|
|
||||||
entrada: ComponenteEntrada
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic value
|
|
||||||
valor: any
|
|
||||||
}
|
|
||||||
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic typing needed
|
|
||||||
function rotuloDoFiltro(f: FiltroBase<any>) {
|
|
||||||
return f.rotulo
|
|
||||||
}
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaModalFiltroAvancado",
|
|
||||||
props: {
|
|
||||||
aberto: { type: Boolean, required: true },
|
|
||||||
filtrosBase: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: generic component
|
|
||||||
type: Array as PropType<Array<FiltroBase<any>>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
modelo: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic model
|
|
||||||
type: Array as PropType<Array<any>>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
fechar: () => true,
|
|
||||||
limpar: () => true,
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic lines
|
|
||||||
salvar: (_linhas: any[]) => true,
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const linhas = ref<Array<LinhaFiltro>>([])
|
|
||||||
|
|
||||||
const chaveParaAdicionar = ref<string>("")
|
|
||||||
|
|
||||||
const chavesDisponiveis = computed(() =>
|
|
||||||
(props.filtrosBase ?? []).map((b) => String(b.chave)),
|
|
||||||
)
|
|
||||||
|
|
||||||
const opcoesParaAdicionar = computed(() => {
|
|
||||||
const usadas = new Set(linhas.value.map((l) => String(l.chave)))
|
|
||||||
return (props.filtrosBase ?? []).filter(
|
|
||||||
(b) => !usadas.has(String(b.chave)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
function componenteEntrada(entrada: ComponenteEntrada) {
|
|
||||||
const tipo = entrada?.[0]
|
|
||||||
if (tipo === "numero") return EliEntradaNumero
|
|
||||||
if (tipo === "dataHora") return EliEntradaDataHora
|
|
||||||
return EliEntradaTexto
|
|
||||||
}
|
|
||||||
|
|
||||||
function opcoesEntrada(entrada: ComponenteEntrada) {
|
|
||||||
// o rótulo vem do próprio componente (entrada[1].rotulo)
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic options
|
|
||||||
return (entrada?.[1] as any) ?? { rotulo: "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
function valorInicialPorEntrada(entrada: ComponenteEntrada) {
|
|
||||||
const tipo = entrada?.[0]
|
|
||||||
if (tipo === "numero") return null
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizarModelo() {
|
|
||||||
const base = props.filtrosBase ?? []
|
|
||||||
const modelo = Array.isArray(props.modelo) ? props.modelo : []
|
|
||||||
linhas.value = modelo
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic model item
|
|
||||||
.map((m: any) => {
|
|
||||||
const baseItem =
|
|
||||||
base.find((b) => String(b.chave) === String(m.chave)) ?? base[0]
|
|
||||||
|
|
||||||
if (!baseItem) return null
|
|
||||||
|
|
||||||
const entrada = (baseItem.entrada ?? m.entrada) as ComponenteEntrada
|
|
||||||
const chave = String(baseItem.chave ?? m.chave)
|
|
||||||
const val = m.valor ?? valorInicialPorEntrada(entrada)
|
|
||||||
|
|
||||||
return {
|
|
||||||
chave: chave,
|
|
||||||
entrada,
|
|
||||||
valor: val,
|
|
||||||
} as LinhaFiltro
|
|
||||||
})
|
|
||||||
.filter(Boolean) as LinhaFiltro[]
|
|
||||||
|
|
||||||
// se algum filtro mudou a chave para valor inválido, ajusta
|
|
||||||
linhas.value = linhas.value.filter((l) =>
|
|
||||||
chavesDisponiveis.value.includes(String(l.chave)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => [props.aberto, props.filtrosBase, props.modelo] as const,
|
|
||||||
() => {
|
|
||||||
if (props.aberto) normalizarModelo()
|
|
||||||
},
|
|
||||||
{ deep: true, immediate: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
function adicionar() {
|
|
||||||
if (!chaveParaAdicionar.value) return
|
|
||||||
const b0 = (props.filtrosBase ?? []).find(
|
|
||||||
(b) => String(b.chave) === String(chaveParaAdicionar.value),
|
|
||||||
)
|
|
||||||
if (!b0) return
|
|
||||||
// evita repetição
|
|
||||||
if (linhas.value.some((l) => String(l.chave) === String(b0.chave))) return
|
|
||||||
|
|
||||||
linhas.value.push({
|
|
||||||
chave: String(b0.chave),
|
|
||||||
entrada: b0.entrada,
|
|
||||||
valor: valorInicialPorEntrada(b0.entrada),
|
|
||||||
})
|
|
||||||
|
|
||||||
chaveParaAdicionar.value = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
function remover(idx: number) {
|
|
||||||
linhas.value.splice(idx, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitFechar() {
|
|
||||||
emit("fechar")
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitLimpar() {
|
|
||||||
emit("limpar")
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitSalvar() {
|
|
||||||
emit(
|
|
||||||
"salvar",
|
|
||||||
linhas.value.map((l) => ({
|
|
||||||
chave: l.chave,
|
|
||||||
valor: l.valor,
|
|
||||||
})),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
linhas,
|
|
||||||
opcoesParaAdicionar,
|
|
||||||
chaveParaAdicionar,
|
|
||||||
componenteEntrada,
|
|
||||||
opcoesEntrada,
|
|
||||||
adicionar,
|
|
||||||
remover,
|
|
||||||
emitFechar,
|
|
||||||
emitSalvar,
|
|
||||||
emitLimpar,
|
|
||||||
rotuloDoFiltro,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela-modal-filtro__overlay {
|
|
||||||
position: fixed;
|
|
||||||
inset: 0;
|
|
||||||
background: rgba(15, 23, 42, 0.35);
|
|
||||||
z-index: 4000;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__modal {
|
|
||||||
width: min(980px, 100%);
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 14px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.1);
|
|
||||||
box-shadow: 0 18px 60px rgba(15, 23, 42, 0.25);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-bottom: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__titulo {
|
|
||||||
font-size: 1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__fechar {
|
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 22px;
|
|
||||||
line-height: 1;
|
|
||||||
color: rgba(15, 23, 42, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__fechar:hover,
|
|
||||||
.eli-tabela-modal-filtro__fechar:focus-visible {
|
|
||||||
background: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__conteudo {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__vazio {
|
|
||||||
opacity: 0.75;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__lista {
|
|
||||||
display: grid;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__linha {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 34px;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__select {
|
|
||||||
height: 34px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
padding: 0 10px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__entrada {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__remover {
|
|
||||||
width: 34px;
|
|
||||||
height: 34px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
background: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 1;
|
|
||||||
color: rgba(15, 23, 42, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__remover:hover,
|
|
||||||
.eli-tabela-modal-filtro__remover:focus-visible {
|
|
||||||
background: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__acoes {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 14px 16px;
|
|
||||||
border-top: 1px solid rgba(15, 23, 42, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__botao {
|
|
||||||
height: 34px;
|
|
||||||
padding: 0 14px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
background: #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__botao:disabled {
|
|
||||||
opacity: 0.55;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__botao--sec:hover,
|
|
||||||
.eli-tabela-modal-filtro__botao--sec:focus-visible {
|
|
||||||
background: rgba(15, 23, 42, 0.06);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__botao--prim {
|
|
||||||
border: none;
|
|
||||||
background: rgba(37, 99, 235, 0.95);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela-modal-filtro__botao--prim:hover,
|
|
||||||
.eli-tabela-modal-filtro__botao--prim:focus-visible {
|
|
||||||
background: rgba(37, 99, 235, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 880px) {
|
|
||||||
.eli-tabela-modal-filtro__linha {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela__rodape">
|
|
||||||
<div
|
|
||||||
v-if="acoes.length > 0"
|
|
||||||
class="eli-tabela__acoes-inferiores"
|
|
||||||
style="margin-right: auto"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
v-for="(botao, indice) in acoes"
|
|
||||||
:key="`${botao.rotulo}-${indice}`"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__acao-inferior"
|
|
||||||
:style="botao.cor ? { borderColor: botao.cor, color: botao.cor } : undefined"
|
|
||||||
@click="botao.acao(parametrosConsulta)"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
v-if="botao.icone"
|
|
||||||
:is="botao.icone"
|
|
||||||
class="eli-tabela__acoes-cabecalho-icone"
|
|
||||||
:size="16"
|
|
||||||
:stroke-width="2"
|
|
||||||
/>
|
|
||||||
<span class="eli-tabela__acoes-cabecalho-rotulo">{{ botao.rotulo }}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav
|
|
||||||
v-if="totalPaginasExibidas > 1"
|
|
||||||
class="eli-tabela__paginacao"
|
|
||||||
role="navigation"
|
|
||||||
aria-label="Paginação de resultados"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__pagina-botao"
|
|
||||||
:disabled="anteriorDesabilitado"
|
|
||||||
aria-label="Página anterior"
|
|
||||||
@click="irParaPagina(paginaAtual - 1)"
|
|
||||||
>
|
|
||||||
<<
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<template v-for="(item, index) in botoes" :key="`${item.label}-${index}`">
|
|
||||||
<span
|
|
||||||
v-if="item.ehEllipsis"
|
|
||||||
class="eli-tabela__pagina-ellipsis"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__pagina-botao"
|
|
||||||
:class="item.ativo ? 'eli-tabela__pagina-botao--ativo' : undefined"
|
|
||||||
:disabled="item.ativo"
|
|
||||||
:aria-current="item.ativo ? 'page' : undefined"
|
|
||||||
:aria-label="`Ir para página ${item.label}`"
|
|
||||||
@click="irParaPagina(item.pagina)"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__pagina-botao"
|
|
||||||
:disabled="proximaDesabilitada"
|
|
||||||
aria-label="Próxima página"
|
|
||||||
@click="irParaPagina(paginaAtual + 1)"
|
|
||||||
>
|
|
||||||
>>
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaPaginacao",
|
|
||||||
props: {
|
|
||||||
pagina: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
totalPaginas: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
maximoBotoes: {
|
|
||||||
type: Number,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
acoes: {
|
|
||||||
type: Array as PropType<
|
|
||||||
Array<{
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic icon
|
|
||||||
icone?: any
|
|
||||||
cor?: string
|
|
||||||
rotulo: string
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic action
|
|
||||||
acao: (params?: any) => void
|
|
||||||
}>
|
|
||||||
>,
|
|
||||||
required: false,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
parametrosConsulta: {
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic params
|
|
||||||
type: Object as PropType<any>,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: {
|
|
||||||
alterar(pagina: number) {
|
|
||||||
return Number.isFinite(pagina)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props, { emit }) {
|
|
||||||
/**
|
|
||||||
* Define o limite de botões visíveis. Mantemos um mínimo de 7 para garantir
|
|
||||||
* uma navegação confortável, mesmo quando o consumidor não informa o valor.
|
|
||||||
*/
|
|
||||||
const maximoBotoesVisiveis = computed(() => {
|
|
||||||
const valor = props.maximoBotoes
|
|
||||||
if (typeof valor === "number" && valor >= 5) {
|
|
||||||
return Math.floor(valor)
|
|
||||||
}
|
|
||||||
return 7
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constrói a lista de botões/reticências que serão exibidos na paginação.
|
|
||||||
* Mantemos sempre a primeira e a última página visíveis, posicionando as
|
|
||||||
* demais de forma dinâmica ao redor da página atual.
|
|
||||||
*/
|
|
||||||
const botoes = computed(() => {
|
|
||||||
const total = props.totalPaginas
|
|
||||||
const atual = props.pagina
|
|
||||||
const limite = maximoBotoesVisiveis.value
|
|
||||||
const resultado: Array<{
|
|
||||||
label: string
|
|
||||||
pagina?: number
|
|
||||||
ativo?: boolean
|
|
||||||
ehEllipsis?: boolean
|
|
||||||
}> = []
|
|
||||||
|
|
||||||
const adicionarPagina = (pagina: number) => {
|
|
||||||
resultado.push({
|
|
||||||
label: String(pagina),
|
|
||||||
pagina,
|
|
||||||
ativo: pagina === atual,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const adicionarReticencias = () => {
|
|
||||||
resultado.push({ label: "…", ehEllipsis: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (total <= limite) {
|
|
||||||
for (let pagina = 1; pagina <= total; pagina += 1) {
|
|
||||||
adicionarPagina(pagina)
|
|
||||||
}
|
|
||||||
return resultado
|
|
||||||
}
|
|
||||||
|
|
||||||
const visiveisCentrais = Math.max(3, limite - 2)
|
|
||||||
let inicio = Math.max(2, atual - Math.floor(visiveisCentrais / 2))
|
|
||||||
let fim = inicio + visiveisCentrais - 1
|
|
||||||
|
|
||||||
if (fim >= total) {
|
|
||||||
fim = total - 1
|
|
||||||
inicio = fim - visiveisCentrais + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
adicionarPagina(1)
|
|
||||||
|
|
||||||
if (inicio > 2) {
|
|
||||||
adicionarReticencias()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let pagina = inicio; pagina <= fim; pagina += 1) {
|
|
||||||
adicionarPagina(pagina)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fim < total - 1) {
|
|
||||||
adicionarReticencias()
|
|
||||||
}
|
|
||||||
|
|
||||||
adicionarPagina(total)
|
|
||||||
|
|
||||||
return resultado
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emite a requisição de mudança de página garantindo que o valor esteja
|
|
||||||
* dentro dos limites válidos informados pelo componente pai.
|
|
||||||
*/
|
|
||||||
function irParaPagina(pagina: number | undefined) {
|
|
||||||
if (!pagina) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const alvo = Math.min(Math.max(1, pagina), props.totalPaginas)
|
|
||||||
if (alvo !== props.pagina) {
|
|
||||||
emit("alterar", alvo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const anteriorDesabilitado = computed(() => props.pagina <= 1)
|
|
||||||
const proximaDesabilitada = computed(
|
|
||||||
() => props.pagina >= props.totalPaginas,
|
|
||||||
)
|
|
||||||
const paginaAtual = computed(() => props.pagina)
|
|
||||||
const totalPaginasExibidas = computed(() => props.totalPaginas)
|
|
||||||
|
|
||||||
return {
|
|
||||||
botoes,
|
|
||||||
irParaPagina,
|
|
||||||
anteriorDesabilitado,
|
|
||||||
proximaDesabilitada,
|
|
||||||
paginaAtual,
|
|
||||||
totalPaginasExibidas,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__paginacao {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
gap: 12px;
|
|
||||||
margin-top: 12px;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-botao {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 6px 14px;
|
|
||||||
border-radius: 9999px;
|
|
||||||
border: 1px solid rgba(15, 23, 42, 0.12);
|
|
||||||
background: #ffffff;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
color: rgba(15, 23, 42, 0.82);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, border-color 0.2s ease,
|
|
||||||
color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-botao:hover,
|
|
||||||
.eli-tabela__pagina-botao:focus-visible {
|
|
||||||
background-color: rgba(37, 99, 235, 0.08);
|
|
||||||
border-color: rgba(37, 99, 235, 0.4);
|
|
||||||
color: rgba(37, 99, 235, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-botao:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-botao:disabled {
|
|
||||||
cursor: default;
|
|
||||||
opacity: 0.5;
|
|
||||||
background: rgba(148, 163, 184, 0.08);
|
|
||||||
border-color: rgba(148, 163, 184, 0.18);
|
|
||||||
color: rgba(71, 85, 105, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-botao--ativo {
|
|
||||||
background: rgba(37, 99, 235, 0.12);
|
|
||||||
border-color: rgba(37, 99, 235, 0.4);
|
|
||||||
color: rgba(37, 99, 235, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__pagina-ellipsis {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 32px;
|
|
||||||
color: rgba(107, 114, 128, 0.85);
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acao-inferior {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
height: 34px;
|
|
||||||
padding: 0 14px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #16a34a; /* default green */
|
|
||||||
background: #ffffff;
|
|
||||||
color: #16a34a;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acao-inferior:hover,
|
|
||||||
.eli-tabela__acao-inferior:focus-visible {
|
|
||||||
background-color: #f0fdf4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__acao-inferior:focus-visible {
|
|
||||||
outline: 2px solid #16a34a;
|
|
||||||
outline-offset: 2px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
<template>
|
|
||||||
<!--
|
|
||||||
Os componentes de célula possuem props tipadas por `tipo`.
|
|
||||||
Aqui o TS do template não consegue inferir o narrowing do union do `dados`,
|
|
||||||
então normalizamos para `unknown` e deixamos a validação de runtime do Vue.
|
|
||||||
-->
|
|
||||||
<component :is="Componente" :dados="dadosParaComponente" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import type { Component } from "vue"
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
|
|
||||||
import type {
|
|
||||||
tipoComponenteCelula,
|
|
||||||
tiposTabelaCelulas,
|
|
||||||
tipoTabelaCelula,
|
|
||||||
} from "../types-eli-tabela"
|
|
||||||
import { registryTabelaCelulas } from "./registryTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelula",
|
|
||||||
props: {
|
|
||||||
celula: {
|
|
||||||
// `ComponenteCelula` é uma tupla `readonly [tipo, dados]`.
|
|
||||||
type: Array as unknown as PropType<tipoComponenteCelula>,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const tipo = computed(() => props.celula[0] as tipoTabelaCelula)
|
|
||||||
const dados = computed(
|
|
||||||
() => props.celula[1] as tiposTabelaCelulas[tipoTabelaCelula],
|
|
||||||
)
|
|
||||||
|
|
||||||
// Observação: mantemos o registry tipado, mas o TS do template não consegue
|
|
||||||
// fazer narrowing do componente com base em `tipo`, então tipamos como `Component`.
|
|
||||||
const Componente = computed(
|
|
||||||
() => registryTabelaCelulas[tipo.value] as unknown as Component,
|
|
||||||
)
|
|
||||||
|
|
||||||
const dadosParaComponente = computed(() => dados.value)
|
|
||||||
|
|
||||||
return { Componente, dadosParaComponente }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
<template>
|
|
||||||
<button
|
|
||||||
v-if="dados?.acao"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__celula-link"
|
|
||||||
@click.stop.prevent="dados.acao()"
|
|
||||||
>
|
|
||||||
{{ textoData }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<span v-else>{{ textoData }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { dayjsbr } from "p-comuns"
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelulaData",
|
|
||||||
props: {
|
|
||||||
dados: {
|
|
||||||
type: Object as PropType<tiposTabelaCelulas["data"]>,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup({ dados }) {
|
|
||||||
const textoData = computed(() => {
|
|
||||||
const valorIso = dados?.valor
|
|
||||||
if (!valorIso) return ""
|
|
||||||
|
|
||||||
const formato = dados?.formato ?? "data"
|
|
||||||
|
|
||||||
if (formato === "relativo") {
|
|
||||||
return dayjsbr(valorIso).fromNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formato === "data_hora") {
|
|
||||||
// Padrão pt-BR simples (sem depender de locale do dayjsbr)
|
|
||||||
return dayjsbr(valorIso).format("DD/MM/YYYY HH:mm")
|
|
||||||
}
|
|
||||||
|
|
||||||
// formato === "data"
|
|
||||||
return dayjsbr(valorIso).format("DD/MM/YYYY")
|
|
||||||
})
|
|
||||||
|
|
||||||
return { dados, textoData }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__celula-link {
|
|
||||||
all: unset;
|
|
||||||
display: inline;
|
|
||||||
color: #2563eb;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: rgba(37, 99, 235, 0.55);
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:hover {
|
|
||||||
color: #1d4ed8;
|
|
||||||
text-decoration-color: rgba(29, 78, 216, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
<template>
|
|
||||||
<button
|
|
||||||
v-if="dados?.acao"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__celula-link"
|
|
||||||
@click.stop.prevent="dados.acao()"
|
|
||||||
>
|
|
||||||
{{ textoNumero }}
|
|
||||||
</button>
|
|
||||||
<span v-else>{{ textoNumero }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { computed, defineComponent, type PropType } from "vue"
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelulaNumero",
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
dados: {
|
|
||||||
type: Object as PropType<tiposTabelaCelulas["numero"]>,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup({ dados }) {
|
|
||||||
const textoNumero = computed(() => {
|
|
||||||
// Mantemos o comportamento anterior (trocar "." por ","), mas agora suportamos prefixo/sufixo.
|
|
||||||
const numero = String(dados?.numero).replace(".", ",")
|
|
||||||
const prefixo = dados?.prefixo?.trim()
|
|
||||||
const sufixo = dados?.sufixo?.trim()
|
|
||||||
|
|
||||||
const inicio = prefixo ? `${prefixo} ` : ""
|
|
||||||
const fim = sufixo ? ` ${sufixo}` : ""
|
|
||||||
|
|
||||||
return `${inicio}${numero}${fim}`
|
|
||||||
})
|
|
||||||
|
|
||||||
return { dados, textoNumero }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__celula-link {
|
|
||||||
all: unset;
|
|
||||||
display: inline;
|
|
||||||
color: #2563eb;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: rgba(37, 99, 235, 0.55);
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:hover {
|
|
||||||
color: #1d4ed8;
|
|
||||||
text-decoration-color: rgba(29, 78, 216, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="eli-tabela__celula-tags">
|
|
||||||
<v-chip
|
|
||||||
v-for="(tag, idx) in dados?.opcoes ?? []"
|
|
||||||
:key="idx"
|
|
||||||
class="eli-tabela__celula-tag"
|
|
||||||
size="small"
|
|
||||||
variant="tonal"
|
|
||||||
:color="tag.cor"
|
|
||||||
:clickable="Boolean(tag.acao)"
|
|
||||||
@click.stop.prevent="tag.acao?.()"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="tag.icone"
|
|
||||||
v-if="tag.icone"
|
|
||||||
class="eli-tabela__celula-tag-icone"
|
|
||||||
:size="14"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span>{{ tag.rotulo }}</span>
|
|
||||||
</v-chip>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import { VChip } from "vuetify/components"
|
|
||||||
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelulaTags",
|
|
||||||
components: { VChip },
|
|
||||||
props: {
|
|
||||||
dados: {
|
|
||||||
type: Object as PropType<tiposTabelaCelulas["tags"]>,
|
|
||||||
required: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup({ dados }) {
|
|
||||||
return { dados }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__celula-tags {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 6px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-tag {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-tag-icone {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
<template>
|
|
||||||
<button
|
|
||||||
v-if="dados?.acao"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__celula-link"
|
|
||||||
@click.stop.prevent="dados.acao()"
|
|
||||||
>
|
|
||||||
{{ dados?.texto }}
|
|
||||||
</button>
|
|
||||||
<span v-else>{{ dados?.texto }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelulaTextoSimples",
|
|
||||||
components: {},
|
|
||||||
props: {
|
|
||||||
dados: {
|
|
||||||
type: Object as PropType<tiposTabelaCelulas["textoSimples"]>,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
methods: {},
|
|
||||||
setup({ dados }) {
|
|
||||||
return { dados }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__celula-link {
|
|
||||||
all: unset;
|
|
||||||
display: inline;
|
|
||||||
color: #2563eb;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: rgba(37, 99, 235, 0.55);
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:hover {
|
|
||||||
color: #1d4ed8;
|
|
||||||
text-decoration-color: rgba(29, 78, 216, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<template>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-if="dados?.acao"
|
|
||||||
type="button"
|
|
||||||
class="eli-tabela__texto-truncado eli-tabela__celula-link"
|
|
||||||
:title="dados?.texto"
|
|
||||||
@click.stop.prevent="dados?.acao?.()"
|
|
||||||
>
|
|
||||||
{{ dados?.texto }}
|
|
||||||
</button>
|
|
||||||
<span v-else class="eli-tabela__texto-truncado" :title="dados?.texto">{{ dados?.texto }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, type PropType } from "vue"
|
|
||||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
name: "EliTabelaCelulaTextoTruncado",
|
|
||||||
props: {
|
|
||||||
dados: {
|
|
||||||
type: Object as PropType<tiposTabelaCelulas["textoTruncado"]>,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
setup({ dados }) {
|
|
||||||
return { dados }
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.eli-tabela__texto-truncado {
|
|
||||||
display: inline-block;
|
|
||||||
max-width: 260px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link {
|
|
||||||
all: unset;
|
|
||||||
display: inline;
|
|
||||||
color: #2563eb;
|
|
||||||
cursor: pointer;
|
|
||||||
text-decoration: underline;
|
|
||||||
text-decoration-color: rgba(37, 99, 235, 0.55);
|
|
||||||
text-underline-offset: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:hover {
|
|
||||||
color: #1d4ed8;
|
|
||||||
text-decoration-color: rgba(29, 78, 216, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.eli-tabela__celula-link:focus-visible {
|
|
||||||
outline: 2px solid rgba(37, 99, 235, 0.45);
|
|
||||||
outline-offset: 2px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
# Células da EliTabela
|
|
||||||
|
|
||||||
Este diretório contém os componentes de **célula** usados pela `EliTabela`.
|
|
||||||
|
|
||||||
## Como funcionam as células
|
|
||||||
|
|
||||||
A `EliTabela` não renderiza o conteúdo direto: cada coluna retorna uma tupla tipada via helper:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { celulaTabela } from "@/componentes/EliTabela";
|
|
||||||
|
|
||||||
celula: (linha) => celulaTabela("textoSimples", { texto: linha.nome })
|
|
||||||
```
|
|
||||||
|
|
||||||
O `tipo` seleciona qual componente de célula será usado (via registry) e o `dados` define o payload tipado.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Tipos disponíveis
|
|
||||||
|
|
||||||
### 1) `textoSimples`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{ texto: string; acao?: () => void }
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2) `textoTruncado`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{ texto: string; acao?: () => void }
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3) `numero`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{ numero: number; prefixo?: string; sufixo?: string; acao?: () => void }
|
|
||||||
```
|
|
||||||
|
|
||||||
Exemplos:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// moeda
|
|
||||||
celula: (l) => celulaTabela("numero", { numero: l.total, prefixo: "R$" })
|
|
||||||
|
|
||||||
// unidade de medida
|
|
||||||
celula: (l) => celulaTabela("numero", { numero: l.peso, sufixo: "kg" })
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4) `tags`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{
|
|
||||||
opcoes: {
|
|
||||||
rotulo: string;
|
|
||||||
cor?: string;
|
|
||||||
icone?: import("lucide-vue-next").LucideIcon;
|
|
||||||
acao?: () => void;
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5) `data`
|
|
||||||
|
|
||||||
```ts
|
|
||||||
{ valor: string; formato: "data" | "data_hora" | "relativo"; acao?: () => void }
|
|
||||||
```
|
|
||||||
|
|
||||||
Exemplos:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
celula: (l) => celulaTabela("data", { valor: l.criado_em, formato: "data" })
|
|
||||||
celula: (l) => celulaTabela("data", { valor: l.criado_em, formato: "data_hora" })
|
|
||||||
celula: (l) => celulaTabela("data", { valor: l.atualizado_em, formato: "relativo" })
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Onde ficam os tipos e o registry
|
|
||||||
|
|
||||||
- Tipos: `src/componentes/EliTabela/celulas/tiposTabelaCelulas.ts`
|
|
||||||
- Registry: `src/componentes/EliTabela/celulas/registryTabelaCelulas.ts`
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
import type { Component } from "vue"
|
|
||||||
import EliTabelaCelulaData from "./EliTabelaCelulaData.vue"
|
|
||||||
import EliTabelaCelulaNumero from "./EliTabelaCelulaNumero.vue"
|
|
||||||
import EliTabelaCelulaTags from "./EliTabelaCelulaTags.vue"
|
|
||||||
import EliTabelaCelulaTextoSimples from "./EliTabelaCelulaTextoSimples.vue"
|
|
||||||
import EliTabelaCelulaTextoTruncado from "./EliTabelaCelulaTextoTruncado.vue"
|
|
||||||
import type { tipoTabelaCelula } from "./tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export const registryTabelaCelulas = {
|
|
||||||
textoSimples: EliTabelaCelulaTextoSimples,
|
|
||||||
textoTruncado: EliTabelaCelulaTextoTruncado,
|
|
||||||
numero: EliTabelaCelulaNumero,
|
|
||||||
tags: EliTabelaCelulaTags,
|
|
||||||
data: EliTabelaCelulaData,
|
|
||||||
} as const satisfies Record<tipoTabelaCelula, Component>
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
/**
|
|
||||||
* Tipagem dos dados de entrada dos componentes de celulas
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { LucideIcon } from "lucide-vue-next"
|
|
||||||
|
|
||||||
export type tiposTabelaCelulas = {
|
|
||||||
textoSimples: {
|
|
||||||
texto: string
|
|
||||||
acao?: () => void
|
|
||||||
}
|
|
||||||
textoTruncado: {
|
|
||||||
texto: string
|
|
||||||
acao?: () => void
|
|
||||||
}
|
|
||||||
numero: {
|
|
||||||
numero: number
|
|
||||||
/** Texto opcional exibido antes do número (ex.: "R$", "≈"). */
|
|
||||||
prefixo?: string
|
|
||||||
/** Texto opcional exibido depois do número (ex.: "kg", "%"). */
|
|
||||||
sufixo?: string
|
|
||||||
acao?: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
tags: {
|
|
||||||
opcoes: {
|
|
||||||
/** Texto exibido dentro da tag. */
|
|
||||||
rotulo: string
|
|
||||||
/** Cor do chip (segue as cores do Vuetify, ex.: "primary", "success", "error"). */
|
|
||||||
cor?: string
|
|
||||||
/** Ícone (Lucide) opcional exibido antes do rótulo. */
|
|
||||||
icone?: LucideIcon
|
|
||||||
/** Ação opcional da tag. Quando existir, o chip vira clicável. */
|
|
||||||
acao?: () => void
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
data: {
|
|
||||||
/** Valor em ISO 8601 (ex.: "2026-01-09T16:15:00Z"). */
|
|
||||||
valor: string
|
|
||||||
/** Define o formato de exibição. */
|
|
||||||
formato: "data" | "data_hora" | "relativo"
|
|
||||||
/** Ação opcional ao clicar no valor. */
|
|
||||||
acao?: () => void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type tipoTabelaCelula = keyof tiposTabelaCelulas
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
export type EliTabelaColunasConfig = {
|
|
||||||
/** Rotulos das colunas visiveis (em ordem). */
|
|
||||||
visiveis: string[]
|
|
||||||
/** Rotulos das colunas invisiveis. */
|
|
||||||
invisiveis: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const STORAGE_PREFIX = "eli:tabela"
|
|
||||||
|
|
||||||
export function storageKeyColunas(nomeTabela: string) {
|
|
||||||
return `${STORAGE_PREFIX}:${nomeTabela}:colunas`
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizarConfig(valor: unknown): EliTabelaColunasConfig {
|
|
||||||
if (!valor || typeof valor !== "object") {
|
|
||||||
return { visiveis: [], invisiveis: [] }
|
|
||||||
}
|
|
||||||
|
|
||||||
const v = valor as EliTabelaColunasConfig
|
|
||||||
const visiveis = Array.isArray(v.visiveis)
|
|
||||||
? v.visiveis.filter((x: unknown) => typeof x === "string")
|
|
||||||
: []
|
|
||||||
const invisiveis = Array.isArray(v.invisiveis)
|
|
||||||
? v.invisiveis.filter((x: unknown) => typeof x === "string")
|
|
||||||
: []
|
|
||||||
return { visiveis, invisiveis }
|
|
||||||
}
|
|
||||||
|
|
||||||
export function carregarConfigColunas(
|
|
||||||
nomeTabela: string,
|
|
||||||
): EliTabelaColunasConfig {
|
|
||||||
try {
|
|
||||||
const raw = window.localStorage.getItem(storageKeyColunas(nomeTabela))
|
|
||||||
if (!raw) return { visiveis: [], invisiveis: [] }
|
|
||||||
return normalizarConfig(JSON.parse(raw))
|
|
||||||
} catch {
|
|
||||||
return { visiveis: [], invisiveis: [] }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function salvarConfigColunas(
|
|
||||||
nomeTabela: string,
|
|
||||||
config: EliTabelaColunasConfig,
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
window.localStorage.setItem(
|
|
||||||
storageKeyColunas(nomeTabela),
|
|
||||||
JSON.stringify(normalizarConfig(config)),
|
|
||||||
)
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function limparConfigColunas(nomeTabela: string) {
|
|
||||||
try {
|
|
||||||
window.localStorage.removeItem(storageKeyColunas(nomeTabela))
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
export type EliTabelaFiltroAvancadoSalvo<T> = Array<{
|
|
||||||
coluna: keyof T
|
|
||||||
|
|
||||||
valor: T[keyof T]
|
|
||||||
}>
|
|
||||||
|
|
||||||
function key(nomeTabela: string) {
|
|
||||||
return `eli_tabela:${nomeTabela}:filtro_avancado`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function carregarFiltroAvancado<T>(
|
|
||||||
nomeTabela: string,
|
|
||||||
): EliTabelaFiltroAvancadoSalvo<T> {
|
|
||||||
try {
|
|
||||||
const raw = localStorage.getItem(key(nomeTabela))
|
|
||||||
if (!raw) return [] as unknown as EliTabelaFiltroAvancadoSalvo<T>
|
|
||||||
const parsed = JSON.parse(raw)
|
|
||||||
return Array.isArray(parsed)
|
|
||||||
? (parsed as EliTabelaFiltroAvancadoSalvo<T>)
|
|
||||||
: ([] as unknown as EliTabelaFiltroAvancadoSalvo<T>)
|
|
||||||
} catch {
|
|
||||||
return [] as unknown as EliTabelaFiltroAvancadoSalvo<T>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function salvarFiltroAvancado<T>(
|
|
||||||
nomeTabela: string,
|
|
||||||
filtros: EliTabelaFiltroAvancadoSalvo<T>,
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
localStorage.setItem(key(nomeTabela), JSON.stringify(filtros ?? []))
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function limparFiltroAvancado(nomeTabela: string) {
|
|
||||||
try {
|
|
||||||
localStorage.removeItem(key(nomeTabela))
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
export * from "./celulas/tiposTabelaCelulas"
|
|
||||||
export { default as EliTabela } from "./EliTabela.vue"
|
|
||||||
export * from "./types-eli-tabela"
|
|
||||||
|
|
||||||
// Helper para construção de células tipadas.
|
|
||||||
export { celulaTabela } from "./types-eli-tabela"
|
|
||||||
|
|
@ -1,155 +0,0 @@
|
||||||
import type { LucideIcon } from "lucide-vue-next"
|
|
||||||
import type { tipoFiltro26 } from "p-comuns"
|
|
||||||
|
|
||||||
export type tipoFiltro<T> = tipoFiltro26<T>
|
|
||||||
|
|
||||||
import type { tipoResposta } from "p-respostas"
|
|
||||||
import type { ComponenteEntrada } from "../EliEntrada/tiposEntradas"
|
|
||||||
import type {
|
|
||||||
tiposTabelaCelulas,
|
|
||||||
tipoTabelaCelula,
|
|
||||||
} from "./celulas/tiposTabelaCelulas"
|
|
||||||
|
|
||||||
export type tipoComponenteCelulaBase<T extends tipoTabelaCelula> = readonly [
|
|
||||||
T,
|
|
||||||
tiposTabelaCelulas[T],
|
|
||||||
]
|
|
||||||
|
|
||||||
export type tipoComponenteCelula = {
|
|
||||||
[K in tipoTabelaCelula]: tipoComponenteCelulaBase<K>
|
|
||||||
}[tipoTabelaCelula]
|
|
||||||
|
|
||||||
export const celulaTabela = <T extends tipoTabelaCelula>(
|
|
||||||
tipo: T,
|
|
||||||
dados: tiposTabelaCelulas[T],
|
|
||||||
): tipoComponenteCelulaBase<T> => {
|
|
||||||
return [tipo, dados] as const
|
|
||||||
}
|
|
||||||
|
|
||||||
export type { tipoTabelaCelula, tiposTabelaCelulas }
|
|
||||||
|
|
||||||
export type tipoEliColuna<T> = {
|
|
||||||
/** Texto exibido no cabeçalho da coluna. */
|
|
||||||
rotulo: string
|
|
||||||
/** Função responsável por renderizar o conteúdo da célula. */
|
|
||||||
celula: (linha: T) => tipoComponenteCelula
|
|
||||||
/** Ação opcional disparada ao clicar na célula. */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Campo de ordenação associado à coluna. Caso informado, a coluna passa a
|
|
||||||
* exibir controles de ordenação e utiliza o valor como chave para o backend.
|
|
||||||
*/
|
|
||||||
coluna_ordem?: keyof T
|
|
||||||
|
|
||||||
/**
|
|
||||||
* indica que a coluna será visivel, se false incia em detalhe
|
|
||||||
* Caso já tenha salvo a propriedade de visibilidade será adotado a propriedade salva
|
|
||||||
*/
|
|
||||||
visivel: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export type tipoEliConsultaPaginada<T> = {
|
|
||||||
/** Registros retornados na consulta. */
|
|
||||||
valores: T[]
|
|
||||||
/** Total de registros disponíveis no backend. */
|
|
||||||
quantidade: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export type tipoEliTabelaAcao<T> = {
|
|
||||||
/** Ícone (Lucide) exibido para representar a ação. */
|
|
||||||
icone: LucideIcon
|
|
||||||
/** Cor aplicada ao ícone e rótulo. */
|
|
||||||
cor: string
|
|
||||||
/** Texto descritivo da ação. */
|
|
||||||
rotulo: string
|
|
||||||
/** Função executada quando o usuário ativa a ação. */
|
|
||||||
acao: (linha: T) => void
|
|
||||||
/**
|
|
||||||
* Define se a ação deve ser exibida para a linha. Pode ser um booleano fixo
|
|
||||||
* ou uma função (sincrona/assíncrona) que recebe a linha para decisão dinâmica.
|
|
||||||
*/
|
|
||||||
exibir?: boolean | ((linha: T) => Promise<boolean> | boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
export type parametrosConsulta<T> = {
|
|
||||||
filtros?: tipoFiltro26<T>[]
|
|
||||||
coluna_ordem?: keyof T
|
|
||||||
direcao_ordem?: "asc" | "desc"
|
|
||||||
offSet?: number
|
|
||||||
limit?: number
|
|
||||||
/** Texto digitado na caixa de busca, quando habilitada. */
|
|
||||||
texto_busca?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Estrutura de dados para uma tabela alimentada por uma consulta.
|
|
||||||
*
|
|
||||||
* - `colunas`: definição de colunas e como renderizar cada célula
|
|
||||||
* - `consulta`: função que recupera os dados, com suporte a ordenação/paginação
|
|
||||||
* - `mostrarCaixaDeBusca`: habilita um campo de busca textual no cabeçalho
|
|
||||||
*/
|
|
||||||
export type tipoEliTabelaConsulta<T> = {
|
|
||||||
/** nome da tabela, um identificador unico */
|
|
||||||
nome: string
|
|
||||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
|
||||||
mostrarCaixaDeBusca?: boolean
|
|
||||||
/** Lista de colunas da tabela. */
|
|
||||||
colunas: tipoEliColuna<T>[]
|
|
||||||
/** Quantidade de registros solicitados por consulta (padrão `10`). */
|
|
||||||
registros_por_consulta?: number
|
|
||||||
/**
|
|
||||||
* Função responsável por buscar os dados. Recebe parâmetros opcionais de
|
|
||||||
* ordenação (`coluna_ordem`/`direcao_ordem`) e paginação (`offSet`/`limit`).
|
|
||||||
*/
|
|
||||||
consulta: (
|
|
||||||
parametrosConsulta?: parametrosConsulta<T>,
|
|
||||||
) => Promise<tipoResposta<tipoEliConsultaPaginada<T>>>
|
|
||||||
/** Quantidade máxima de botões exibidos na paginação (padrão `7`). */
|
|
||||||
maximo_botoes_paginacao?: number
|
|
||||||
/** Mensagem exibida quando a consulta retorna ok porém sem dados. */
|
|
||||||
mensagemVazio?: string
|
|
||||||
/** Ações exibidas à direita de cada linha. */
|
|
||||||
acoesLinha?: tipoEliTabelaAcao<T>[]
|
|
||||||
/**
|
|
||||||
* Configurações dos botões que serão inseridos a direita da caixa de busca.
|
|
||||||
* Seu uso mais comum será para criar novos registros, mas poderá ter outras utilidades.
|
|
||||||
*/
|
|
||||||
acoesTabela?: {
|
|
||||||
/** superio será exibido a direita da caixa de busca, inferior a direita da paginação */
|
|
||||||
posicao: "superior" | "inferior"
|
|
||||||
|
|
||||||
/** Ícone (Lucide) exibido no botão */
|
|
||||||
icone?: LucideIcon
|
|
||||||
/** Cor aplicada ao botão. */
|
|
||||||
cor?: string
|
|
||||||
/** Texto descritivo da ação. */
|
|
||||||
rotulo: string
|
|
||||||
/** Função executada ao clicar no botão. */
|
|
||||||
|
|
||||||
acao: (
|
|
||||||
parametrosConsulta: parametrosConsulta<T> & {
|
|
||||||
/**
|
|
||||||
* Callback opcional para forçar atualização da consulta.
|
|
||||||
* Observação: o componente `EliTabela` pode ignorar isso dependendo do modo de uso.
|
|
||||||
*/
|
|
||||||
atualizarConsulta: () => Promise<void>
|
|
||||||
/**
|
|
||||||
* Callback opcional para permitir editar a lista localmente (sem refazer consulta).
|
|
||||||
* Observação: o componente `EliTabela` pode ignorar isso dependendo do modo de uso.
|
|
||||||
*/
|
|
||||||
editarLista: (lista: T[]) => Promise<T[]>
|
|
||||||
},
|
|
||||||
) => void
|
|
||||||
}[]
|
|
||||||
|
|
||||||
filtroAvancado?: {
|
|
||||||
/** Identificador único do filtro (usado para persistência) */
|
|
||||||
chave: string
|
|
||||||
/** Rótulo exibido no select de adicionar filtro */
|
|
||||||
rotulo: string
|
|
||||||
/** vai gerar filtro e mescla com os filtros já existentes */
|
|
||||||
filtro: (valor: unknown) => tipoFiltro26<T>
|
|
||||||
/** componente de entrada que vai receber o valor para o filtro */
|
|
||||||
entrada: ComponenteEntrada
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<v-btn
|
<v-btn
|
||||||
:color="color"
|
:color="color"
|
||||||
:variant="variant"
|
:variant="variant"
|
||||||
:size="size"
|
:size="size"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
class="eli-botao text-none pt-1"
|
class="text-none pt-1"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, type PropType } from "vue"
|
import { defineComponent, PropType } from "vue";
|
||||||
import type { BotaoTamanho, BotaoVariante } from "../../tipos"
|
import type { BotaoTamanho, BotaoVariante } from "../../tipos";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "EliBotao",
|
name: "EliBotao",
|
||||||
|
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
inheritAttrs: false,
|
props: {
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "primary"
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
variant: {
|
||||||
color: {
|
type: String as PropType<BotaoVariante>,
|
||||||
type: String,
|
default: "elevated",
|
||||||
default: "primary",
|
},
|
||||||
},
|
|
||||||
|
|
||||||
variant: {
|
size: {
|
||||||
type: String as PropType<BotaoVariante>,
|
type: String as PropType<BotaoTamanho>,
|
||||||
default: "elevated",
|
|
||||||
},
|
|
||||||
|
|
||||||
size: {
|
|
||||||
type: String as PropType<BotaoTamanho>,
|
|
||||||
default: "default",
|
default: "default",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -46,6 +46,7 @@ export default defineComponent({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { default as EliBotao } from "./EliBotao.vue"
|
export { default as EliBotao } from "./EliBotao.vue";
|
||||||
|
|
|
||||||
297
src/componentes/campo/EliInput.vue
Normal file
297
src/componentes/campo/EliInput.vue
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
<template>
|
||||||
|
<div class="eli-input">
|
||||||
|
<!-- TEXT LIKE INPUTS -->
|
||||||
|
<v-text-field
|
||||||
|
v-if="isTextLike"
|
||||||
|
v-model="value"
|
||||||
|
:type="inputHtmlType"
|
||||||
|
:label="label"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:disabled="disabled"
|
||||||
|
:clearable="clearable && type !== 'password'"
|
||||||
|
:error="error"
|
||||||
|
:error-messages="errorMessages"
|
||||||
|
:hint="hint"
|
||||||
|
:persistent-hint="persistentHint"
|
||||||
|
:density="density"
|
||||||
|
:variant="variant"
|
||||||
|
:color="internalColor"
|
||||||
|
:inputmode="inputMode"
|
||||||
|
v-bind="attrs"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="onBlur"
|
||||||
|
@input="onInput"
|
||||||
|
>
|
||||||
|
<!-- PASSWORD TOGGLE -->
|
||||||
|
<template
|
||||||
|
v-if="type === 'password' && showPasswordToggle"
|
||||||
|
#append-inner
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="cursor-pointer"
|
||||||
|
@click="togglePassword"
|
||||||
|
>
|
||||||
|
{{ showPassword ? "mdi-eye-off" : "mdi-eye" }}
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-text-field>
|
||||||
|
|
||||||
|
<!-- TEXTAREA -->
|
||||||
|
<v-textarea
|
||||||
|
v-else-if="type === 'textarea'"
|
||||||
|
v-model="value"
|
||||||
|
:label="label"
|
||||||
|
:rows="rows"
|
||||||
|
:density="density"
|
||||||
|
:variant="variant"
|
||||||
|
v-bind="attrs"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- SELECT -->
|
||||||
|
<v-select
|
||||||
|
v-else-if="type === 'select'"
|
||||||
|
v-model="value"
|
||||||
|
:items="computedItems"
|
||||||
|
:label="label"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:multiple="multiple"
|
||||||
|
:chips="chips"
|
||||||
|
:clearable="clearable"
|
||||||
|
:disabled="disabled"
|
||||||
|
:density="density"
|
||||||
|
:variant="variant"
|
||||||
|
item-title="label"
|
||||||
|
item-value="value"
|
||||||
|
:error="error"
|
||||||
|
:error-messages="errorMessages"
|
||||||
|
v-bind="attrs"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="onBlur"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- RADIO -->
|
||||||
|
<v-radio-group
|
||||||
|
v-else-if="type === 'radio'"
|
||||||
|
v-model="value"
|
||||||
|
:row="row"
|
||||||
|
>
|
||||||
|
<v-radio
|
||||||
|
v-for="opt in computedItems"
|
||||||
|
:key="String(opt.value)"
|
||||||
|
:label="opt.label"
|
||||||
|
:value="opt.value"
|
||||||
|
/>
|
||||||
|
</v-radio-group>
|
||||||
|
|
||||||
|
<!-- CHECKBOX -->
|
||||||
|
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
||||||
|
<v-checkbox
|
||||||
|
v-for="opt in computedItems"
|
||||||
|
:key="String(opt.value)"
|
||||||
|
v-model="value"
|
||||||
|
:label="opt.label"
|
||||||
|
:value="opt.value"
|
||||||
|
:density="density"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, computed, PropType } from "vue";
|
||||||
|
import type {
|
||||||
|
CampoDensidade,
|
||||||
|
CampoOpcao,
|
||||||
|
CampoOpcaoBruta,
|
||||||
|
CampoTipo,
|
||||||
|
CampoValor,
|
||||||
|
CampoValorMultiplo,
|
||||||
|
CampoVariante,
|
||||||
|
} from "../../tipos";
|
||||||
|
import { formatarCpfCnpj } from "./utils/cpfCnpj";
|
||||||
|
import { formatTelefone } from "./utils/telefone";
|
||||||
|
import { formatarDecimal, formatarMoeda, somenteNumeros } from "./utils/numerico"
|
||||||
|
import { formatarCep } from "./utils/cep";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: "EliInput",
|
||||||
|
inheritAttrs: false,
|
||||||
|
|
||||||
|
props: {
|
||||||
|
/**
|
||||||
|
* Aceita valor simples (text-like) ou lista de valores (checkbox/select multiple).
|
||||||
|
* O componente não converte tipos automaticamente: mantém o que receber.
|
||||||
|
*/
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number, Boolean, Array] as PropType<CampoValor | CampoValorMultiplo>,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
type: { type: String as PropType<CampoTipo>, default: "text" },
|
||||||
|
label: String,
|
||||||
|
placeholder: String,
|
||||||
|
disabled: Boolean,
|
||||||
|
error: Boolean,
|
||||||
|
errorMessages: {
|
||||||
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
hint: String,
|
||||||
|
persistentHint: Boolean,
|
||||||
|
rows: { type: Number, default: 4 },
|
||||||
|
/**
|
||||||
|
* Para select/radio/checkbox.
|
||||||
|
* Aceita lista já normalizada ({ label, value }) ou valores primitivos.
|
||||||
|
*/
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<Array<CampoOpcaoBruta>>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
clearable: Boolean,
|
||||||
|
variant: { type: String as PropType<CampoVariante>, default: "outlined" },
|
||||||
|
density: { type: String as PropType<CampoDensidade>, default: "comfortable" },
|
||||||
|
color: { type: String, default: "primary" },
|
||||||
|
row: Boolean,
|
||||||
|
showPasswordToggle: Boolean,
|
||||||
|
multiple: Boolean,
|
||||||
|
chips: Boolean,
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ["update:modelValue", "change", "focus", "blur"],
|
||||||
|
|
||||||
|
setup(props, { emit, attrs }) {
|
||||||
|
const focused = ref(false);
|
||||||
|
const showPassword = ref(false);
|
||||||
|
|
||||||
|
const value = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (v: CampoValor | CampoValorMultiplo) => {
|
||||||
|
emit("update:modelValue", v);
|
||||||
|
emit("change", v);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const isTextLike = computed(() =>
|
||||||
|
[
|
||||||
|
"text",
|
||||||
|
"password",
|
||||||
|
"email",
|
||||||
|
"search",
|
||||||
|
"url",
|
||||||
|
"telefone",
|
||||||
|
"cpfCnpj",
|
||||||
|
"numericoInteiro",
|
||||||
|
"numericoDecimal",
|
||||||
|
"numericoMoeda",
|
||||||
|
"cep",
|
||||||
|
].includes(props.type)
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputHtmlType = computed(() =>
|
||||||
|
props.type === "password"
|
||||||
|
? showPassword.value
|
||||||
|
? "text"
|
||||||
|
: "password"
|
||||||
|
: "text"
|
||||||
|
);
|
||||||
|
|
||||||
|
const inputMode = computed(() => {
|
||||||
|
if (props.type === "telefone") return "tel";
|
||||||
|
if (props.type.startsWith("numerico")) return "numeric";
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const internalColor = computed(() =>
|
||||||
|
props.error ? "error" : focused.value ? props.color : undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
function onInput(e: Event) {
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
let resultado = target.value;
|
||||||
|
|
||||||
|
switch (props.type) {
|
||||||
|
case "numericoInteiro":
|
||||||
|
resultado = somenteNumeros(resultado);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "numericoDecimal":
|
||||||
|
resultado = formatarDecimal(resultado);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "numericoMoeda":
|
||||||
|
resultado = formatarMoeda(resultado);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "telefone":
|
||||||
|
resultado = formatTelefone(resultado);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "cpfCnpj":
|
||||||
|
resultado = formatarCpfCnpj(resultado);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "cep":
|
||||||
|
resultado = formatarCep(resultado);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.value = resultado;
|
||||||
|
emit("update:modelValue", resultado);
|
||||||
|
emit("change", resultado);
|
||||||
|
}
|
||||||
|
|
||||||
|
function togglePassword() {
|
||||||
|
showPassword.value = !showPassword.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Helpers para select / radio / checkbox (aceita objetos ou primitivos) ---
|
||||||
|
const computedItems = computed<Array<CampoOpcao>>(() => {
|
||||||
|
// Normaliza options para [{ label, value, disabled? }]
|
||||||
|
return (props.options || []).map((o) => {
|
||||||
|
if (o && typeof o === "object" && "value" in o) {
|
||||||
|
const valor = o.value as CampoValor;
|
||||||
|
return {
|
||||||
|
label: o.label ?? String(valor),
|
||||||
|
value: valor,
|
||||||
|
disabled: o.disabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const valor = o as CampoValor;
|
||||||
|
return { label: String(valor), value: valor };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
attrs,
|
||||||
|
value,
|
||||||
|
isTextLike,
|
||||||
|
inputHtmlType,
|
||||||
|
inputMode,
|
||||||
|
internalColor,
|
||||||
|
showPassword,
|
||||||
|
togglePassword,
|
||||||
|
onInput,
|
||||||
|
onFocus: () => emit("focus"),
|
||||||
|
onBlur: () => emit("blur"),
|
||||||
|
computedItems,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.eli-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
117
src/componentes/campo/README.md
Normal file
117
src/componentes/campo/README.md
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
# EliInput
|
||||||
|
|
||||||
|
**Componente base de input do design system**
|
||||||
|
|
||||||
|
O EliInput unifica vários tipos de campo (v-text-field, v-textarea, v-select, v-radio-group, v-checkbox) em uma única API consistente. Ele encapsula comportamentos, máscaras e regras comuns (CPF/CNPJ, telefone, CEP, numéricos, formatação de moeda etc.) para manter coerência visual e de lógica em toda a aplicação.
|
||||||
|
|
||||||
|
> ⚠️ Nunca use os componentes Vuetify diretamente fora do design system para esses casos.
|
||||||
|
> Utilize sempre EliInput para garantir formatação, tipagem e repasse de atributos padronizados.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visão geral
|
||||||
|
|
||||||
|
EliInput foi projetado para:
|
||||||
|
|
||||||
|
* Centralizar formatação (máscaras) para tipos de entrada comuns (telefone, CPF/CNPJ, CEP, numéricos).
|
||||||
|
* Fornecer uma API única (type) que representa diferentes controles (text, textarea, select, radio, checkbox, etc.).
|
||||||
|
* Repassar atributos/props do pai para o componente Vuetify interno (v-bind="$attrs") mantendo inheritAttrs: false.
|
||||||
|
* Emitir eventos padronizados: update:modelValue, change, focus, blur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Principais decisões de implementação
|
||||||
|
|
||||||
|
* inheritAttrs: false — o componente controla explicitamente para onde os atributos são passados (v-bind="attrs" no elemento interno).
|
||||||
|
* Uso de um computed value que faz emit("update:modelValue", v) e emit("change", v) — assim qualquer v-model no pai funciona como esperado.
|
||||||
|
* Normalização de props.options para aceitar objetos { label, value, disabled } ou primitivos ('A', 1).
|
||||||
|
* Separação clara entre lógica de formatação (aplicada em onInput) e componentes que não devem ser formatados (ex.: v-select).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tipagem (TypeScript)
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type ValorCampo = string | number | boolean | null;
|
||||||
|
type Option = { label: string; value: ValorCampo; disabled?: boolean };
|
||||||
|
|
||||||
|
type InputVariant = 'outlined' | 'filled' | 'plain' | 'solo' | 'solo-filled' | 'solo-inverted' | 'underlined';
|
||||||
|
type Density = 'default' | 'comfortable' | 'compact';
|
||||||
|
type TipoNumerico = 'numericoInteiro' | 'numericoDecimal' | 'numericoMoeda';
|
||||||
|
|
||||||
|
type InputType =
|
||||||
|
| 'text' | 'password' | 'email' | 'search' | 'url' | 'textarea'
|
||||||
|
| 'radio' | 'checkbox' | 'telefone' | 'cpfCnpj' | 'cep' | 'select'
|
||||||
|
| TipoNumerico;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
| Prop | Tipo | Default | Descrição |
|
||||||
|
| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
|
||||||
|
| `modelValue` | `string \| number \| boolean \| (string \| number \| boolean \| null)[]` | `""` | Valor controlado (use com `v-model`). |
|
||||||
|
| `type` | `InputType` | `"text"` | Tipo do controle (ver `InputType`). |
|
||||||
|
| `label` | `string` | `-` | Rótulo do campo. |
|
||||||
|
| `placeholder` | `string` | `-` | Texto exibido quando o campo está vazio. |
|
||||||
|
| `disabled` | `boolean` | `false` | Desabilita o campo. |
|
||||||
|
| `error` | `boolean` | `false` | Força estado visual de erro. |
|
||||||
|
| `errorMessages` | `string \| string[]` | `[]` | Mensagem ou lista de mensagens de erro. |
|
||||||
|
| `hint` | `string` | `-` | Texto de ajuda exibido abaixo do campo. |
|
||||||
|
| `persistentHint` | `boolean` | `false` | Mantém o hint sempre visível. |
|
||||||
|
| `variant` | `InputVariant` | `"outlined"` | Variante visual do Vuetify. |
|
||||||
|
| `density` | `Density` | `"comfortable"` | Densidade visual do campo. |
|
||||||
|
| `color` | `string` | `"primary"` | Cor do campo quando focado (ou `error`, se aplicável). |
|
||||||
|
| `clearable` | `boolean` | `false` | Permite limpar o valor do campo. |
|
||||||
|
|
||||||
|
|
||||||
|
## Notas sobre props
|
||||||
|
|
||||||
|
* options: aceita arrays como ['Frontend','Backend'] ou { label:'São Paulo', value:'SP' }. O componente normaliza para { label, value, disabled? }.
|
||||||
|
* type determina quais comportamentos internos são aplicados. Tipos numéricos e máscara (telefone, cpfCnpj, cep) passam por formatação em onInput.
|
||||||
|
* multiple/chips: úteis para type="select". O v-select interno recebe item-title="label" e item-value="value" para compatibilidade com objetos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Emissões (events)
|
||||||
|
|
||||||
|
* update:modelValue — padrão v-model.
|
||||||
|
* change — emitido sempre que o valor muda (alinha com update:modelValue).
|
||||||
|
* focus — quando o campo interno recebe foco.
|
||||||
|
* blur — quando perde o foco.
|
||||||
|
* Observação: como value é um computed com getter/setter que emite ambos, v-model e listeners de mudança no pai funcionarão normalmente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repasso de atributos e listeners
|
||||||
|
|
||||||
|
* O componente define inheritAttrs: false e usa v-bind="attrs" nos componentes internos (v-text-field, v-select, etc.). Isso implica que:
|
||||||
|
* Atributos HTML (ex.: type, aria-label, class, style) passados para <EliInput> são aplicados ao componente Vuetify interno apropriado.
|
||||||
|
* Listeners (ex.: @click, @keydown) também fazem parte de $attrs e serão repassados para o componente interno — use o EliInput como se estivesse ouvindo eventos diretamente no input.
|
||||||
|
|
||||||
|
## Exemplo:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<EliInput type="text" v-model="nome" aria-label="Nome completo" @keydown.enter="enviar" />
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comportamentos de formatação importantes
|
||||||
|
|
||||||
|
* numericoInteiro — remove tudo que não for dígito.
|
||||||
|
* numericoDecimal — mantém separador decimal (aplica formatarDecimal).
|
||||||
|
* numericoMoeda — formata para moeda conforme util (formatarMoeda).
|
||||||
|
* telefone — aplica máscara/format formatTelefone.
|
||||||
|
* cpfCnpj — aplica formatarCpfCnpj.
|
||||||
|
* cep — aplica formatarCep.
|
||||||
|
|
||||||
|
**Importante: a formatação ocorre no onInput (campos text-like). O v-select não passa por onInput — ele usa v-model="value" e o computed que emite o update. Se desejar formatação específica para itens do select (por exemplo, mostrar label formatado), trate nos options antes de passar.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Slot
|
||||||
|
|
||||||
|
* O componente não expõe slots customizados diretamente. Ele controla internamente o append para toggle de senha quando type === 'password' && showPasswordToggle (ícone de olho).
|
||||||
|
* Se você precisa de slots específicos do v-text-field/v-select, considere estender o componente ou criar uma variação que exponha os slots desejados.
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue