@stencitecnologia/vue-kit
v0.1.3
Published
Non-visual Vue runtime layer: composables, directives, app context, HTTP client, storage, toast, and Vuelidate wrappers.
Readme
@stencitecnologia/vue-kit
Camada de runtime Vue 3 (sem componentes visuais): composables, contexto de app, formulários com Vuelidate, cliente HTTP, storage, toast e diretivas.
Instalação
npm install @stencitecnologia/vue-kitPeer dependencies (precisam ser instaladas no app consumidor):
npm install vue@^3.3 vue-router@^4 primevue@^4 axios@^1 \
@vuelidate/core@>=2 @vuelidate/validators@>=2Uso
Formulário com validação
import {
useForm,
validRequired,
validEmail,
} from '@stencitecnologia/vue-kit';
const { values, errors, isSubmitting, handleSubmit } = useForm(
{ email: '', name: '' },
{ email: { validRequired, validEmail }, name: { validRequired } },
{
onValidationFail: (errors) => {
console.warn('Formulário inválido', errors.email, errors.name);
},
},
);
const submit = handleSubmit(async (data) => {
await api.post('/endpoint', data);
});errors.email retorna a primeira mensagem de erro ou null. Nested: errors.address.postalCode.
Cliente HTTP
import { createHttpClient } from '@stencitecnologia/vue-kit';
const http = createHttpClient({
baseURL: import.meta.env.VITE_API_URL,
interceptors: {
getToken: () => getAuthToken(),
getSlug: () => currentSlug.value,
onUnauthorized: () => router.push('/login'),
},
});Setup do app
import { createApp } from 'vue';
import { setupCore, createAppContext } from '@stencitecnologia/vue-kit';
const app = createApp(App);
const context = createAppContext({ appName: 'web', env: 'production' });
await setupCore(app, { router, pinia, context });
app.mount('#app');Referência — setup do app
| Export | Assinatura | Descrição |
|---|---|---|
| setupCore | async (app, { router, pinia, context, beforeInstall?, afterInstall? }) => context | Bootstrap único do app. |
| createAppContext | ({ appName?, env?, http?, extra? }) => Readonly<object> | Objeto frozen injetado no app. |
| APP_CONTEXT_KEY | Symbol | Chave de inject para recuperar o contexto. |
Referência — formulário
useForm(initialValues?, rules?, options?)
Retorna:
| Propriedade | Tipo | Descrição |
|---|---|---|
| values | Reactive<T> | Bind direto com v-model. |
| errors | Proxy | errors.field → primeira mensagem ou null. Suporta dot-notation. |
| isSubmitting | Ref<boolean> | Gerenciado por handleSubmit. |
| v$ | ComputedRef (Vuelidate) | Acesso bruto ao Vuelidate; use .value para $dirty, $pending, $touch, etc. |
| validate | () => Promise<boolean> | Roda a validação manualmente. |
| handleSubmit | (fn) => (event?) => Promise<void> | Valida; se OK, chama fn(deepClone(values)) e gerencia isSubmitting. Compatível com @submit e @click. |
| reset | () => void | Reseta valores e flags de dirty. |
Opções (options):
| Opção | Tipo | Descrição |
|---|---|---|
| options.vuelidate | Object | Opções repassadas ao useVuelidate. Merge com defaults ($autoDirty: true). |
| options.onValidationFail | (errors, v$) => void | Chamada com o proxy de erros e a instância Vuelidate quando validate() retorna false. |
Validadores Vuelidate
Mensagens em português. Por padrão são opcionais (passam se vazio) — combine com validRequired para tornar obrigatório.
| Export | Mensagem |
|---|---|
| validRequired | Campo obrigatório. |
| validEmail | E-mail inválido. |
| validFullName | Informe nome e sobrenome. |
| validOnlyNumbers | Informe apenas números. |
| validPostalCode | CEP inválido. |
| validCpf | CPF inválido. |
| validCnpj | CNPJ inválido. |
| validCellphone | Nº celular inválido. |
| validPhone | Nº telefone inválido. |
| validDate | Data inválida. |
| validNotFutureDate | Data não pode ser maior que hoje. |
| validDateRange | Intervalo de datas inválido. |
| validMaxLength(max, message?) | Informe no máximo {max} caracteres. |
| validMinLength(min, message?) | Informe no mínimo {min} caracteres. |
| validMinValue(min, message?) | Valor mínimo é {min}. |
| validSameAs(ref, message?) | Os valores não conferem. |
validCellphone e validPhone chamam onlyNumber() internamente antes de delegar para os validadores puros.
validSameAs recebe um getter () => valor apontando para o campo de referência. Exemplo — confirmar senha:
const { values, errors, handleSubmit } = useForm(
{ password: '', confirmPassword: '' },
{
password: { validRequired },
confirmPassword: {
validRequired,
validSameAs: validSameAs(() => values.password, 'As senhas não conferem.'),
},
},
);useVuelidateField(v$, field)
Hook de baixo nível para um campo Vuelidate específico (uso sem useForm).
const { invalid, error, touch } = useVuelidateField(v$, 'address.postalCode');
// invalid() → dirty AND invalid
// error() → primeira mensagem ou ''
// touch() → marca dirtyReferência — HTTP
createHttpClient(config)
createHttpClient({
baseURL: string, // obrigatório
timeout?: number,
interceptors?: {
getToken(): string | null, // → 'Authorization: JWT <token>'
getSlug(): string | null, // → header 'x-slug'
requireSlugFor({ url, config }): boolean, // bloqueia request sem slug
onMissingSlug({ url, config }): void,
onUnauthorized(error): void, // chamado em HTTP 401
isNotFoundLike({ status, data, error }): boolean,
onNotFoundLike(error): void,
}
})Request interceptor injeta x-slug e Authorization. Response interceptor normaliza erros para HttpError.
HttpError e utilitários
| Export | Descrição |
|---|---|
| HttpError | class { status, data, originalError } — extends Error. |
| normalizeApiError | (error, { isNotFoundLike?, getMessage? }) => HttpError com mensagens default em pt-BR. |
| API_DEFAULT_MESSAGES | Mapa default de mensagens (400, 401, 403, 404, 500, erro de conexão). |
Referência — storage
| Função | Descrição |
|---|---|
| storageGet(key) | localStorage.getItem. |
| storageSet(key, value) | localStorage.setItem. |
| storageRemove(key) | localStorage.removeItem. |
| storageGetJson(key) | JSON.parse, retorna null em erro. |
| storageSetJson(key, value) | JSON.stringify. |
| setAuthToken(token) | Armazena em memória + localStorage. |
| getAuthToken() | Lê do cache em memória, fallback no localStorage. |
| clearAuthToken() | Limpa ambos. |
Referência — toast, composables, diretivas
| Export | Tipo | Descrição |
|---|---|---|
| useAppToast | Composable | toast.success(msg, summary?) (4s) / toast.error(msg, summary?) (5s). Requer plugin de toast do PrimeVue instalado pelo setupPrimeVue do vue-ui. |
| useClickOutside | Composable | (el: Ref<HTMLElement>, handler) => void. Listener pointerdown montado/desmontado automaticamente. |
| vFocus | Diretiva | Auto-foco com retry de 350ms. Use <input v-focus /> após app.directive('focus', vFocus). |
Restrições
- Não importa CSS — concerns visuais ficam no
@stencitecnologia/vue-ui. - Não importa internos do PrimeVue (tema/config ficam no
vue-ui). useAppToast()depende dosetupPrimeVue(app)dovue-uiter sido chamado no bootstrap.
