chore: alinhar projeto às regras do agent
This commit is contained in:
parent
86d451efa1
commit
51a48eee70
36 changed files with 485 additions and 208 deletions
|
|
@ -1,4 +0,0 @@
|
|||
import EliBadge from "./EliBadge.vue";
|
||||
|
||||
export { EliBadge };
|
||||
export default EliBadge;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import EliBotao from "./EliBotao.vue";
|
||||
|
||||
export { EliBotao };
|
||||
export default EliBotao;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import EliInput from "./EliInput.vue";
|
||||
|
||||
export { EliInput };
|
||||
export default EliInput;
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
# EliOlaMundo (Exemplo de Estrutura)
|
||||
|
||||
Este componente serve como **referência oficial** para a criação de novos componentes neste Design System. Utilize esta estrutura como guia.
|
||||
|
||||
## 📂 Estrutura de Pastas e Arquivos
|
||||
|
||||
Todo componente deve seguir rigorosamente a estrutura abaixo, utilizando **PascalCase** (PrimeiraLetraMaiuscula) para pastas e arquivos.
|
||||
|
||||
```
|
||||
src/componentes/
|
||||
└── NomeDoComponente/ <-- Pasta do Componente
|
||||
├── NomeDoComponente.vue <-- Lógica e Template (Vue 3 + TS)
|
||||
├── index.ts <-- Ponto de entrada (Exports)
|
||||
└── README.md <-- Documentação de uso (Props, Slots, Exemplos)
|
||||
```
|
||||
|
||||
## 📝 Como Criar um Novo Componente
|
||||
|
||||
1. **Crie a Pasta:**
|
||||
Nomeie a pasta com o nome do componente em PascalCase.
|
||||
*Ex: `src/componentes/MeuBotao/`*
|
||||
|
||||
2. **Crie o Arquivo Vue:**
|
||||
Nomeie o arquivo igual à pasta.
|
||||
*Ex: `src/componentes/MeuBotao/MeuBotao.vue`*
|
||||
- Utilize a Composition API com TypeScript.
|
||||
- Defina sempre o `name` do componente.
|
||||
|
||||
3. **Crie o Index (`index.ts`):**
|
||||
Este arquivo facilita a importação. Deve conter:
|
||||
```typescript
|
||||
import MeuBotao from './MeuBotao.vue'
|
||||
|
||||
export { MeuBotao }
|
||||
export default MeuBotao
|
||||
```
|
||||
|
||||
4. **Crie a Documentação (`README.md`):**
|
||||
Descreva o que o componente faz, suas propriedades (`props`), eventos (`emits`) e slots.
|
||||
|
||||
5. **Registre na Biblioteca:**
|
||||
Adicione o novo componente no arquivo principal `src/index.ts`:
|
||||
```typescript
|
||||
import { MeuBotao } from './componentes/MeuBotao'
|
||||
// ...
|
||||
export { MeuBotao }
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
// ...
|
||||
app.component('MeuBotao', MeuBotao)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
import EliOlaMundo from './EliOlaMundo.vue'
|
||||
|
||||
export { EliOlaMundo }
|
||||
export default EliOlaMundo
|
||||
|
|
@ -116,7 +116,7 @@ Exemplos:
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import EliBotao from '@/components/EliBotao.vue'
|
||||
import EliBotao from '@/componentes/botao/EliBotao.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { EliBotao },
|
||||
1
src/componentes/botao/index.ts
Normal file
1
src/componentes/botao/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as EliBotao } from "./EliBotao.vue";
|
||||
|
|
@ -76,8 +76,8 @@
|
|||
:row="row"
|
||||
>
|
||||
<v-radio
|
||||
v-for="opt in options"
|
||||
:key="opt.value"
|
||||
v-for="opt in computedItems"
|
||||
:key="String(opt.value)"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
|
|
@ -86,8 +86,8 @@
|
|||
<!-- CHECKBOX -->
|
||||
<div v-else-if="type === 'checkbox'" class="checkbox-group">
|
||||
<v-checkbox
|
||||
v-for="opt in options"
|
||||
:key="opt.value"
|
||||
v-for="opt in computedItems"
|
||||
:key="String(opt.value)"
|
||||
v-model="value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
|
|
@ -104,12 +104,27 @@ import { formatTelefone } from "./utils/telefone";
|
|||
import { formatarDecimal, formatarMoeda, somenteNumeros } from "./utils/numerico"
|
||||
import { formatarCep } from "./utils/cep";
|
||||
|
||||
type Option = {
|
||||
/**
|
||||
* Tipos base do EliInput.
|
||||
* Mantidos aqui para evitar exports internos não documentados.
|
||||
*/
|
||||
type ValorCampo = string | number | boolean | null;
|
||||
type ValorCampoMultiplo = ValorCampo[];
|
||||
|
||||
type OpcaoCampo<TValor extends ValorCampo = ValorCampo> = {
|
||||
label: string;
|
||||
value: any;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type OpcaoBruta<TValor extends ValorCampo = ValorCampo> =
|
||||
| TValor
|
||||
| {
|
||||
label?: string;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type InputVariant =
|
||||
| "outlined"
|
||||
| "filled"
|
||||
|
|
@ -146,17 +161,34 @@ export default defineComponent({
|
|||
inheritAttrs: false,
|
||||
|
||||
props: {
|
||||
modelValue: { type: [String, Number, Array] as any, default: "" },
|
||||
/**
|
||||
* 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<ValorCampo | ValorCampoMultiplo>,
|
||||
default: "",
|
||||
},
|
||||
type: { type: String as PropType<InputType>, default: "text" },
|
||||
label: String,
|
||||
placeholder: String,
|
||||
disabled: Boolean,
|
||||
error: Boolean,
|
||||
errorMessages: { type: [String, Array] as any, default: () => [] },
|
||||
errorMessages: {
|
||||
type: [String, Array] as PropType<string | string[]>,
|
||||
default: () => [],
|
||||
},
|
||||
hint: String,
|
||||
persistentHint: Boolean,
|
||||
rows: { type: Number, default: 4 },
|
||||
options: { type: Array as PropType<Option[]>, default: () => [] },
|
||||
/**
|
||||
* Para select/radio/checkbox.
|
||||
* Aceita lista já normalizada ({ label, value }) ou valores primitivos.
|
||||
*/
|
||||
options: {
|
||||
type: Array as PropType<Array<OpcaoBruta>>,
|
||||
default: () => [],
|
||||
},
|
||||
clearable: Boolean,
|
||||
variant: { type: String as PropType<InputVariant>, default: "outlined" },
|
||||
density: { type: String as PropType<Density>, default: "comfortable" },
|
||||
|
|
@ -175,7 +207,7 @@ export default defineComponent({
|
|||
|
||||
const value = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v) => {
|
||||
set: (v: ValorCampo | ValorCampoMultiplo) => {
|
||||
emit("update:modelValue", v);
|
||||
emit("change", v);
|
||||
},
|
||||
|
|
@ -255,25 +287,23 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// --- Helpers para select / radio / checkbox (aceita objetos ou primitivos) ---
|
||||
const computedItems = computed(() => {
|
||||
const computedItems = computed<Array<OpcaoCampo>>(() => {
|
||||
// Normaliza options para [{ label, value, disabled? }]
|
||||
return (props.options || []).map((o: any) =>
|
||||
o && typeof o === "object" && ("label" in o || "value" in o)
|
||||
? { label: o.label ?? String(o.value), value: o.value, disabled: o.disabled }
|
||||
: { label: String(o), value: o }
|
||||
);
|
||||
return (props.options || []).map((o) => {
|
||||
if (o && typeof o === "object" && "value" in o) {
|
||||
const valor = o.value as ValorCampo;
|
||||
return {
|
||||
label: o.label ?? String(valor),
|
||||
value: valor,
|
||||
disabled: o.disabled,
|
||||
};
|
||||
}
|
||||
|
||||
const valor = o as ValorCampo;
|
||||
return { label: String(valor), value: valor };
|
||||
});
|
||||
});
|
||||
|
||||
function optLabel(opt: any) {
|
||||
if (opt && typeof opt === "object") return opt.label ?? String(opt.value);
|
||||
return String(opt);
|
||||
}
|
||||
|
||||
function optValue(opt: any) {
|
||||
if (opt && typeof opt === "object") return opt.value;
|
||||
return opt;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
attrs,
|
||||
|
|
@ -288,8 +318,6 @@ export default defineComponent({
|
|||
onFocus: () => emit("focus"),
|
||||
onBlur: () => emit("blur"),
|
||||
computedItems,
|
||||
optLabel,
|
||||
optValue,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
@ -32,7 +32,8 @@ EliInput foi projetado para:
|
|||
## Tipagem (TypeScript)
|
||||
|
||||
```ts
|
||||
type Option = { label: string; value: any; disabled?: boolean };
|
||||
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';
|
||||
|
|
@ -50,7 +51,7 @@ type InputType =
|
|||
|
||||
| Prop | Tipo | Default | Descrição |
|
||||
| ---------------- | --------------------------- | --------------- | ------------------------------------------------------ |
|
||||
| `modelValue` | `string \| number \| any[]` | `""` | Valor controlado (use com `v-model`). |
|
||||
| `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. |
|
||||
|
|
@ -113,4 +114,4 @@ type InputType =
|
|||
## 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.
|
||||
* 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.
|
||||
1
src/componentes/campo/index.ts
Normal file
1
src/componentes/campo/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as EliInput } from "./EliInput.vue";
|
||||
|
|
@ -121,8 +121,8 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .v-badge__badge,
|
||||
::v-deep .v-badge__content {
|
||||
:deep(.v-badge__badge),
|
||||
:deep(.v-badge__content) {
|
||||
border-radius: var(--eli-badge-radius) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -177,6 +177,6 @@ Exemplo (pseudocódigo):
|
|||
|
||||
Observações sobre Vuetify
|
||||
|
||||
1. O EliBadge usa seletores com ::v-deep para alterar o border-radius do elemento interno do v-badge. Isso funciona para Vuetify 2 e 3, mas as classes internas podem variar entre versões. Se você atualizar o Vuetify, verifique os nomes de classe (.v-badge__badge ou .v-badge__content) e ajuste o seletor se necessário.
|
||||
1. O EliBadge usa seletor com `:deep(...)` para alterar o border-radius do elemento interno do `v-badge`. Se você atualizar o Vuetify, verifique os nomes de classe (`.v-badge__badge` / `.v-badge__content`) e ajuste o seletor se necessário.
|
||||
|
||||
2. Prop names do v-badge (ex.: location, offset-x, offset-y, content, dot) podem variar entre versões do Vuetify — reveja a docs da versão em uso se algo não for aplicado como esperado.
|
||||
1
src/componentes/indicador/index.ts
Normal file
1
src/componentes/indicador/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as EliBadge } from "./EliBadge.vue";
|
||||
|
|
@ -119,9 +119,11 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from "vue";
|
||||
import EliBotao from "../EliBotao/EliBotao.vue";
|
||||
import EliBadge from "../EliBadge/EliBadge.vue";
|
||||
import EliInput from "../EliInput/EliInput.vue";
|
||||
import EliBotao from "../botao/EliBotao.vue";
|
||||
import EliBadge from "../indicador/EliBadge.vue";
|
||||
import EliInput from "../campo/EliInput.vue";
|
||||
|
||||
type Habilidade = "vue" | "react";
|
||||
|
||||
export default defineComponent({
|
||||
name: "EliOlaMundo",
|
||||
|
|
@ -132,7 +134,7 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
const nome = ref("");
|
||||
const estado = ref([])
|
||||
const estado = ref<string[]>([]);
|
||||
const cep = ref("");
|
||||
const telefone = ref("");
|
||||
const idade = ref("");
|
||||
|
|
@ -142,8 +144,8 @@ export default defineComponent({
|
|||
const mensagem = ref("");
|
||||
const senha = ref("");
|
||||
const documento = ref("");
|
||||
const cor = ref(null);
|
||||
const habilidades = ref<any[]>([]);
|
||||
const cor = ref<"azul" | "verde" | null>(null);
|
||||
const habilidades = ref<Habilidade[]>([]);
|
||||
return {
|
||||
nome,
|
||||
email,
|
||||
34
src/componentes/ola_mundo/README.md
Normal file
34
src/componentes/ola_mundo/README.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# EliOlaMundo (componente de demonstração)
|
||||
|
||||
O `EliOlaMundo` é um componente **de exemplo** usado para validar rapidamente o Design System no playground.
|
||||
|
||||
> Ele não é um componente “de produto”; ele existe para demonstrar integração com Vuetify e mostrar variações de uso de `EliInput`, `EliBotao` e `EliBadge`.
|
||||
|
||||
## Estrutura do repositório (padrão)
|
||||
|
||||
Neste Design System:
|
||||
|
||||
- **Pastas e arquivos** (quando aplicável) preferem português: `botao/`, `campo/`, `indicador/`, etc.
|
||||
- **Componentes** mantêm prefixo técnico `Eli` (PascalCase): `EliBotao`, `EliInput`.
|
||||
|
||||
Exemplo:
|
||||
|
||||
```
|
||||
src/componentes/
|
||||
botao/
|
||||
EliBotao.vue
|
||||
index.ts
|
||||
README.md
|
||||
campo/
|
||||
EliInput.vue
|
||||
index.ts
|
||||
README.md
|
||||
```
|
||||
|
||||
## Playground
|
||||
|
||||
O playground deve conter arquivos `*.playground.vue` para cada componente, com no mínimo:
|
||||
|
||||
- 3 variações visuais/estados
|
||||
- interações (v-model/click)
|
||||
- casos de borda relevantes
|
||||
1
src/componentes/ola_mundo/index.ts
Normal file
1
src/componentes/ola_mundo/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as EliOlaMundo } from "./EliOlaMundo.vue";
|
||||
Loading…
Add table
Add a link
Reference in a new issue