@stencitecnologia/vue-ui
v0.1.9
Published
Base* Vue components (PrimeVue), CSS design tokens, and PrimeVue/pt-BR locale integration.
Readme
@stencitecnologia/vue-ui
Biblioteca de componentes Vue 3 sobre o PrimeVue 4 + design system em CSS. Inclui inputs, modais, drawers, tabelas, gráficos e demais primitivos visuais usados pelos apps Stenci.
Instalação
npm install @stencitecnologia/vue-uiPeer dependencies (precisam ser instaladas no app consumidor):
npm install vue@^3.3 vue-router@^4 primevue@^4.5.4 chart.js@^4 \
@fortawesome/free-solid-svg-icons@^7 @fortawesome/vue-fontawesome@^3Setup
Chame setupPrimeVue(app) uma vez no bootstrap e importe o CSS uma única vez (no main.js/main.ts):
import { createApp } from 'vue';
import { setupPrimeVue } from '@stencitecnologia/vue-ui';
import '@stencitecnologia/vue-ui/style.css';
import App from './App.vue';
const app = createApp(App);
setupPrimeVue(app); // PrimeVue + tema Aura + locale pt-BR
app.mount('#app');Uso — padrão de formulário
<script setup>
import { useForm, validRequired, validCpf } from '@stencitecnologia/vue-kit';
import { BaseField, BaseInputMask, BaseButton } from '@stencitecnologia/vue-ui';
const { values, errors, handleSubmit } = useForm(
{ cpf: '' },
{ cpf: [validRequired, validCpf] },
);
const submit = handleSubmit(async (data) => {
await api.post('/patients', data);
});
</script>
<template>
<BaseField label="CPF" for-id="cpf" :error="errors.cpf">
<BaseInputMask
id="cpf"
v-model="values.cpf"
mask="999.999.999-99"
:invalid="!!errors.cpf"
/>
</BaseField>
<BaseButton label="Salvar" type="submit" @click="submit" />
</template>Convenções comuns de props
A maioria dos controles de formulário compartilha:
| Prop | Tipo | Default | Notas |
|---|---|---|---|
| modelValue | varia | — | Bind com v-model. |
| invalid | Boolean | false | Aplica estilo de erro. |
| disabled | Boolean | false | |
| readonly | Boolean | false | Quando aplicável. |
| size | 'sm' \| 'md' | 'md' | Controla padding/font-size. |
Combine controles com BaseField para ter label, mensagem de erro e texto de ajuda.
Componentes
FaIcon
Wrapper do FontAwesome. Passa atributos adiante.
<FaIcon :icon="['fas', 'user']" />| Prop | Tipo | Default |
|---|---|---|
| icon | Array \| String \| Object | obrigatório |
BaseAlert
Banner inline com status.
<BaseAlert message="Falha ao salvar" variant="error" />| Prop | Tipo | Default | Valores |
|---|---|---|---|
| message | String | '' | |
| variant | String | 'error' | error \| success \| warning \| info |
BaseAvatar
Avatar circular com iniciais.
<BaseAvatar name="João Silva" variant="primary" size="md" />| Prop | Tipo | Default | Valores |
|---|---|---|---|
| name | String | obrigatório | |
| variant | String | 'primary' | primary \| secondary \| tertiary \| success \| warning \| danger \| info |
| size | String | 'md' | sm \| md \| lg |
BaseButton
<BaseButton label="Salvar" variant="primary" :loading="saving" @click="submit" />| Prop | Tipo | Default | Valores |
|---|---|---|---|
| label | String | '' | |
| loading | Boolean | false | Desabilita automaticamente. |
| disabled | Boolean | false | |
| variant | String | 'primary' | primary \| secondary \| tertiary \| ghost \| outline \| error \| danger |
| type | String | 'button' | button \| submit \| reset |
| size | String | 'md' | sm \| md |
| icon | Array | null | Ícone FontAwesome. |
Slot default disponível para conteúdo custom.
BaseSplitButton
Botão com ação principal à esquerda e dropdown de opções extras à direita.
<BaseSplitButton
label="Salvar"
:items="[
{ label: 'Salvar e continuar', command: () => salvarContinuar() },
{ label: 'Salvar como rascunho', command: () => salvarRascunho() },
]"
@click="salvar"
/>| Prop | Tipo | Default | Valores |
|---|---|---|---|
| label | String | '' | |
| loading | Boolean | false | Desabilita ambos os botões automaticamente. |
| disabled | Boolean | false | |
| variant | String | 'primary' | primary \| secondary \| tertiary \| ghost \| outline \| error \| danger |
| size | String | 'md' | sm \| md |
| items | Array | [] | Array de MenuItem do PrimeVue para o dropdown. |
| icon | Array | null | Ícone FontAwesome no botão principal. |
Emite click ao clicar no botão principal. O chevron abre um TieredMenu com os items.
BaseCard
Container com header, alerta opcional e slot footer.
<BaseCard title="Dados do paciente" :alert-message="errorMsg">
<!-- conteúdo -->
<template #footer>...</template>
</BaseCard>| Prop | Tipo | Default |
|---|---|---|
| title | String | '' |
| subtitle | String | '' |
| className | String | '' |
| hasFooter | Boolean | false |
| alertMessage | String | '' |
| alertVariant | String | 'error' |
BaseChart
Wrapper do Chart.js (via PrimeVue Chart).
<BaseChart type="bar" :data="chartData" :options="chartOptions" />| Prop | Tipo | Default | Notas |
|---|---|---|---|
| type | String | obrigatório | bar \| line \| pie \| doughnut |
| data | Object | obrigatório | Formato Chart.js. |
| options | Object | {} | Deep-merged com config base. |
| height | String | null | Default 300px (cartesiano), 400px (pie/doughnut). |
Cores aplicadas automaticamente a partir de uma paleta interna (6 pares).
BaseCheckbox
<BaseCheckbox v-model="values.accepted" :input-id="id" name="accepted" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | Boolean \| Array \| null | — |
| value | String \| Number \| Boolean \| Object | — |
| inputId | String | — |
| name | String | — |
| invalid | Boolean | false |
| disabled | Boolean | false |
BaseCurrency
Input de moeda pt-BR (1.234,56). Armazena o número cru.
<BaseCurrency v-model="values.price" :invalid="!!errors.price" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | Number \| null | — |
| invalid | Boolean | false |
| disabled | Boolean | false |
| readonly | Boolean | false |
| placeholder | String | '0,00' |
| size | String | 'md' |
Input parseado como centavos (remove não-dígitos, divide por 100).
BaseDate
Date picker simples. Para range/máscara, use BaseDatePicker.
<BaseDate v-model="values.date" :invalid="!!errors.date" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | Date \| String \| Array \| null | — |
| invalid | Boolean | false |
| disabled | Boolean | false |
| size | String | 'md' |
BaseDatePicker
Date/range picker com input mascarado e popover de calendário.
<BaseDatePicker
v-model="values.date"
selection-mode="single"
show-today
show-clear
:min-date="minDate"
/>| Prop | Tipo | Default | Notas |
|---|---|---|---|
| modelValue | Date \| Array \| null | — | Array [start, end] no modo range. |
| invalid | Boolean | false | |
| disabled | Boolean | false | |
| selectionMode | String | 'single' | single \| range |
| minDate | Date | null | |
| maxDate | Date | null | |
| placeholder | String | 'dd/mm/aaaa' | |
| mask | String | '99/99/9999' | |
| showToday | Boolean | false | |
| showClear | Boolean | false | |
| calendarIcon | Array \| Object \| String | — | |
| size | String | 'md' | |
Emite: update:modelValue, update:textValue, blur. Expõe hasPartialInput (computed).
BaseDialog
Dialog enxuto com conteúdo default (ícone + texto). Sem slot de footer.
<BaseDialog v-model="visible" header="Confirmar?" content="Tem certeza?" size="sm" />| Prop | Tipo | Default | Valores |
|---|---|---|---|
| modelValue | Boolean | obrigatório | |
| header | String | '' | |
| icon | Array | null | |
| content | String | '' | |
| size | String | 'md' | sm(24rem) \| md(32rem) \| lg(48rem) \| full(64rem) |
| closable | Boolean | true | |
| dismissableMask | Boolean | true | |
| closeOnEscape | Boolean | true | |
BaseModal
Modal completo com slots de header e footer. Use BaseDialog para confirmações simples; BaseModal quando precisar de footer.
<BaseModal v-model="visible" header="Editar registro" size="lg">
<!-- conteúdo -->
<template #footer>
<BaseButton label="Salvar" @click="save" />
</template>
</BaseModal>| Prop | Tipo | Default | Valores |
|---|---|---|---|
| modelValue | Boolean | obrigatório | |
| header | String | '' | |
| size | String | 'md' | sm(24rem) \| md(38rem) \| lg(56rem) \| full(72rem) |
| closable | Boolean | true | |
| dismissableMask | Boolean | false | |
| closeOnEscape | Boolean | true | |
BaseDrawer
Painel lateral (slide-in).
<BaseDrawer :visible="open" position="right" title="Filtros" @update:visible="open = $event">
<!-- conteúdo -->
</BaseDrawer>| Prop | Tipo | Default |
|---|---|---|
| visible | Boolean | false |
| position | String | 'left' |
| title | String | 'Atenção' |
| modal | Boolean | true |
| dismissable | Boolean | true |
BaseEmpty
Estado vazio com ícone/imagem, título, descrição e slot actions.
<BaseEmpty title="Nenhum registro" description="Tente outro filtro.">
<template #actions>
<BaseButton label="Limpar filtros" @click="clear" />
</template>
</BaseEmpty>| Prop | Tipo | Default |
|---|---|---|
| icon | Array | ['fal', 'info-circle'] |
| image | String | null |
| title | String | 'Nenhum resultado encontrado' |
| description | String | '' |
BaseField
Wrapper de campo: label + slot do controle + mensagem de erro/ajuda.
<BaseField label="Email" for-id="email-input" :error="errors.email">
<BaseInputText id="email-input" v-model="values.email" :invalid="!!errors.email" />
</BaseField>| Prop | Tipo | Default | Notas |
|---|---|---|---|
| label | String | '' | |
| forId | String | '' | Vai para <label for>. |
| error | String | '' | Quando presente, esconde help. |
| help | String | '' | Texto de ajuda em cinza. |
BaseForbidden
Tela de acesso negado com slot opcional de ação.
<BaseForbidden title="Acesso negado" />| Prop | Tipo | Default |
|---|---|---|
| title | String | 'Acesso não autorizado' |
| description | String | (mensagem default em pt-BR) |
BaseInputMask
Input com máscara ('999.999.999-99' para CPF, por exemplo).
<BaseInputMask v-model="values.cpf" mask="999.999.999-99" :invalid="!!errors.cpf" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | String \| Number \| null | — |
| mask | String | obrigatório |
| invalid | Boolean | false |
| disabled | Boolean | false |
| readonly | Boolean | false |
| slotChar | String | '_' |
| autoClear | Boolean | false |
| size | String | 'md' |
BaseInputText
Input de texto simples.
<BaseInputText v-model="values.name" :invalid="!!errors.name" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | String \| Number \| null | — |
| invalid | Boolean | false |
| disabled | Boolean | false |
| readonly | Boolean | false |
| size | String | 'md' |
Expõe método focus() via template ref.
BaseMultiSelect
Dropdown de múltipla seleção.
<BaseMultiSelect v-model="values.tags" :options="tagOptions" filter />| Prop | Tipo | Default |
|---|---|---|
| modelValue | Array | [] |
| options | Array | obrigatório |
| optionLabel | String | 'label' |
| optionValue | String | null |
| placeholder | String | 'Selecione' |
| disabled | Boolean | false |
| loading | Boolean | false |
| invalid | Boolean | false |
| filter | Boolean | false |
| size | String | 'md' |
BasePanel
Painel colapsável com variante de cor opcional.
<BasePanel header="Detalhes" variant="info" toggleable>
<!-- conteúdo -->
</BasePanel>| Prop | Tipo | Default | Valores |
|---|---|---|---|
| header | String | '' | |
| variant | String | null | success \| warning \| danger \| info \| gray |
| toggleable | Boolean | false | |
| collapsed | Boolean | false | |
Aplica borda colorida à esquerda e fundo tingido (8% alpha).
BaseRadioButton
<BaseRadioButton v-model="values.gender" value="male" input-id="gender-male" name="gender" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | String \| Number \| Boolean \| Object \| null | — |
| value | String \| Number \| Boolean \| Object | obrigatório |
| name | String | — |
| inputId | String | — |
| invalid | Boolean | false |
| disabled | Boolean | false |
BaseRouterLink
Link com aparência de botão. Renderiza <RouterLink> ou <a> conforme target.
<BaseRouterLink :to="{ name: 'dashboard' }" variant="outline">Dashboard</BaseRouterLink>| Prop | Tipo | Default | Valores |
|---|---|---|---|
| to | String \| Object | '/' | |
| loading | Boolean | false | |
| disabled | Boolean | false | |
| variant | String | 'primary' | primary \| secondary \| ghost \| outline |
| size | String | 'md' | sm \| md |
| target | String | null | '_blank' etc. |
BaseSectionDivider
Linha horizontal com label centralizado opcional.
<BaseSectionDivider label="Dados pessoais" />| Prop | Tipo | Default |
|---|---|---|
| label | String | null |
BaseSelect
Dropdown de seleção única. Suporta uma opção "vazia" no topo.
<BaseSelect v-model="values.state" :options="STATES" :invalid="!!errors.state" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | String \| Number \| Boolean \| null | — |
| options | Array | obrigatório |
| optionLabel | String | 'label' |
| optionValue | String | null |
| placeholder | String | 'Selecione' |
| disabled | Boolean | false |
| loading | Boolean | false |
| invalid | Boolean | false |
| optionEmpty | Object | null |
| size | String | 'md' |
optionEmpty é prependado à lista (útil para um placeholder do tipo "— selecione —").
BaseSwitch
Toggle. Não emite quando disabled ou loading.
<BaseSwitch v-model="isActive" :disabled="saving" input-id="active-toggle" />| Prop | Tipo | Default |
|---|---|---|
| modelValue | Boolean | false |
| disabled | Boolean | false |
| loading | Boolean | false |
| inputId | String | null |
| size | String | 'md' |
BaseTextarea
<BaseTextarea v-model="values.notes" :rows="6" auto-resize />| Prop | Tipo | Default |
|---|---|---|
| modelValue | String \| null | '' |
| invalid | Boolean | false |
| disabled | Boolean | false |
| readonly | Boolean | false |
| rows | Number | 4 |
| autoResize | Boolean | false |
BaseDataTable
Tabela de dados sobre o DataTable do PrimeVue. Colunas definidas via prop columns; slots nomeados permitem customizar cabeçalho, célula e filtro por coluna.
<BaseDataTable
:value="patients"
:columns="[
{ field: 'name', header: 'Nome' },
{ field: 'email', header: 'E-mail' },
{ field: 'status', header: 'Status', sortable: true },
]"
:loading="loading"
>
<!-- célula customizada -->
<template #body-status="{ data }">
<BaseAlert :message="data.status" variant="info" />
</template>
<!-- estado vazio -->
<template #empty>
<BaseEmpty title="Nenhum paciente encontrado" />
</template>
</BaseDataTable>| Prop | Tipo | Default | Notas |
|---|---|---|---|
| value | Array | [] | Linhas da tabela. |
| columns | Array | obrigatório | Array de objetos coluna — todas as props do Column do PrimeVue são repassadas via v-bind. |
| loading | Boolean | false | Exibe overlay de carregamento. |
| size | String | 'md' | sm \| md — aplica classe p-sm na tabela menor. |
Atributos extras ($attrs) são repassados ao DataTable do PrimeVue (ex.: paginator, rows, rowsPerPageOptions, sortField, etc.).
Slots disponíveis:
| Slot | Quando usar |
|---|---|
| #header | Conteúdo acima das colunas (filtros globais, título, etc.). |
| #body-{field} | Célula customizada para a coluna field. Recebe { data, field, index }. |
| #header-{field} | Cabeçalho customizado para a coluna field. |
| #filter-{field} | Filtro inline para a coluna field (requer filterDisplay no DataTable). |
| #empty | Conteúdo quando value está vazio. |
| #loading | Conteúdo do overlay de carregamento. |
| #footer | Rodapé da tabela. |
| default | Slot passado diretamente ao DataTable — útil para <Column> extras. |
Restrições
- Importe o CSS uma única vez no entry do app:
import '@stencitecnologia/vue-ui/style.css'. - Chame
setupPrimeVue(app)antes de montar o app. - Componentes são primitivos visuais — não coloque regras de negócio neles.
- Novos componentes devem aceitar
size: 'sm' | 'md'e, em controles de formulário,invalid: boolean.
