Package Exports
- @ministerjs/ui
- @ministerjs/ui/enums/FieldContextEnum
- @ministerjs/ui/enums/TableFeaturesEnum
- @ministerjs/ui/events/AfterSubmitEvent
- @ministerjs/ui/events/InputFieldEvent
- @ministerjs/ui/events/SearchFieldEvent
- @ministerjs/ui/style
- @ministerjs/ui/types
Readme
@ministerjs/ui
Uma biblioteca de componentes Vue 3 + Vuetify para construção de dashboards e aplicações full-stack, parte do ecossistema MinisterJS.
🚀 Instalação
npm install @ministerjs/ui
# ou
pnpm add @ministerjs/ui
# ou
yarn add @ministerjs/uiDependências Peer
Este pacote requer as seguintes dependências peer:
{
"@ministerjs/composables": "^1.0.2",
"@ministerjs/model": "^1.1.5",
"@ministerjs/resource": "^1.3.1",
"@ministerjs/store": "^1.2.1",
"@ministerjs/utils": "^2.4.0",
"@ministerjs/validates": "^1.0.2",
"vue": "^3.5.12",
"vue-router": "^4.4.5",
"vuetify": "^3.7.2"
}📦 Estrutura do Pacote
Componentes Principais
- Fields: Campos de formulário especializados
- Forms: Formulários base para CRUD
- Views: Visualizações de dados (Lista, Tabela, Item)
- Widgets: Componentes de UI reutilizáveis
- Events: Eventos customizados para comunicação
- Enums: Enumerações para configuração
🎯 Uso Básico
1. Configuração Inicial
// main.ts
import { createApp } from "vue";
import { createVuetify } from "vuetify";
import "@ministerjs/ui/style";
import App from "./App.vue";
const vuetify = createVuetify();
const app = createApp(App);
app.use(vuetify);
app.mount("#app");2. Importação de Componentes
// Importação individual
import { TextField, SelectField, TableViewList } from "@ministerjs/ui";
// Importação de tipos
import type { FieldScheme, TableViewScheme } from "@ministerjs/ui/types";
// Importação de enums
import { HiddenEnum, TableFeaturesEnum } from "@ministerjs/ui/enums/HiddenEnum";
// Importação de eventos
import { InputFieldEvent } from "@ministerjs/ui/events/InputFieldEvent";🔧 Componentes de Campo (Fields)
TextField
Campo de texto básico com validação e máscaras:
<template>
<TextField v-model="value" :scheme="textFieldScheme" @input="handleInput" />
</template>
<script setup lang="ts">
import { ref } from "vue";
import { TextField, TextFieldScheme } from "@ministerjs/ui";
const value = ref("");
const textFieldScheme = new TextFieldScheme({
title: "Nome",
key: "name",
modelValue: value,
required: true,
requiredMessage: "Nome é obrigatório",
});
function handleInput(event: InputFieldEvent) {
console.log("Input event:", event.data);
}
</script>Campos Especializados
// Campo de CPF com validação automática
import { CPFField, CPFFieldScheme } from "@ministerjs/ui";
const cpfScheme = new CPFFieldScheme({
title: "CPF",
key: "cpf",
required: true,
});
// Campo de Email
import { EmailField, EmailFieldScheme } from "@ministerjs/ui";
const emailScheme = new EmailFieldScheme({
title: "Email",
key: "email",
required: true,
});
// Campo de Preço
import { PriceField, PriceFieldScheme } from "@ministerjs/ui";
const priceScheme = new PriceFieldScheme({
title: "Valor",
key: "price",
defaultValue: 0,
});Lista Completa de Campos
| Campo | Componente | Scheme | Descrição |
|---|---|---|---|
CNPJField |
CNPJField |
CNPJFieldScheme |
Campo para CNPJ com validação |
CPFField |
CPFField |
CPFFieldScheme |
Campo para CPF com validação |
CEPField |
CEPField |
CEPFieldScheme |
Campo para CEP com busca automática |
EmailField |
EmailField |
EmailFieldScheme |
Campo de email com validação |
PasswordField |
PasswordField |
PasswordFieldScheme |
Campo de senha com toggle |
PhoneField |
PhoneField |
PhoneFieldScheme |
Campo de telefone com máscara |
PriceField |
PriceField |
PriceFieldScheme |
Campo monetário formatado |
NumberField |
NumberField |
NumberFieldScheme |
Campo numérico |
DateField |
DateField |
DateFieldScheme |
Seletor de data |
TextAreaField |
TextAreaField |
TextAreaFieldScheme |
Área de texto multilinha |
RichTextField |
RichTextField |
RichTextFieldScheme |
Editor de texto rico (CKEditor) |
SelectField |
SelectField |
SelectFieldScheme |
Campo de seleção |
SelectSearchField |
SelectSearchField |
SelectSearchFieldScheme |
Campo de busca com seleção |
FileField |
FileField |
FileFieldScheme |
Upload de arquivos |
ImageField |
ImageField |
ImageFieldScheme |
Upload e preview de imagens |
📋 Formulários
BaseForm
Formulário base com validação automática:
<template>
<BaseForm
:fields="fields"
@beforesubmit="handleBeforeSubmit"
@aftersubmit="handleAfterSubmit"
/>
</template>
<script setup lang="ts">
import { BaseForm, FieldSchemeCollection } from "@ministerjs/ui";
import type { AfterSubmitEvent } from "@ministerjs/ui/events";
const fields = new FieldSchemeCollection({
name: new TextFieldScheme({
title: "Nome",
key: "name",
required: true,
}),
email: new EmailFieldScheme({
title: "Email",
key: "email",
required: true,
}),
});
function handleAfterSubmit(event: AfterSubmitEvent) {
console.log("Resposta do servidor:", event.data);
}
</script>📊 Visualizações (Views)
TableViewList
Tabela completa com CRUD, paginação e busca:
<template>
<TableViewList :scheme="tableScheme" />
</template>
<script setup lang="ts">
import {
TableViewList,
TableViewScheme,
FieldSchemeCollection,
} from "@ministerjs/ui";
import { TableFeaturesEnum } from "@ministerjs/ui/enums/TableFeaturesEnum";
import { useRestResources } from "@ministerjs/resource";
import { TableModel } from "@ministerjs/model";
// Configuração do resource
const { users } = useRestResources(["users"]);
// Configuração dos campos
const fields = new FieldSchemeCollection({
name: new TextFieldScheme({
title: "Nome",
key: "name",
required: true,
}),
email: new EmailFieldScheme({
title: "Email",
key: "email",
required: true,
}),
phone: new PhoneFieldScheme({
title: "Telefone",
key: "phone",
}),
});
// Configuração do modelo
const model = new TableModel(users, "id");
// Esquema da tabela
const tableScheme = new TableViewScheme({
title: "Usuários",
key: "users",
fields,
model,
headers: {
name: true,
email: true,
phone: false, // Oculta a coluna telefone
},
features: TableFeaturesEnum.ALL, // Habilita todas as funcionalidades
noDataText: "Nenhum usuário encontrado",
});
</script>Configuração de Funcionalidades
import { TableFeaturesEnum } from "@ministerjs/ui/enums/TableFeaturesEnum";
// Apenas visualização
features: TableFeaturesEnum.GET;
// Apenas criação e visualização
features: TableFeaturesEnum.GET | TableFeaturesEnum.ADD;
// Todas as funcionalidades
features: TableFeaturesEnum.ALL;
// Funcionalidades customizadas
features: TableFeaturesEnum.GET | TableFeaturesEnum.UPD | TableFeaturesEnum.DEL;Botões de Ação Customizados
const tableScheme = new TableViewScheme({
// ... outras configurações
// Botões por item (linha)
itemActionsButtons: [
{
icon: "mdi-eye",
title: "Visualizar",
onClick: ({ scheme, item }) => {
console.log("Visualizar item:", item);
},
},
],
// Botões da lista (toolbar)
listActionsButtons: [
{
icon: "mdi-export",
title: "Exportar",
onClick: ({ scheme }) => {
console.log("Exportar dados");
},
},
],
// Botões de linha (contexto)
rowActionsButtons: [
{
icon: "mdi-star",
title: "Favoritar",
onClick: ({ scheme, item }) => {
// Toggle favorito
},
isActive: ({ scheme, item }) => {
return item.isFavorite === true;
},
},
],
});ItemView
Visualização de item individual:
<template>
<ItemView :scheme="itemScheme" />
</template>
<script setup lang="ts">
import { ItemView, ItemViewScheme } from "@ministerjs/ui";
const itemScheme = new ItemViewScheme({
title: "Detalhes do Usuário",
key: "user",
fields,
model,
});
</script>ListView
Lista simples sem tabela:
<template>
<ListView :scheme="listScheme" />
</template>
<script setup lang="ts">
import { ListView, ListViewScheme } from "@ministerjs/ui";
const listScheme = new ListViewScheme({
title: "Lista de Usuários",
key: "users",
fields,
model,
});
</script>🎨 Widgets
ButtonWidget
<template>
<ButtonWidget
icon="mdi-plus"
text="Adicionar"
color="primary"
@click="handleAdd"
/>
</template>IconButtonWidget
<template>
<IconButtonWidget
icon="mdi-edit"
title="Editar"
size="small"
@click="handleEdit"
/>
</template>ToolbarButtonWidget
<template>
<ToolbarButtonWidget
icon="mdi-delete"
text="Excluir"
color="error"
:loading="deleteLoading"
@click="handleDelete"
/>
</template>🔄 Eventos
InputFieldEvent
Disparado quando um campo recebe input:
import { InputFieldEvent } from "@ministerjs/ui/events/InputFieldEvent";
function handleInput(event: InputFieldEvent) {
console.log("Campo:", event.scheme.key);
console.log("Valor:", event.data);
}AfterSubmitEvent
Eventos de ciclo de vida do formulário:
import { AfterSubmitEvent } from "@ministerjs/ui/events";
function handleAfterSubmit(event: AfterSubmitEvent) {
// Ações após o envio bem-sucedido
console.log("Dados salvos:", event.data);
router.push("/success");
}SearchFieldEvent
Evento de busca em campos de seleção:
import { SearchFieldEvent } from "@ministerjs/ui/events/SearchFieldEvent";
function handleSearch(event: SearchFieldEvent) {
console.log("Termo de busca:", event.data);
// Implementar lógica de busca customizada
}⚙️ Enumerações
HiddenEnum
Controla a visibilidade de campos em diferentes contextos:
import { HiddenEnum } from "@ministerjs/ui/enums/HiddenEnum";
const fieldScheme = new TextFieldScheme({
title: "Campo",
key: "field",
hidden: HiddenEnum.TABLE_ADD, // Oculta apenas na criação via tabela
});
// Opções disponíveis:
// HiddenEnum.NEVER - Sempre visível (padrão)
// HiddenEnum.ITEM_UPD - Oculto na edição de item
// HiddenEnum.TABLE_ADD - Oculto na criação via tabela
// HiddenEnum.TABLE_UPD - Oculto na edição via tabela
// HiddenEnum.TABLE_ALWAYS - Oculto sempre na tabela
// HiddenEnum.ALWAYS - Sempre ocultoTableFeaturesEnum
Define funcionalidades habilitadas na tabela:
import { TableFeaturesEnum } from "@ministerjs/ui/enums/TableFeaturesEnum";
// Funcionalidades individuais:
// TableFeaturesEnum.GET - Visualização
// TableFeaturesEnum.ADD - Criação
// TableFeaturesEnum.UPD - Edição
// TableFeaturesEnum.DEL - Exclusão
// TableFeaturesEnum.ALL - Todas as funcionalidades
// TableFeaturesEnum.NONE - Nenhuma funcionalidade🎨 Estilos
Importação de Estilos
// Importar estilos CSS
import "@ministerjs/ui/style";
// Ou especificamente
import "@ministerjs/ui/dist/styles.css";Personalização com Vuetify
O pacote é construído sobre Vuetify 3, permitindo personalização completa do tema:
import { createVuetify } from "vuetify";
const vuetify = createVuetify({
theme: {
defaultTheme: "light",
themes: {
light: {
colors: {
primary: "#1976D2",
secondary: "#424242",
// ... outras cores
},
},
},
},
});🔗 Integração com MinisterJS
Com @ministerjs/resource
import { useRestResources } from "@ministerjs/resource";
import { TableModel } from "@ministerjs/model";
const { users, posts } = useRestResources(["users", "posts"]);
const usersModel = new TableModel(users, "id");
const postsModel = new TableModel(posts, "id");Com @ministerjs/store
import { useModels } from "@ministerjs/model";
const models = useModels({
users: usersModel,
posts: postsModel,
});Com @ministerjs/validates
import { validateEmail } from "@ministerjs/validates";
const emailField = new EmailFieldScheme({
title: "Email",
key: "email",
rules: [(value) => validateEmail(value) || "Email inválido"],
});📚 Exemplos Completos
Formulário de Usuário Completo
<template>
<v-container>
<v-card>
<v-card-title>Cadastro de Usuário</v-card-title>
<v-card-text>
<BaseForm :fields="userFields" @aftersubmit="handleSuccess" />
</v-card-text>
</v-card>
</v-container>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { useRouter } from "vue-router";
import {
BaseForm,
FieldSchemeCollection,
TextFieldScheme,
EmailFieldScheme,
PhoneFieldScheme,
CPFFieldScheme,
CEPFieldScheme,
SelectFieldScheme,
} from "@ministerjs/ui";
import { HiddenEnum } from "@ministerjs/ui/enums/HiddenEnum";
const router = useRouter();
const userFields = new FieldSchemeCollection({
name: new TextFieldScheme({
title: "Nome Completo",
key: "name",
required: true,
requiredMessage: "Nome é obrigatório",
}),
email: new EmailFieldScheme({
title: "Email",
key: "email",
required: true,
}),
phone: new PhoneFieldScheme({
title: "Telefone",
key: "phone",
}),
cpf: new CPFFieldScheme({
title: "CPF",
key: "cpf",
required: true,
}),
cep: new CEPFieldScheme({
title: "CEP",
key: "cep",
}),
gender: new SelectFieldScheme({
title: "Gênero",
key: "gender",
options: [
{ value: "M", text: "Masculino" },
{ value: "F", text: "Feminino" },
{ value: "O", text: "Outro" },
],
}),
id: new TextFieldScheme({
title: "ID",
key: "id",
hidden: HiddenEnum.ALWAYS, // Campo oculto
readonly: true,
}),
});
function handleSuccess(event: AfterSubmitEvent) {
console.log("Usuário criado:", event.data);
router.push("/users");
}
</script>Dashboard Completo
<template>
<v-app>
<v-main>
<v-container fluid>
<TableViewList :scheme="usersTableScheme" />
</v-container>
</v-main>
</v-app>
</template>
<script setup lang="ts">
import {
TableViewList,
TableViewScheme,
FieldSchemeCollection,
TextFieldScheme,
EmailFieldScheme,
PhoneFieldScheme,
DateFieldScheme,
} from "@ministerjs/ui";
import { TableFeaturesEnum } from "@ministerjs/ui/enums/TableFeaturesEnum";
import { HiddenEnum } from "@ministerjs/ui/enums/HiddenEnum";
import { useRestResources } from "@ministerjs/resource";
import { TableModel } from "@ministerjs/model";
// Configuração da API
const { users } = useRestResources(["users"]);
const usersModel = new TableModel(users, "id");
// Campos da tabela
const usersFields = new FieldSchemeCollection({
id: new TextFieldScheme({
title: "ID",
key: "id",
readonly: true,
hidden: HiddenEnum.TABLE_ADD,
}),
name: new TextFieldScheme({
title: "Nome",
key: "name",
required: true,
}),
email: new EmailFieldScheme({
title: "Email",
key: "email",
required: true,
}),
phone: new PhoneFieldScheme({
title: "Telefone",
key: "phone",
}),
createdAt: new DateFieldScheme({
title: "Criado em",
key: "createdAt",
readonly: true,
hidden: HiddenEnum.TABLE_ALWAYS,
}),
});
// Esquema da tabela
const usersTableScheme = new TableViewScheme({
title: "Gerenciamento de Usuários",
key: "users",
fields: usersFields,
model: usersModel,
headers: {
id: true,
name: true,
email: true,
phone: true,
createdAt: false,
},
features: TableFeaturesEnum.ALL,
noDataText: "Nenhum usuário cadastrado",
// Botões customizados
listActionsButtons: [
{
icon: "mdi-download",
title: "Exportar CSV",
onClick: ({ scheme }) => {
// Lógica de exportação
console.log("Exportando dados...");
},
},
],
itemActionsButtons: [
{
icon: "mdi-eye",
title: "Visualizar Detalhes",
onClick: ({ scheme, item }) => {
console.log("Ver detalhes:", item);
},
},
],
});
</script>🚀 Deploy e Distribuição
Build do Pacote
# Build de produção
pnpm build
# Build apenas dos tipos
pnpm build:types
# Lint do código
pnpm lint
# Storybook para desenvolvimento
pnpm storybookUso em Produção
// Otimização para bundlers
import { TableViewList } from "@ministerjs/ui"; // Tree shaking automático
// Importação de tipos apenas em development
import type { TableViewScheme } from "@ministerjs/ui/types";🔍 Troubleshooting
Problemas Comuns
- Estilos não carregando: Certifique-se de importar
@ministerjs/ui/style - Vuetify não configurado: Instale e configure o Vuetify 3
- Dependências peer faltando: Instale todas as dependências peer necessárias
- Erros de tipo: Verifique se está importando os tipos corretos
Debugging
// Habilitar logs de debug
localStorage.setItem("ministerjs:debug", "true");
// Verificar estado dos campos
console.log(fieldScheme.modelValue.value);
console.log(fieldScheme.isValid.value);
console.log(fieldScheme.errors.value);📖 Referências
🤝 Contribuição
Para contribuir com o pacote, veja o guia de contribuição do monorepo MinisterJS.
📄 Licença
Este pacote faz parte do framework MinisterJS e segue a mesma licença do projeto principal.