Adicionado celular do tipo componente
This commit is contained in:
parent
1446d6225b
commit
9b2651d5c7
17 changed files with 1386 additions and 1075 deletions
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<component v-if="propsResolvidas" :is="dados?.componente" v-bind="propsResolvidas" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, type PropType, ref } from "vue"
|
||||
import type { tiposTabelaCelulas } from "./tiposTabelaCelulas"
|
||||
|
||||
export default defineComponent({
|
||||
name: "EliTabelaCelulaComponente",
|
||||
props: {
|
||||
dados: {
|
||||
type: Object as PropType<tiposTabelaCelulas["componente"]>,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const propsResolvidas = ref<Record<string, unknown> | undefined>(undefined)
|
||||
|
||||
onMounted(async () => {
|
||||
if (!props.dados?.props) return
|
||||
const resultado = props.dados.props()
|
||||
propsResolvidas.value = resultado instanceof Promise ? await resultado : resultado
|
||||
})
|
||||
|
||||
return { propsResolvidas }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
@ -73,6 +73,118 @@ celula: (l) => celulaTabela("data", { valor: l.criado_em, formato: "data_hora" }
|
|||
celula: (l) => celulaTabela("data", { valor: l.atualizado_em, formato: "relativo" })
|
||||
```
|
||||
|
||||
### 6) `componente`
|
||||
|
||||
Renderiza um **componente Vue arbitrário** como conteúdo da célula.
|
||||
Use quando nenhum tipo pré-definido atende e você precisa de controle total sobre a renderização.
|
||||
|
||||
```ts
|
||||
{
|
||||
/** Componente Vue a ser renderizado na célula. */
|
||||
componente: Component;
|
||||
/**
|
||||
* Função que retorna as props do componente.
|
||||
* Pode retornar um objeto direto ou uma Promise (para resolver dados de API).
|
||||
*/
|
||||
props?: () => Promise<Record<string, unknown>> | Record<string, unknown>;
|
||||
}
|
||||
```
|
||||
|
||||
#### Uso básico (síncrono)
|
||||
|
||||
```ts
|
||||
import MeuBadge from "./MeuBadge.vue"
|
||||
|
||||
celula: (l) => celulaTabela("componente", {
|
||||
componente: MeuBadge,
|
||||
props: () => ({ status: l.status, cor: l.cor }),
|
||||
})
|
||||
```
|
||||
|
||||
#### Uso com API (assíncrono)
|
||||
|
||||
```ts
|
||||
import MeuDetalhe from "./MeuDetalhe.vue"
|
||||
|
||||
celula: (l) => celulaTabela("componente", {
|
||||
componente: MeuDetalhe,
|
||||
props: async () => {
|
||||
const dados = await api.get(`/detalhe/${l.codigo}`)
|
||||
return { detalhe: dados }
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
#### Exemplo: criando o componente `.vue`
|
||||
|
||||
```vue
|
||||
<!-- CelulaOlaNome.vue -->
|
||||
<template>
|
||||
<span class="celula-ola-nome">
|
||||
Olá, <strong>{{ nome }}</strong>!
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue"
|
||||
|
||||
export default defineComponent({
|
||||
name: "CelulaOlaNome",
|
||||
props: {
|
||||
nome: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.celula-ola-nome {
|
||||
font-size: 13px;
|
||||
color: #1e293b;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
#### Exemplo: usando na definição de colunas
|
||||
|
||||
```ts
|
||||
import CelulaOlaNome from "./CelulaOlaNome.vue"
|
||||
|
||||
celula: (l) => celulaTabela("componente", {
|
||||
componente: CelulaOlaNome,
|
||||
props: () => ({ nome: l.empreendedor }),
|
||||
})
|
||||
```
|
||||
|
||||
#### Quando usar
|
||||
|
||||
| Cenário | Use `componente`? |
|
||||
|---|---|
|
||||
| Texto simples ou truncado | ❌ Use `textoSimples` / `textoTruncado` |
|
||||
| Número com prefixo/sufixo | ❌ Use `numero` |
|
||||
| Chips/badges com ação | ❌ Use `tags` |
|
||||
| Data com formatação | ❌ Use `data` |
|
||||
| Barra de progresso, gráfico inline, badge complexo | ✅ Sim |
|
||||
| Componente com lógica interna (hover, tooltip, estado) | ✅ Sim |
|
||||
|
||||
#### Observações
|
||||
|
||||
- As **props não são tipadas** no contrato — é `Record<string, unknown>`. A responsabilidade de passar props corretas é do consumidor.
|
||||
- O componente é renderizado via `<component :is>` + `v-bind`, então suporta qualquer componente Vue válido (SFC, `defineComponent`, funcional).
|
||||
- Prefira sempre os tipos pré-definidos quando possível. O tipo `componente` é uma **escotilha de escape**, não o padrão.
|
||||
|
||||
---
|
||||
|
||||
## Como criar um novo tipo de célula pré-definido
|
||||
|
||||
Se o padrão de renderização se repete em múltiplas tabelas, considere promover de `componente` para um tipo próprio:
|
||||
|
||||
1. Criar `EliTabelaCelula<Tipo>.vue` neste diretório
|
||||
2. Adicionar a chave e tipagem em `tiposTabelaCelulas.ts`
|
||||
3. Registrar no mapa em `registryTabelaCelulas.ts`
|
||||
|
||||
---
|
||||
|
||||
## Onde ficam os tipos e o registry
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import type { Component } from "vue"
|
||||
import EliTabelaCelulaComponente from "./EliTabelaCelulaComponente.vue"
|
||||
import EliTabelaCelulaData from "./EliTabelaCelulaData.vue"
|
||||
import EliTabelaCelulaNumero from "./EliTabelaCelulaNumero.vue"
|
||||
import EliTabelaCelulaTags from "./EliTabelaCelulaTags.vue"
|
||||
|
|
@ -22,4 +23,5 @@ export const registryTabelaCelulas = {
|
|||
numero: EliTabelaCelulaNumero,
|
||||
tags: EliTabelaCelulaTags,
|
||||
data: EliTabelaCelulaData,
|
||||
componente: EliTabelaCelulaComponente,
|
||||
} as const satisfies Record<tipoTabelaCelula, Component>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
import type { LucideIcon } from "@lucide/vue"
|
||||
import type { Component } from "vue"
|
||||
|
||||
export type tiposTabelaCelulas = {
|
||||
textoSimples: {
|
||||
|
|
@ -43,6 +44,19 @@ export type tiposTabelaCelulas = {
|
|||
/** Ação opcional ao clicar no valor. */
|
||||
acao?: () => void
|
||||
}
|
||||
|
||||
/** Célula que renderiza um componente Vue arbitrário com props dinâmicas. */
|
||||
componente: {
|
||||
/** Componente Vue a ser renderizado na célula. */
|
||||
componente: Component
|
||||
/**
|
||||
* Props passadas ao componente via `v-bind`.
|
||||
* Aceita:
|
||||
* - objeto direto: `{ status: "ativo" }`
|
||||
* - função assíncrona: `() => api.get(...)` — útil quando é necessário resolver dados antes de renderizar
|
||||
*/
|
||||
props?: () => Promise<Record<string, unknown>> | Record<string, unknown>
|
||||
}
|
||||
}
|
||||
|
||||
export type tipoTabelaCelula = keyof tiposTabelaCelulas
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue