rafatoração de componentes de entrada
This commit is contained in:
parent
6aedf2469f
commit
27c9e4d5e2
45 changed files with 1295 additions and 2605 deletions
2
dist/eli-vue.css
vendored
2
dist/eli-vue.css
vendored
File diff suppressed because one or more lines are too long
2407
dist/eli-vue.es.js
vendored
2407
dist/eli-vue.es.js
vendored
File diff suppressed because it is too large
Load diff
30
dist/eli-vue.umd.js
vendored
30
dist/eli-vue.umd.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -186,30 +186,27 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
default: undefined;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
||||
onInput?: ((_v: string | null) => any) | undefined;
|
||||
onChange?: ((_v: string | null) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: string | null) => any) | undefined;
|
||||
onAlterar?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
||||
onFoco?: (() => any) | undefined;
|
||||
onDesfoco?: (() => any) | undefined;
|
||||
}>, {
|
||||
placeholder: string;
|
||||
modelValue: string | null;
|
||||
value: string | null | undefined;
|
||||
max: string | undefined;
|
||||
min: string | undefined;
|
||||
erro: boolean;
|
||||
rotulo: string;
|
||||
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;
|
||||
value: string | null | undefined;
|
||||
opcoes: {
|
||||
rotulo: string;
|
||||
placeholder?: string;
|
||||
|
|
@ -225,6 +222,9 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
densidade?: import("../../tipos").CampoDensidade;
|
||||
variante?: import("../../tipos").CampoVariante;
|
||||
};
|
||||
placeholder: string;
|
||||
rotulo: string;
|
||||
modelValue: string | null;
|
||||
desabilitado: boolean;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
declare const _default: typeof __VLS_export;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
emit: ((event: "change", _v: number | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void) & ((event: "input", _v: number | null | undefined) => void) & ((event: "update:value", _v: number | null | undefined) => void);
|
||||
emit: ((event: "update:value", _v: number | null | undefined) => void) & ((event: "input", _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;
|
||||
|
|
@ -37,11 +37,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
required: true;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onChange?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
||||
}>, {
|
||||
value: number | null | undefined;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
emit: ((event: "change", _v: string | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void) & ((event: "input", _v: string | null | undefined) => void) & ((event: "update:value", _v: string | null | undefined) => void);
|
||||
emit: ((event: "update:value", _v: string | null | undefined) => void) & ((event: "input", _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) */
|
||||
|
|
@ -35,11 +38,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
required: true;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
||||
}>, {
|
||||
value: string | null | undefined;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export declare const registryTabelaCelulas: {
|
|||
placeholder?: string;
|
||||
} & {
|
||||
limiteCaracteres?: number;
|
||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
||||
}>;
|
||||
required: true;
|
||||
};
|
||||
|
|
@ -17,8 +18,11 @@ export declare const registryTabelaCelulas: {
|
|||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
emit: ((event: "change", _v: string | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void) & ((event: "input", _v: string | null | undefined) => void) & ((event: "update:value", _v: string | null | undefined) => void);
|
||||
emit: ((event: "update:value", _v: string | null | undefined) => void) & ((event: "input", _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;
|
||||
|
|
@ -36,15 +40,16 @@ export declare const registryTabelaCelulas: {
|
|||
placeholder?: string;
|
||||
} & {
|
||||
limiteCaracteres?: number;
|
||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
||||
}>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
||||
}>, {
|
||||
value: string | null | undefined;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
|
|
@ -68,7 +73,7 @@ export declare const registryTabelaCelulas: {
|
|||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
emit: ((event: "change", _v: number | null | undefined) => void) & ((event: "focus") => void) & ((event: "blur") => void) & ((event: "input", _v: number | null | undefined) => void) & ((event: "update:value", _v: number | null | undefined) => void);
|
||||
emit: ((event: "update:value", _v: number | null | undefined) => void) & ((event: "input", _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;
|
||||
|
|
@ -95,11 +100,11 @@ export declare const registryTabelaCelulas: {
|
|||
required: true;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onChange?: ((_v: number | null | undefined) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: number | null | undefined) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: number | null | undefined) => any) | undefined;
|
||||
}>, {
|
||||
value: number | null | undefined;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
|
|
@ -121,8 +126,8 @@ export declare const registryTabelaCelulas: {
|
|||
dicaPersistente?: boolean;
|
||||
min?: string;
|
||||
max?: string;
|
||||
densidade?: import("../../tipos/campo.js").CampoDensidade;
|
||||
variante?: import("../../tipos/campo.js").CampoVariante;
|
||||
densidade?: import("../../tipos/entrada.js").CampoDensidade;
|
||||
variante?: import("../../tipos/entrada.js").CampoVariante;
|
||||
}>;
|
||||
required: false;
|
||||
default: undefined;
|
||||
|
|
@ -168,11 +173,11 @@ export declare const registryTabelaCelulas: {
|
|||
default: undefined;
|
||||
};
|
||||
densidade: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoDensidade>;
|
||||
type: import("vue").PropType<import("../../tipos/entrada.js").CampoDensidade>;
|
||||
default: undefined;
|
||||
};
|
||||
variante: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoVariante>;
|
||||
type: import("vue").PropType<import("../../tipos/entrada.js").CampoVariante>;
|
||||
default: undefined;
|
||||
};
|
||||
min: {
|
||||
|
|
@ -203,8 +208,8 @@ export declare const registryTabelaCelulas: {
|
|||
dicaPersistente?: boolean;
|
||||
min?: string;
|
||||
max?: string;
|
||||
densidade?: import("../../tipos/campo.js").CampoDensidade;
|
||||
variante?: import("../../tipos/campo.js").CampoVariante;
|
||||
densidade?: import("../../tipos/entrada.js").CampoDensidade;
|
||||
variante?: import("../../tipos/entrada.js").CampoVariante;
|
||||
}>;
|
||||
desabilitadoEfetivo: import("vue").ComputedRef<boolean>;
|
||||
emitCompatFocus: () => void;
|
||||
|
|
@ -237,8 +242,8 @@ export declare const registryTabelaCelulas: {
|
|||
dicaPersistente?: boolean;
|
||||
min?: string;
|
||||
max?: string;
|
||||
densidade?: import("../../tipos/campo.js").CampoDensidade;
|
||||
variante?: import("../../tipos/campo.js").CampoVariante;
|
||||
densidade?: import("../../tipos/entrada.js").CampoDensidade;
|
||||
variante?: import("../../tipos/entrada.js").CampoVariante;
|
||||
}>;
|
||||
required: false;
|
||||
default: undefined;
|
||||
|
|
@ -284,11 +289,11 @@ export declare const registryTabelaCelulas: {
|
|||
default: undefined;
|
||||
};
|
||||
densidade: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoDensidade>;
|
||||
type: import("vue").PropType<import("../../tipos/entrada.js").CampoDensidade>;
|
||||
default: undefined;
|
||||
};
|
||||
variante: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoVariante>;
|
||||
type: import("vue").PropType<import("../../tipos/entrada.js").CampoVariante>;
|
||||
default: undefined;
|
||||
};
|
||||
min: {
|
||||
|
|
@ -300,30 +305,27 @@ export declare const registryTabelaCelulas: {
|
|||
default: undefined;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
||||
onInput?: ((_v: string | null) => any) | undefined;
|
||||
onChange?: ((_v: string | null) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
onInput?: ((_v: string | null) => any) | undefined;
|
||||
onAlterar?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null) => any) | undefined;
|
||||
"onUpdate:modelValue"?: ((_v: string | null) => any) | undefined;
|
||||
onFoco?: (() => any) | undefined;
|
||||
onDesfoco?: (() => any) | undefined;
|
||||
}>, {
|
||||
placeholder: string;
|
||||
modelValue: string | null;
|
||||
value: string | null | undefined;
|
||||
max: string | undefined;
|
||||
min: string | undefined;
|
||||
erro: boolean;
|
||||
rotulo: string;
|
||||
modo: "data" | "dataHora" | undefined;
|
||||
limpavel: boolean;
|
||||
erro: boolean;
|
||||
mensagensErro: string | string[];
|
||||
dica: string;
|
||||
dicaPersistente: boolean;
|
||||
densidade: import("../../tipos/campo.js").CampoDensidade;
|
||||
variante: import("../../tipos/campo.js").CampoVariante;
|
||||
min: string | undefined;
|
||||
max: string | undefined;
|
||||
densidade: import("../../tipos/entrada.js").CampoDensidade;
|
||||
variante: import("../../tipos/entrada.js").CampoVariante;
|
||||
value: string | null | undefined;
|
||||
opcoes: {
|
||||
rotulo: string;
|
||||
placeholder?: string;
|
||||
|
|
@ -336,9 +338,12 @@ export declare const registryTabelaCelulas: {
|
|||
dicaPersistente?: boolean;
|
||||
min?: string;
|
||||
max?: string;
|
||||
densidade?: import("../../tipos/campo.js").CampoDensidade;
|
||||
variante?: import("../../tipos/campo.js").CampoVariante;
|
||||
densidade?: import("../../tipos/entrada.js").CampoDensidade;
|
||||
variante?: import("../../tipos/entrada.js").CampoVariante;
|
||||
};
|
||||
placeholder: string;
|
||||
rotulo: string;
|
||||
modelValue: string | null;
|
||||
desabilitado: boolean;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ 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³") */
|
||||
|
|
|
|||
2
dist/types/componentes/EliEntrada/utils/cep.d.ts
vendored
Normal file
2
dist/types/componentes/EliEntrada/utils/cep.d.ts
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/** Formata CEP no padrão 00000-000 */
|
||||
export declare function formatarCep(valor: string): string;
|
||||
146
dist/types/componentes/campo/EliInput.vue.d.ts
vendored
146
dist/types/componentes/campo/EliInput.vue.d.ts
vendored
|
|
@ -1,146 +0,0 @@
|
|||
import { PropType } from "vue";
|
||||
import type { CampoDensidade, CampoOpcao, CampoOpcaoBruta, CampoTipo, CampoValor, CampoValorMultiplo, CampoVariante } from "../../tipos";
|
||||
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
/**
|
||||
* 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: PropType<CampoValor | CampoValorMultiplo>;
|
||||
default: string;
|
||||
};
|
||||
type: {
|
||||
type: PropType<CampoTipo>;
|
||||
default: string;
|
||||
};
|
||||
label: StringConstructor;
|
||||
placeholder: StringConstructor;
|
||||
disabled: BooleanConstructor;
|
||||
error: BooleanConstructor;
|
||||
errorMessages: {
|
||||
type: PropType<string | string[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
hint: StringConstructor;
|
||||
persistentHint: BooleanConstructor;
|
||||
rows: {
|
||||
type: NumberConstructor;
|
||||
default: number;
|
||||
};
|
||||
/**
|
||||
* Para select/radio/checkbox.
|
||||
* Aceita lista já normalizada ({ label, value }) ou valores primitivos.
|
||||
*/
|
||||
options: {
|
||||
type: PropType<Array<CampoOpcaoBruta>>;
|
||||
default: () => never[];
|
||||
};
|
||||
clearable: BooleanConstructor;
|
||||
variant: {
|
||||
type: PropType<CampoVariante>;
|
||||
default: string;
|
||||
};
|
||||
density: {
|
||||
type: PropType<CampoDensidade>;
|
||||
default: string;
|
||||
};
|
||||
color: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
row: BooleanConstructor;
|
||||
showPasswordToggle: BooleanConstructor;
|
||||
multiple: BooleanConstructor;
|
||||
chips: BooleanConstructor;
|
||||
}>, {
|
||||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
value: import("vue").WritableComputedRef<CampoValor | CampoValorMultiplo, CampoValor | CampoValorMultiplo>;
|
||||
isTextLike: import("vue").ComputedRef<boolean>;
|
||||
inputHtmlType: import("vue").ComputedRef<"text" | "password">;
|
||||
inputMode: import("vue").ComputedRef<"tel" | "decimal" | "numeric" | undefined>;
|
||||
internalColor: import("vue").ComputedRef<string | undefined>;
|
||||
showPassword: import("vue").Ref<boolean, boolean>;
|
||||
togglePassword: () => void;
|
||||
onInput: (e: Event) => void;
|
||||
onFocus: () => void;
|
||||
onBlur: () => void;
|
||||
computedItems: import("vue").ComputedRef<CampoOpcao[]>;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "change" | "focus" | "blur")[], "update:modelValue" | "change" | "focus" | "blur", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
/**
|
||||
* 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: PropType<CampoValor | CampoValorMultiplo>;
|
||||
default: string;
|
||||
};
|
||||
type: {
|
||||
type: PropType<CampoTipo>;
|
||||
default: string;
|
||||
};
|
||||
label: StringConstructor;
|
||||
placeholder: StringConstructor;
|
||||
disabled: BooleanConstructor;
|
||||
error: BooleanConstructor;
|
||||
errorMessages: {
|
||||
type: PropType<string | string[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
hint: StringConstructor;
|
||||
persistentHint: BooleanConstructor;
|
||||
rows: {
|
||||
type: NumberConstructor;
|
||||
default: number;
|
||||
};
|
||||
/**
|
||||
* Para select/radio/checkbox.
|
||||
* Aceita lista já normalizada ({ label, value }) ou valores primitivos.
|
||||
*/
|
||||
options: {
|
||||
type: PropType<Array<CampoOpcaoBruta>>;
|
||||
default: () => never[];
|
||||
};
|
||||
clearable: BooleanConstructor;
|
||||
variant: {
|
||||
type: PropType<CampoVariante>;
|
||||
default: string;
|
||||
};
|
||||
density: {
|
||||
type: PropType<CampoDensidade>;
|
||||
default: string;
|
||||
};
|
||||
color: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
row: BooleanConstructor;
|
||||
showPasswordToggle: BooleanConstructor;
|
||||
multiple: BooleanConstructor;
|
||||
chips: BooleanConstructor;
|
||||
}>> & Readonly<{
|
||||
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
||||
onChange?: ((...args: any[]) => any) | undefined;
|
||||
onFocus?: ((...args: any[]) => any) | undefined;
|
||||
onBlur?: ((...args: any[]) => any) | undefined;
|
||||
}>, {
|
||||
color: string;
|
||||
type: CampoTipo;
|
||||
variant: CampoVariante;
|
||||
disabled: boolean;
|
||||
error: boolean;
|
||||
persistentHint: boolean;
|
||||
clearable: boolean;
|
||||
row: boolean;
|
||||
showPasswordToggle: boolean;
|
||||
multiple: boolean;
|
||||
chips: boolean;
|
||||
modelValue: CampoValor | CampoValorMultiplo;
|
||||
errorMessages: string | string[];
|
||||
rows: number;
|
||||
options: CampoOpcaoBruta[];
|
||||
density: CampoDensidade;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
declare const _default: typeof __VLS_export;
|
||||
export default _default;
|
||||
1
dist/types/componentes/campo/index.d.ts
vendored
1
dist/types/componentes/campo/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
|||
export { default as EliInput } from "./EliInput.vue";
|
||||
1
dist/types/componentes/campo/utils/cep.d.ts
vendored
1
dist/types/componentes/campo/utils/cep.d.ts
vendored
|
|
@ -1 +0,0 @@
|
|||
export declare function formatarCep(v: string): string;
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
export declare function somenteNumeros(valor: string): string;
|
||||
export declare function formatarDecimal(valor: string): string;
|
||||
/**
|
||||
* Formatação para percentual:
|
||||
* - remove '%' caso venha junto (ex: colar "10%")
|
||||
* - mantém apenas dígitos e vírgula (no máximo uma)
|
||||
*/
|
||||
export declare function formatarPorcentagem(valor: string): string;
|
||||
export declare function formatarMoeda(valor: string): string;
|
||||
|
|
@ -22,7 +22,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
};
|
||||
}>, {
|
||||
rotuloStatus: import("vue").ComputedRef<CartaoStatus>;
|
||||
corStatus: import("vue").ComputedRef<"primary" | "error" | "secondary" | "success">;
|
||||
corStatus: import("vue").ComputedRef<"primary" | "secondary" | "success" | "error">;
|
||||
classeStatus: import("vue").ComputedRef<string>;
|
||||
onClick: () => void;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||
|
|
|
|||
1
dist/types/componentes/data_hora/index.d.ts
vendored
1
dist/types/componentes/data_hora/index.d.ts
vendored
|
|
@ -1 +0,0 @@
|
|||
export { default as EliEntradaDataHora } from "../EliEntrada/EliEntradaDataHora.vue";
|
||||
|
|
@ -1,18 +1,9 @@
|
|||
type Habilidade = "vue" | "react";
|
||||
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>;
|
||||
estado: import("vue").Ref<string[], string[]>;
|
||||
telefone: import("vue").Ref<string, string>;
|
||||
mensagem: import("vue").Ref<string, string>;
|
||||
senha: import("vue").Ref<string, string>;
|
||||
cor: import("vue").Ref<"azul" | "verde" | null, "azul" | "verde" | null>;
|
||||
habilidades: import("vue").Ref<Habilidade[], Habilidade[]>;
|
||||
idade: import("vue").Ref<string, string>;
|
||||
altura: import("vue").Ref<string, string>;
|
||||
cep: import("vue").Ref<string, string>;
|
||||
valor: 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: {
|
||||
|
|
@ -144,131 +135,59 @@ declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|||
badge: string | number | undefined;
|
||||
radius: import("../../tipos/indicador.js").IndicadorPresetRaio | import("../../tipos/indicador.js").CssLength;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
EliInput: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
modelValue: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoValor | import("../../tipos/campo.js").CampoValorMultiplo>;
|
||||
default: string;
|
||||
EliEntradaTexto: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
value: {
|
||||
type: import("vue").PropType<string | null | undefined>;
|
||||
default: undefined;
|
||||
};
|
||||
type: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoTipo>;
|
||||
default: string;
|
||||
opcoes: {
|
||||
type: import("vue").PropType<{
|
||||
rotulo: string;
|
||||
placeholder?: string;
|
||||
} & {
|
||||
limiteCaracteres?: number;
|
||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
||||
}>;
|
||||
required: true;
|
||||
};
|
||||
label: StringConstructor;
|
||||
placeholder: StringConstructor;
|
||||
disabled: BooleanConstructor;
|
||||
error: BooleanConstructor;
|
||||
errorMessages: {
|
||||
type: import("vue").PropType<string | string[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
hint: StringConstructor;
|
||||
persistentHint: BooleanConstructor;
|
||||
rows: {
|
||||
type: NumberConstructor;
|
||||
default: number;
|
||||
};
|
||||
options: {
|
||||
type: import("vue").PropType<Array<import("../../tipos/campo.js").CampoOpcaoBruta>>;
|
||||
default: () => never[];
|
||||
};
|
||||
clearable: BooleanConstructor;
|
||||
variant: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoVariante>;
|
||||
default: string;
|
||||
};
|
||||
density: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoDensidade>;
|
||||
default: string;
|
||||
};
|
||||
color: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
row: BooleanConstructor;
|
||||
showPasswordToggle: BooleanConstructor;
|
||||
multiple: BooleanConstructor;
|
||||
chips: BooleanConstructor;
|
||||
}>, {
|
||||
attrs: {
|
||||
[x: string]: unknown;
|
||||
};
|
||||
value: import("vue").WritableComputedRef<import("../../tipos/campo.js").CampoValor | import("../../tipos/campo.js").CampoValorMultiplo, import("../../tipos/campo.js").CampoValor | import("../../tipos/campo.js").CampoValorMultiplo>;
|
||||
isTextLike: import("vue").ComputedRef<boolean>;
|
||||
inputHtmlType: import("vue").ComputedRef<"text" | "password">;
|
||||
inputMode: import("vue").ComputedRef<"tel" | "decimal" | "numeric" | undefined>;
|
||||
internalColor: import("vue").ComputedRef<string | undefined>;
|
||||
showPassword: import("vue").Ref<boolean, boolean>;
|
||||
togglePassword: () => void;
|
||||
emit: ((event: "update:value", _v: string | null | undefined) => void) & ((event: "input", _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;
|
||||
onFocus: () => void;
|
||||
onBlur: () => void;
|
||||
computedItems: import("vue").ComputedRef<import("../../tipos/campo.js").CampoOpcao[]>;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("update:modelValue" | "change" | "focus" | "blur")[], "update:modelValue" | "change" | "focus" | "blur", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
modelValue: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoValor | import("../../tipos/campo.js").CampoValorMultiplo>;
|
||||
default: string;
|
||||
}, {}, {}, {}, 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;
|
||||
};
|
||||
type: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoTipo>;
|
||||
default: string;
|
||||
opcoes: {
|
||||
type: import("vue").PropType<{
|
||||
rotulo: string;
|
||||
placeholder?: string;
|
||||
} & {
|
||||
limiteCaracteres?: number;
|
||||
formato?: "texto" | "email" | "url" | "telefone" | "cpfCnpj" | "cep";
|
||||
}>;
|
||||
required: true;
|
||||
};
|
||||
label: StringConstructor;
|
||||
placeholder: StringConstructor;
|
||||
disabled: BooleanConstructor;
|
||||
error: BooleanConstructor;
|
||||
errorMessages: {
|
||||
type: import("vue").PropType<string | string[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
hint: StringConstructor;
|
||||
persistentHint: BooleanConstructor;
|
||||
rows: {
|
||||
type: NumberConstructor;
|
||||
default: number;
|
||||
};
|
||||
options: {
|
||||
type: import("vue").PropType<Array<import("../../tipos/campo.js").CampoOpcaoBruta>>;
|
||||
default: () => never[];
|
||||
};
|
||||
clearable: BooleanConstructor;
|
||||
variant: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoVariante>;
|
||||
default: string;
|
||||
};
|
||||
density: {
|
||||
type: import("vue").PropType<import("../../tipos/campo.js").CampoDensidade>;
|
||||
default: string;
|
||||
};
|
||||
color: {
|
||||
type: StringConstructor;
|
||||
default: string;
|
||||
};
|
||||
row: BooleanConstructor;
|
||||
showPasswordToggle: BooleanConstructor;
|
||||
multiple: BooleanConstructor;
|
||||
chips: BooleanConstructor;
|
||||
}>> & Readonly<{
|
||||
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
||||
onChange?: ((...args: any[]) => any) | undefined;
|
||||
onFocus?: ((...args: any[]) => any) | undefined;
|
||||
onBlur?: ((...args: any[]) => any) | undefined;
|
||||
"onUpdate:value"?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onInput?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onChange?: ((_v: string | null | undefined) => any) | undefined;
|
||||
onFocus?: (() => any) | undefined;
|
||||
onBlur?: (() => any) | undefined;
|
||||
}>, {
|
||||
color: string;
|
||||
type: import("../../tipos/campo.js").CampoTipo;
|
||||
variant: import("../../tipos/campo.js").CampoVariante;
|
||||
disabled: boolean;
|
||||
error: boolean;
|
||||
persistentHint: boolean;
|
||||
clearable: boolean;
|
||||
row: boolean;
|
||||
showPasswordToggle: boolean;
|
||||
multiple: boolean;
|
||||
chips: boolean;
|
||||
modelValue: import("../../tipos/campo.js").CampoValor | import("../../tipos/campo.js").CampoValorMultiplo;
|
||||
errorMessages: string | string[];
|
||||
rows: number;
|
||||
options: import("../../tipos/campo.js").CampoOpcaoBruta[];
|
||||
density: import("../../tipos/campo.js").CampoDensidade;
|
||||
value: string | null | undefined;
|
||||
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
||||
declare const _default: typeof __VLS_export;
|
||||
|
|
|
|||
2
dist/types/index.d.ts
vendored
2
dist/types/index.d.ts
vendored
|
|
@ -3,14 +3,12 @@ import "./styles/eli-vue-fonts.css";
|
|||
import { EliOlaMundo } from "./componentes/ola_mundo";
|
||||
import { EliBotao } from "./componentes/botao";
|
||||
import { EliBadge } from "./componentes/indicador";
|
||||
import { EliInput } from "./componentes/campo";
|
||||
import { EliCartao } from "./componentes/cartao";
|
||||
import { EliTabela } from "./componentes/EliTabela";
|
||||
import { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora } from "./componentes/EliEntrada";
|
||||
export { EliOlaMundo };
|
||||
export { EliBotao };
|
||||
export { EliBadge };
|
||||
export { EliInput };
|
||||
export { EliCartao };
|
||||
export { EliTabela };
|
||||
export { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora };
|
||||
|
|
|
|||
19
dist/types/tipos/campo.d.ts
vendored
19
dist/types/tipos/campo.d.ts
vendored
|
|
@ -1,19 +0,0 @@
|
|||
/**
|
||||
* Tipos do componente EliInput (campo).
|
||||
*/
|
||||
export type CampoValor = string | number | boolean | null;
|
||||
export type CampoValorMultiplo = CampoValor[];
|
||||
export type CampoOpcao<TValor extends CampoValor = CampoValor> = {
|
||||
label: string;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
export type CampoOpcaoBruta<TValor extends CampoValor = CampoValor> = TValor | {
|
||||
label?: string;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
export type CampoVariante = "outlined" | "filled" | "plain" | "solo" | "solo-filled" | "solo-inverted" | "underlined";
|
||||
export type CampoDensidade = "default" | "comfortable" | "compact";
|
||||
export type CampoTipoNumerico = "numericoInteiro" | "numericoDecimal" | "numericoMoeda" | "porcentagem";
|
||||
export type CampoTipo = "text" | "password" | "email" | "search" | "url" | "textarea" | "radio" | "checkbox" | "telefone" | "cpfCnpj" | "cep" | "select" | CampoTipoNumerico;
|
||||
9
dist/types/tipos/entrada.d.ts
vendored
Normal file
9
dist/types/tipos/entrada.d.ts
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* 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";
|
||||
2
dist/types/tipos/index.d.ts
vendored
2
dist/types/tipos/index.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
|||
export * from "./botao";
|
||||
export * from "./cartao";
|
||||
export * from "./campo";
|
||||
export * from "./entrada";
|
||||
export * from "./indicador";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "eli-vue",
|
||||
"version": "0.1.60",
|
||||
"version": "0.1.62",
|
||||
"private": false,
|
||||
"main": "./dist/eli-vue.umd.js",
|
||||
"module": "./dist/eli-vue.es.js",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<template>
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
:type="inputHtmlType"
|
||||
:inputmode="inputMode"
|
||||
:label="opcoes?.rotulo"
|
||||
:placeholder="opcoes?.placeholder"
|
||||
:counter="opcoes?.limiteCaracteres"
|
||||
|
|
@ -8,12 +10,16 @@
|
|||
v-bind="attrs"
|
||||
@focus="() => emit('focus')"
|
||||
@blur="() => emit('blur')"
|
||||
@input="onInput"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from "vue";
|
||||
import type { PadroesEntradas } from "./tiposEntradas";
|
||||
import { formatarCpfCnpj } from "./utils/cpfCnpj";
|
||||
import { formatTelefone } from "./utils/telefone";
|
||||
import { formatarCep } from "./utils/cep";
|
||||
|
||||
type EntradaTexto = PadroesEntradas["texto"];
|
||||
|
||||
|
|
@ -40,6 +46,8 @@ export default defineComponent({
|
|||
blur: () => true,
|
||||
},
|
||||
setup(props, { attrs, emit }) {
|
||||
const formato = computed(() => props.opcoes?.formato ?? "texto");
|
||||
|
||||
const localValue = computed<EntradaTexto["value"]>({
|
||||
get: () => props.value,
|
||||
set: (v) => {
|
||||
|
|
@ -49,7 +57,43 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
|
||||
return { attrs, emit, localValue };
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -47,18 +47,24 @@ export type PadroesEntradas = {
|
|||
{
|
||||
/** 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³") */
|
||||
|
||||
/** Unidade de medida (ex.: "kg", "m³") */
|
||||
sufixo?: string
|
||||
|
||||
/** Moéda (ex.: "R$") */
|
||||
/** Moéda (ex.: "R$") */
|
||||
prefixo?: string
|
||||
|
||||
/**
|
||||
|
|
|
|||
10
src/componentes/EliEntrada/utils/cep.ts
Normal file
10
src/componentes/EliEntrada/utils/cep.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
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,5 +1,3 @@
|
|||
// utils/telefone.ts
|
||||
|
||||
/**
|
||||
* Remove tudo que não é número
|
||||
*/
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
<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"
|
||||
:suffix="type === 'porcentagem' ? '%' : undefined"
|
||||
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, formatarPorcentagem, 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",
|
||||
"porcentagem",
|
||||
"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 === "porcentagem") return "decimal";
|
||||
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 "porcentagem":
|
||||
resultado = formatarPorcentagem(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>
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
# 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' | 'porcentagem';
|
||||
|
||||
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).
|
||||
* porcentagem — aplica formatação decimal e exibe sufixo `%` automaticamente.
|
||||
* 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.
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default as EliInput } from "./EliInput.vue";
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
import { somenteNumeros } from "./numerico";
|
||||
|
||||
export function formatarCep(v: string): string {
|
||||
const d = somenteNumeros(v).slice(0, 8);
|
||||
|
||||
if (d.length <= 5) return d;
|
||||
|
||||
return d.replace(/^(\d{5})(\d{1,3})$/, "$1-$2");
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
export function somenteNumeros(valor: string) {
|
||||
return valor.replace(/\D+/g, "");
|
||||
}
|
||||
|
||||
export function formatarDecimal(valor: string) {
|
||||
const limpo = valor.replace(/[^\d,]/g, "");
|
||||
const partes = limpo.split(",");
|
||||
return partes.length > 2 ? partes[0] + "," + partes.slice(1).join("") : limpo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatação para percentual:
|
||||
* - remove '%' caso venha junto (ex: colar "10%")
|
||||
* - mantém apenas dígitos e vírgula (no máximo uma)
|
||||
*/
|
||||
export function formatarPorcentagem(valor: string) {
|
||||
return formatarDecimal(valor.replace(/%/g, ""));
|
||||
}
|
||||
|
||||
export function formatarMoeda(valor: string) {
|
||||
const numero = somenteNumeros(valor);
|
||||
if (!numero) return "";
|
||||
|
||||
const inteiro = (parseInt(numero, 10) / 100).toFixed(2);
|
||||
return inteiro.replace(".", ",").replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||
}
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
# EliDataHora
|
||||
|
||||
O `EliDataHora` é um componente de **entrada de data e hora** baseado em `v-text-field` (Vuetify), usando o tipo nativo do HTML `datetime-local`.
|
||||
|
||||
Ele foi criado para oferecer uma solução **estável e leve** sem depender de componentes experimentais do Vuetify.
|
||||
|
||||
## Objetivo
|
||||
|
||||
- Permitir o usuário selecionar **data + hora** com UX nativa do navegador.
|
||||
- Padronizar a API em português (props/eventos) no Design System.
|
||||
|
||||
## API
|
||||
|
||||
### Props
|
||||
|
||||
| Prop | Tipo | Padrão | Descrição |
|
||||
|------|------|--------|-----------|
|
||||
| `modelValue` | `string \| null` | `null` | **Sempre em ISO 8601**, aceitando UTC absoluto (`Z`) ou com offset (ex.: `2026-01-09T16:15:00Z`, `2026-01-09T13:15:00-03:00`). O componente converte para horário **local** antes de exibir. |
|
||||
| `modo` | `"data" \| "dataHora"` | `"dataHora"` | Define se o campo permite selecionar apenas data (`date`) ou data+hora (`datetime-local`). |
|
||||
| `rotulo` | `string` | `"Data e hora"` | Label do campo. |
|
||||
| `placeholder` | `string` | `""` | Placeholder do campo. |
|
||||
| `desabilitado` | `boolean` | `false` | Desabilita o campo. |
|
||||
| `limpavel` | `boolean` | `false` | Habilita botão de limpar (Vuetify `clearable`). |
|
||||
| `erro` | `boolean` | `false` | Estado de erro visual. |
|
||||
| `mensagensErro` | `string \| string[]` | `[]` | Mensagens de erro. |
|
||||
| `dica` | `string` | `""` | Hint/ajuda abaixo do campo. |
|
||||
| `dicaPersistente` | `boolean` | `false` | Mantém dica sempre visível. |
|
||||
| `densidade` | `CampoDensidade` | `"comfortable"` | Densidade (Vuetify). |
|
||||
| `variante` | `CampoVariante` | `"outlined"` | Variante (Vuetify). |
|
||||
| `min` | `string \| undefined` | `undefined` | Mínimo permitido em ISO 8601 (offset ou `Z`). |
|
||||
| `max` | `string \| undefined` | `undefined` | Máximo permitido em ISO 8601 (offset ou `Z`). |
|
||||
|
||||
> Observação: o atributo HTML `datetime-local` **não inclui timezone**.
|
||||
> Este componente resolve isso convertendo:
|
||||
>
|
||||
> - **entrada**: ISO 8601 (UTC/offset) → **exibição** em horário local
|
||||
> - **saída**: valor selecionado → ISO 8601 com **offset local**
|
||||
|
||||
### Emits
|
||||
|
||||
| Evento | Payload | Quando dispara |
|
||||
|--------|---------|---------------|
|
||||
| `update:modelValue` | `string \| null` | Sempre que o valor muda (padrão do v-model). O payload é ISO 8601 com **offset local**. |
|
||||
| `alterar` | `string \| null` | Alias semântico para mudanças de valor (mesmo payload do v-model). |
|
||||
| `foco` | `void` | Ao focar o campo. |
|
||||
| `desfoco` | `void` | Ao sair do foco. |
|
||||
|
||||
### Slots
|
||||
|
||||
Este componente não define slots próprios. Você pode usar slots do `v-text-field` via `v-bind="$attrs"` caso precise (ver exemplos abaixo).
|
||||
|
||||
## Exemplos
|
||||
|
||||
### 1) Uso básico com v-model
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<EliDataHora v-model="dataHora" />
|
||||
<div class="text-caption">Valor: {{ dataHora }}</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from "vue";
|
||||
import { EliDataHora } from "eli-vue";
|
||||
|
||||
export default defineComponent({
|
||||
components: { EliDataHora },
|
||||
setup() {
|
||||
const dataHora = ref<string | null>("2026-01-09T16:15:00Z");
|
||||
return { dataHora };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2) Com limites (min/max) e validação visual
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<EliDataHora
|
||||
v-model="dataHora"
|
||||
rotulo="Agendar"
|
||||
:min="min"
|
||||
:max="max"
|
||||
:erro="!dataHora"
|
||||
:mensagensErro="!dataHora ? ['Obrigatório'] : []"
|
||||
limpavel
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Casos de borda / comportamento esperado
|
||||
|
||||
- Ao limpar o campo, o componente emite `null` (não string vazia).
|
||||
- O navegador pode variar a UI do seletor (isso é esperado do `datetime-local`).
|
||||
- `min/max` devem ser strings em ISO 8601 (offset ou `Z`).
|
||||
- Em `modo="data"`, o componente emite ISO no **início do dia** (`00:00:00`) no fuso local.
|
||||
|
||||
## Acessibilidade
|
||||
|
||||
- O `v-text-field` do Vuetify já oferece base de acessibilidade.
|
||||
- Sempre prefira passar `rotulo` significativo.
|
||||
|
||||
## Decisões de implementação
|
||||
|
||||
- Usamos `datetime-local` por ser amplamente suportado e não depender de APIs experimentais.
|
||||
- O componente usa `dayjs` para converter entradas UTC/offset para local antes de exibir e para emitir ISO 8601 com offset local.
|
||||
- Mantemos o valor como `string | null` para evitar conversões implícitas e permitir que cada projeto decida como persistir (UTC/local).
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default as EliEntradaDataHora } from "../EliEntrada/EliEntradaDataHora.vue";
|
||||
|
|
@ -11,100 +11,31 @@
|
|||
|
||||
<div class="grid-example">
|
||||
<!-- text normal -->
|
||||
<EliInput
|
||||
v-model="nome"
|
||||
label="Nome"
|
||||
placeholder="Digite o nome"
|
||||
|
||||
<EliEntradaTexto
|
||||
v-model:value="nome"
|
||||
:opcoes="{ rotulo: 'Nome', placeholder: 'Digite o nome' }"
|
||||
density="compact"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
v-model="idade"
|
||||
type="numericoInteiro"
|
||||
label="Idade"
|
||||
density="default"
|
||||
<EliEntradaTexto
|
||||
v-model:value="telefone"
|
||||
:opcoes="{ rotulo: 'Telefone', formato: 'telefone' }"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
v-model="altura"
|
||||
type="numericoDecimal"
|
||||
label="Altura"
|
||||
density="comfortable"
|
||||
<EliEntradaTexto
|
||||
v-model:value="cep"
|
||||
:opcoes="{ rotulo: 'CEP', placeholder: '00000-000', formato: 'cep' }"
|
||||
/>
|
||||
|
||||
<EliInput v-model="valor" type="numericoMoeda" label="Valor" />
|
||||
|
||||
<EliInput v-model="telefone" type="telefone" label="Telefone" />
|
||||
|
||||
<EliInput
|
||||
v-model="cep"
|
||||
type="cep"
|
||||
label="CEP"
|
||||
placeholder="00000-000"
|
||||
<EliEntradaTexto
|
||||
v-model:value="documento"
|
||||
:opcoes="{ rotulo: 'CPF / CNPJ', formato: 'cpfCnpj' }"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
type="select"
|
||||
label="Estado"
|
||||
:options="[
|
||||
{ label: 'São Paulo', value: 'SP' },
|
||||
{ label: 'Rio de Janeiro', value: 'RJ' }
|
||||
]"
|
||||
v-model="estado"
|
||||
multiple
|
||||
/>
|
||||
|
||||
<EliInput v-model="documento" type="cpfCnpj" label="CPF / CNPJ" />
|
||||
|
||||
<EliInput
|
||||
v-model="email"
|
||||
label="Email"
|
||||
placeholder="email@exemplo.com"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
v-model="senha"
|
||||
label="Senha"
|
||||
type="password"
|
||||
:showPasswordToggle="true"
|
||||
placeholder="Digite sua senha"
|
||||
/>
|
||||
|
||||
<!-- textarea -->
|
||||
<EliInput
|
||||
type="textarea"
|
||||
v-model="mensagem"
|
||||
label="Mensagem"
|
||||
:rows="5"
|
||||
/>
|
||||
|
||||
<!-- radio -->
|
||||
<EliInput
|
||||
type="radio"
|
||||
v-model="cor"
|
||||
label="Cor favorita"
|
||||
:options="[
|
||||
{ label: 'Azul', value: 'azul' },
|
||||
{ label: 'Verde', value: 'verde' },
|
||||
]"
|
||||
/>
|
||||
|
||||
<!-- checkbox group -->
|
||||
<EliInput
|
||||
type="checkbox"
|
||||
v-model="habilidades"
|
||||
:options="[
|
||||
{ label: 'Vue', value: 'vue' },
|
||||
{ label: 'React', value: 'react' },
|
||||
]"
|
||||
/>
|
||||
|
||||
<!-- erro -->
|
||||
<EliInput
|
||||
v-model="nome"
|
||||
label="Nome"
|
||||
:error="true"
|
||||
:error-messages="['Obrigatório']"
|
||||
<EliEntradaTexto
|
||||
v-model:value="email"
|
||||
:opcoes="{ rotulo: 'Email', placeholder: 'email@exemplo.com', formato: 'email' }"
|
||||
/>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
|
@ -121,45 +52,27 @@
|
|||
import { defineComponent, ref } from "vue";
|
||||
import EliBotao from "../botao/EliBotao.vue";
|
||||
import EliBadge from "../indicador/EliBadge.vue";
|
||||
import EliInput from "../campo/EliInput.vue";
|
||||
|
||||
type Habilidade = "vue" | "react";
|
||||
import EliEntradaTexto from "../EliEntrada/EliEntradaTexto.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "EliOlaMundo",
|
||||
components: {
|
||||
EliBotao,
|
||||
EliBadge,
|
||||
EliInput,
|
||||
EliEntradaTexto,
|
||||
},
|
||||
setup() {
|
||||
const nome = ref("");
|
||||
const estado = ref<string[]>([]);
|
||||
const cep = ref("");
|
||||
const telefone = ref("");
|
||||
const idade = ref("");
|
||||
const altura = ref("");
|
||||
const valor = ref("");
|
||||
const email = ref("");
|
||||
const mensagem = ref("");
|
||||
const senha = ref("");
|
||||
const documento = ref("");
|
||||
const cor = ref<"azul" | "verde" | null>(null);
|
||||
const habilidades = ref<Habilidade[]>([]);
|
||||
return {
|
||||
nome,
|
||||
email,
|
||||
documento,
|
||||
estado,
|
||||
telefone,
|
||||
mensagem,
|
||||
senha,
|
||||
cor,
|
||||
habilidades,
|
||||
idade,
|
||||
altura,
|
||||
cep,
|
||||
valor,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
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`.
|
||||
> Ele não é um componente “de produto”; ele existe para demonstrar integração com Vuetify e mostrar variações de uso de `EliEntradaTexto`, `EliEntradaNumero`, `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`.
|
||||
- **Pastas e arquivos** (quando aplicável) preferem português: `botao/`, `EliEntrada/`, `indicador/`, etc.
|
||||
- **Componentes** mantêm prefixo técnico `Eli` (PascalCase): `EliBotao`, `EliEntradaTexto`.
|
||||
|
||||
Exemplo:
|
||||
|
||||
|
|
@ -19,9 +19,10 @@ src/componentes/
|
|||
EliBotao.vue
|
||||
index.ts
|
||||
README.md
|
||||
campo/
|
||||
EliInput.vue
|
||||
index.ts
|
||||
EliEntrada/
|
||||
EliEntradaTexto.vue
|
||||
EliEntradaNumero.vue
|
||||
EliEntradaDataHora.vue
|
||||
README.md
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import "./styles/eli-vue-fonts.css";
|
|||
import { EliOlaMundo } from "./componentes/ola_mundo";
|
||||
import { EliBotao } from "./componentes/botao";
|
||||
import { EliBadge } from "./componentes/indicador";
|
||||
import { EliInput } from "./componentes/campo";
|
||||
import { EliCartao } from "./componentes/cartao";
|
||||
import { EliTabela } from "./componentes/EliTabela";
|
||||
import { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora } from "./componentes/EliEntrada";
|
||||
|
|
@ -11,7 +10,6 @@ import { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora } from "./compone
|
|||
export { EliOlaMundo };
|
||||
export { EliBotao };
|
||||
export { EliBadge };
|
||||
export { EliInput };
|
||||
export { EliCartao };
|
||||
export { EliTabela };
|
||||
export { EliEntradaTexto, EliEntradaNumero, EliEntradaDataHora };
|
||||
|
|
@ -21,7 +19,6 @@ const EliVue: Plugin = {
|
|||
app.component("EliOlaMundo", EliOlaMundo);
|
||||
app.component("EliBotao", EliBotao);
|
||||
app.component("EliBadge", EliBadge);
|
||||
app.component("EliInput", EliInput);
|
||||
app.component("EliCartao", EliCartao);
|
||||
app.component("EliTabela", EliTabela);
|
||||
app.component("EliEntradaTexto", EliEntradaTexto);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<v-tab value="botao">Botão</v-tab>
|
||||
<v-tab value="indicador">Indicador</v-tab>
|
||||
<v-tab value="cartao">Cartão</v-tab>
|
||||
<v-tab value="campo">Campo</v-tab>
|
||||
<v-tab value="entradas">Entradas</v-tab>
|
||||
<v-tab value="data_hora">Data e hora</v-tab>
|
||||
<v-tab value="tabela">Tabela</v-tab>
|
||||
|
|
@ -20,7 +19,6 @@
|
|||
<BotaoPlayground v-if="aba === 'botao'" />
|
||||
<IndicadorPlayground v-else-if="aba === 'indicador'" />
|
||||
<CartaoPlayground v-else-if="aba === 'cartao'" />
|
||||
<CampoPlayground v-else-if="aba === 'campo'" />
|
||||
<EntradasPlayground v-else-if="aba === 'entradas'" />
|
||||
<DataHoraPlayground v-else-if="aba === 'data_hora'" />
|
||||
<TabelaPlayground v-else-if="aba === 'tabela'" />
|
||||
|
|
@ -33,7 +31,6 @@ import { defineComponent } from "vue";
|
|||
import BotaoPlayground from "./botao.playground.vue";
|
||||
import IndicadorPlayground from "./indicador.playground.vue";
|
||||
import CartaoPlayground from "./cartao.playground.vue";
|
||||
import CampoPlayground from "./campo.playground.vue";
|
||||
import EntradasPlayground from "./entradas.playground.vue";
|
||||
import DataHoraPlayground from "./data_hora.playground.vue";
|
||||
import TabelaPlayground from "./tabela.playground.vue";
|
||||
|
|
@ -43,7 +40,6 @@ type AbaPlayground =
|
|||
| "botao"
|
||||
| "indicador"
|
||||
| "cartao"
|
||||
| "campo"
|
||||
| "entradas"
|
||||
| "data_hora"
|
||||
| "tabela"
|
||||
|
|
@ -53,7 +49,6 @@ const mapaHashParaAba: Record<string, AbaPlayground> = {
|
|||
botao: "botao",
|
||||
indicador: "indicador",
|
||||
cartao: "cartao",
|
||||
campo: "campo",
|
||||
entradas: "entradas",
|
||||
"data-hora": "data_hora",
|
||||
tabela: "tabela",
|
||||
|
|
@ -64,7 +59,6 @@ const mapaAbaParaHash: Record<AbaPlayground, string> = {
|
|||
botao: "botao",
|
||||
indicador: "indicador",
|
||||
cartao: "cartao",
|
||||
campo: "campo",
|
||||
entradas: "entradas",
|
||||
data_hora: "data-hora",
|
||||
tabela: "tabela",
|
||||
|
|
@ -77,7 +71,6 @@ export default defineComponent({
|
|||
BotaoPlayground,
|
||||
IndicadorPlayground,
|
||||
CartaoPlayground,
|
||||
CampoPlayground,
|
||||
EntradasPlayground,
|
||||
DataHoraPlayground,
|
||||
TabelaPlayground,
|
||||
|
|
|
|||
|
|
@ -1,127 +0,0 @@
|
|||
<template>
|
||||
<section class="stack">
|
||||
<h2>EliInput (campo)</h2>
|
||||
|
||||
<div class="grid">
|
||||
<EliInput v-model="nome" label="Nome" placeholder="Digite seu nome" />
|
||||
<EliInput v-model="telefone" type="telefone" label="Telefone" />
|
||||
<EliInput v-model="documento" type="cpfCnpj" label="CPF / CNPJ" />
|
||||
|
||||
<EliInput v-model="idade" type="numericoInteiro" label="Idade" />
|
||||
<EliInput v-model="valor" type="numericoMoeda" label="Valor" />
|
||||
<EliInput v-model="taxa" type="porcentagem" label="Taxa" placeholder="0,00" />
|
||||
<EliInput v-model="cep" type="cep" label="CEP" placeholder="00000-000" />
|
||||
|
||||
<EliInput
|
||||
v-model="estado"
|
||||
type="select"
|
||||
label="Estado"
|
||||
multiple
|
||||
:options="[
|
||||
{ label: 'São Paulo', value: 'SP' },
|
||||
{ label: 'Rio de Janeiro', value: 'RJ' },
|
||||
]"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
v-model="cor"
|
||||
type="radio"
|
||||
label="Cor favorita"
|
||||
:options="[
|
||||
{ label: 'Azul', value: 'azul' },
|
||||
{ label: 'Verde', value: 'verde' },
|
||||
]"
|
||||
/>
|
||||
|
||||
<EliInput
|
||||
v-model="habilidades"
|
||||
type="checkbox"
|
||||
label="Habilidades"
|
||||
:options="[
|
||||
{ label: 'Vue', value: 'vue' },
|
||||
{ label: 'React', value: 'react' },
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<pre class="debug">{{ debug }}</pre>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref } from "vue";
|
||||
import { EliInput } from "@/componentes/campo";
|
||||
|
||||
type Cor = "azul" | "verde" | null;
|
||||
type Habilidade = "vue" | "react";
|
||||
|
||||
export default defineComponent({
|
||||
name: "CampoPlayground",
|
||||
components: { EliInput },
|
||||
setup() {
|
||||
const nome = ref("");
|
||||
const telefone = ref("");
|
||||
const documento = ref("");
|
||||
const idade = ref("");
|
||||
const valor = ref("");
|
||||
const taxa = ref("");
|
||||
const cep = ref("");
|
||||
const estado = ref<string[]>([]);
|
||||
const cor = ref<Cor>(null);
|
||||
const habilidades = ref<Habilidade[]>([]);
|
||||
|
||||
const debug = computed(() =>
|
||||
JSON.stringify(
|
||||
{
|
||||
nome: nome.value,
|
||||
telefone: telefone.value,
|
||||
documento: documento.value,
|
||||
idade: idade.value,
|
||||
valor: valor.value,
|
||||
taxa: taxa.value,
|
||||
cep: cep.value,
|
||||
estado: estado.value,
|
||||
cor: cor.value,
|
||||
habilidades: habilidades.value,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
nome,
|
||||
telefone,
|
||||
documento,
|
||||
idade,
|
||||
valor,
|
||||
taxa,
|
||||
cep,
|
||||
estado,
|
||||
cor,
|
||||
habilidades,
|
||||
debug,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stack {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
}
|
||||
|
||||
.debug {
|
||||
padding: 12px;
|
||||
background: rgba(0, 0, 0, 0.04);
|
||||
border-radius: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -3,10 +3,9 @@
|
|||
<h2>EliCartao (pipeline)</h2>
|
||||
|
||||
<div class="toolbar">
|
||||
<EliInput
|
||||
v-model="filtro"
|
||||
label="Buscar"
|
||||
placeholder="Cliente, título, valor..."
|
||||
<EliEntradaTexto
|
||||
v-model:value="filtro"
|
||||
:opcoes="{ rotulo: 'Buscar', placeholder: 'Cliente, título, valor...' }"
|
||||
density="compact"
|
||||
/>
|
||||
|
||||
|
|
@ -48,7 +47,7 @@
|
|||
import { defineComponent, ref } from "vue";
|
||||
import { EliBadge } from "@/componentes/indicador";
|
||||
import { EliBotao } from "@/componentes/botao";
|
||||
import { EliInput } from "@/componentes/campo";
|
||||
import { EliEntradaTexto } from "@/componentes/EliEntrada";
|
||||
import { EliCartao } from "@/componentes/cartao";
|
||||
import type { CartaoStatus } from "@/tipos";
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ type Coluna = {
|
|||
|
||||
export default defineComponent({
|
||||
name: "CartaoPlayground",
|
||||
components: { EliBadge, EliBotao, EliInput, EliCartao },
|
||||
components: { EliBadge, EliBotao, EliEntradaTexto, EliCartao },
|
||||
setup() {
|
||||
const filtro = ref("");
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<h2>EliOlaMundo</h2>
|
||||
<p class="muted">
|
||||
Demo integrada (útil para smoke-test visual). Para testes específicos,
|
||||
prefira os playgrounds de <code>EliBotao</code>, <code>EliInput</code> e
|
||||
prefira os playgrounds de <code>EliBotao</code>, <code>EliEntradas</code> e
|
||||
<code>EliBadge</code>.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/**
|
||||
* Tipos do componente EliInput (campo).
|
||||
*/
|
||||
|
||||
export type CampoValor = string | number | boolean | null;
|
||||
export type CampoValorMultiplo = CampoValor[];
|
||||
|
||||
export type CampoOpcao<TValor extends CampoValor = CampoValor> = {
|
||||
label: string;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export type CampoOpcaoBruta<TValor extends CampoValor = CampoValor> =
|
||||
| TValor
|
||||
| {
|
||||
label?: string;
|
||||
value: TValor;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export type CampoVariante =
|
||||
| "outlined"
|
||||
| "filled"
|
||||
| "plain"
|
||||
| "solo"
|
||||
| "solo-filled"
|
||||
| "solo-inverted"
|
||||
| "underlined";
|
||||
|
||||
export type CampoDensidade = "default" | "comfortable" | "compact";
|
||||
|
||||
export type CampoTipoNumerico =
|
||||
| "numericoInteiro"
|
||||
| "numericoDecimal"
|
||||
| "numericoMoeda"
|
||||
| "porcentagem";
|
||||
|
||||
export type CampoTipo =
|
||||
| "text"
|
||||
| "password"
|
||||
| "email"
|
||||
| "search"
|
||||
| "url"
|
||||
| "textarea"
|
||||
| "radio"
|
||||
| "checkbox"
|
||||
| "telefone"
|
||||
| "cpfCnpj"
|
||||
| "cep"
|
||||
| "select"
|
||||
| CampoTipoNumerico;
|
||||
18
src/tipos/entrada.ts
Normal file
18
src/tipos/entrada.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/**
|
||||
* 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";
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export * from "./botao";
|
||||
export * from "./cartao";
|
||||
export * from "./campo";
|
||||
export * from "./entrada";
|
||||
export * from "./indicador";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue