bkp
This commit is contained in:
parent
8c5a31ef30
commit
a693081023
34 changed files with 14887 additions and 1146 deletions
66
src/componentes/EliEntrada/EliEntradaParagrafo.vue
Normal file
66
src/componentes/EliEntrada/EliEntradaParagrafo.vue
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<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, 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, opcoes: props.opcoes };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
93
src/componentes/EliEntrada/EliEntradaSelecao.vue
Normal file
93
src/componentes/EliEntrada/EliEntradaSelecao.vue
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<v-select
|
||||
v-model="localValue"
|
||||
:label="opcoes?.rotulo"
|
||||
:placeholder="opcoes?.placeholder"
|
||||
:items="itens"
|
||||
item-title="rotulo"
|
||||
item-value="chave"
|
||||
:loading="carregando"
|
||||
:disabled="carregando"
|
||||
: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, 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();
|
||||
itens.value = Array.isArray(resultado) ? resultado : [];
|
||||
} finally {
|
||||
carregando.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Recarrega quando muda a função (caso o consumidor troque dinamicamente).
|
||||
watch(
|
||||
() => props.opcoes.itens,
|
||||
() => {
|
||||
void carregarItens();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
void carregarItens();
|
||||
});
|
||||
|
||||
return { attrs, emit, localValue, opcoes: props.opcoes, itens, carregando };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -121,6 +121,84 @@ Exemplo:
|
|||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 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):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import EliEntradaTexto from "./EliEntradaTexto.vue";
|
||||
import EliEntradaNumero from "./EliEntradaNumero.vue";
|
||||
import EliEntradaDataHora from "./EliEntradaDataHora.vue";
|
||||
import EliEntradaParagrafo from "./EliEntradaParagrafo.vue";
|
||||
import EliEntradaSelecao from "./EliEntradaSelecao.vue";
|
||||
|
||||
export { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora };
|
||||
export { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora, EliEntradaParagrafo, EliEntradaSelecao };
|
||||
export type { PadroesEntradas, TipoEntrada } from "./tiposEntradas";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import type { Component } from "vue";
|
|||
import EliEntradaTexto from "./EliEntradaTexto.vue";
|
||||
import EliEntradaNumero from "./EliEntradaNumero.vue";
|
||||
import EliEntradaDataHora from "./EliEntradaDataHora.vue";
|
||||
import EliEntradaParagrafo from "./EliEntradaParagrafo.vue";
|
||||
import EliEntradaSelecao from "./EliEntradaSelecao.vue";
|
||||
|
||||
import type { TipoEntrada } from "./tiposEntradas";
|
||||
|
||||
|
|
@ -10,4 +12,6 @@ export const registryTabelaCelulas = {
|
|||
texto: EliEntradaTexto,
|
||||
numero: EliEntradaNumero,
|
||||
dataHora: EliEntradaDataHora,
|
||||
paragrafo: EliEntradaParagrafo,
|
||||
selecao: EliEntradaSelecao,
|
||||
} as const satisfies Record<TipoEntrada, Component>;
|
||||
|
|
|
|||
|
|
@ -113,6 +113,72 @@ export type PadroesEntradas = {
|
|||
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
|
||||
}
|
||||
>
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
78
src/componentes/EliTabela/celulas/EliTabelaCelulaData.vue
Normal file
78
src/componentes/EliTabela/celulas/EliTabelaCelulaData.vue
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<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 { computed, defineComponent, PropType } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
|
||||
import type { TiposTabelaCelulas } from "./tiposTabelaCelulas";
|
||||
|
||||
// Necessário para `fromNow()`.
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
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 dayjs(valorIso).fromNow();
|
||||
}
|
||||
|
||||
if (formato === "data_hora") {
|
||||
// Padrão pt-BR simples (sem depender de locale do dayjs)
|
||||
return dayjs(valorIso).format("DD/MM/YYYY HH:mm");
|
||||
}
|
||||
|
||||
// formato === "data"
|
||||
return dayjs(valorIso).format("DD/MM/YYYY");
|
||||
});
|
||||
|
||||
return { dados, textoData };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.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>
|
||||
|
|
@ -5,13 +5,13 @@
|
|||
class="eli-tabela__celula-link"
|
||||
@click.stop.prevent="dados.acao()"
|
||||
>
|
||||
{{ String(dados?.numero).replace('.', ',') }}
|
||||
{{ textoNumero }}
|
||||
</button>
|
||||
<span v-else>{{ String(dados?.numero).replace('.', ',') }}</span>
|
||||
<span v-else>{{ textoNumero }}</span>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from "vue"
|
||||
import { computed, defineComponent, PropType } from "vue"
|
||||
import type { TiposTabelaCelulas } from "./tiposTabelaCelulas";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
@ -21,16 +21,21 @@ export default defineComponent({
|
|||
dados: {
|
||||
type: Object as PropType<TiposTabelaCelulas["numero"]>,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
setup({ dados }) {
|
||||
return { 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>
|
||||
|
|
|
|||
61
src/componentes/EliTabela/celulas/EliTabelaCelulaTags.vue
Normal file
61
src/componentes/EliTabela/celulas/EliTabelaCelulaTags.vue
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<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, 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 scoped>
|
||||
.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>
|
||||
81
src/componentes/EliTabela/celulas/README.md
Normal file
81
src/componentes/EliTabela/celulas/README.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# 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`
|
||||
|
|
@ -3,10 +3,14 @@ import type { Component } from "vue";
|
|||
import EliTabelaCelulaTextoSimples from "./EliTabelaCelulaTextoSimples.vue";
|
||||
import EliTabelaCelulaTextoTruncado from "./EliTabelaCelulaTextoTruncado.vue";
|
||||
import EliTabelaCelulaNumero from "./EliTabelaCelulaNumero.vue";
|
||||
import EliTabelaCelulaTags from "./EliTabelaCelulaTags.vue";
|
||||
import EliTabelaCelulaData from "./EliTabelaCelulaData.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>;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
* Tipagem dos dados de entrada dos componentes de celulas
|
||||
*/
|
||||
|
||||
import type { LucideIcon } from "lucide-vue-next";
|
||||
|
||||
export type TiposTabelaCelulas = {
|
||||
textoSimples: {
|
||||
texto: string;
|
||||
|
|
@ -13,6 +15,32 @@ export type TiposTabelaCelulas = {
|
|||
};
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue