Cookest
Componentes UI

Componentes

Referência de API para todos os 12 componentes CUCL — props, variantes e exemplos de utilização

Componentes

Todos os componentes são exportados de @cookest/ui. Cada um é totalmente tipado, compatível com modo escuro e acessível por defeito.

import {
  Alert, Avatar, AvatarGroup, Badge, Button,
  Card, CardHeader, CardBody, CardFooter,
  Divider, Input, Modal, Select, Skeleton, SkeletonCard,
  Toggle, Tooltip,
} from "@cookest/ui";
import "@cookest/ui/styles.css";

Button

Botão animado com quatro variantes e um spinner de carregamento integrado.

Props

PropTipoPadrãoDescrição
variant"primary" | "secondary" | "ghost" | "danger""primary"Estilo visual
size"sm" | "md" | "lg""md"Tamanho do botão
loadingbooleanfalseMostra spinner e desativa o botão
iconLeftReactNodeÍcone renderizado antes do rótulo
iconRightReactNodeÍcone renderizado após o rótulo
fullWidthbooleanfalseEstende-se para preencher o contentor
disabledbooleanfalseAtributo disabled nativo
classNamestringClasses Tailwind adicionais

Todos os atributos HTML padrão de <button> são repassados.

Exemplos

// Variantes
<Button variant="primary">Guardar alterações</Button>
<Button variant="secondary">Cancelar</Button>
<Button variant="ghost">Saber mais</Button>
<Button variant="danger">Eliminar conta</Button>

// Tamanhos
<Button size="sm">Pequeno</Button>
<Button size="md">Médio</Button>
<Button size="lg">Grande</Button>

// Estado de carregamento
<Button loading>A guardar…</Button>

// Ícones
<Button iconLeft={<PlusIcon />}>Adicionar item</Button>
<Button iconRight={<ArrowRightIcon />}>Continuar</Button>

O botão utiliza motion.button do Framer Motion — sobe 1px ao passar o rato e reduz para 0.98 ao ser premido. As animações são suprimidas quando disabled ou loading é true.


Input

Campo de texto com rótulo, texto auxiliar, estado de erro e ícones.

Props

PropTipoPadrãoDescrição
labelstringTexto do rótulo acima do campo
helperTextstringTexto auxiliar abaixo
errorstringMensagem de erro — substitui helperText e estiliza a borda a vermelho
iconLeftReactNodeÍcone na posição esquerda
iconRightReactNodeÍcone na posição direita
inputSize"sm" | "md" | "lg""md"Tamanho do campo (usa inputSize para evitar conflito com o atributo HTML size)
fullWidthbooleanfalseEstende-se até à largura do contentor
classNamestringAplicado ao contentor externo

Todos os atributos HTML padrão de <input> são repassados. O id é gerado automaticamente se não for fornecido.

Exemplos

// Básico
<Input label="Email" type="email" placeholder="utilizador@exemplo.com" />

// Com texto auxiliar
<Input label="Nome de utilizador" helperText="3–20 caracteres, apenas minúsculas" />

// Estado de erro
<Input label="Palavra-passe" type="password" error="Mínimo 8 caracteres obrigatório" />

// Ícones
<Input label="Pesquisar" iconLeft={<SearchIcon />} placeholder="Pesquisar receitas…" />

// Largura total
<Input label="Nome" fullWidth />

Card

Componente de contentor com secções opcionais de cabeçalho, corpo e rodapé.

Props do Card

PropTipoPadrãoDescrição
variant"default" | "interactive" | "outlined""default"Estilo visual — interactive adiciona animação ao passar o rato
padding"none" | "sm" | "md" | "lg""md"Preenchimento interno uniforme
classNamestringClasses adicionais

Sub-componentes

CardHeader, CardBody e CardFooter são utilizados para layouts estruturados. Gerem as suas próprias bordas e preenchimentos — não adicione preenchimento ao Card pai quando utilizar sub-componentes (padding="none").

Exemplos

// Cartão simples com preenchimento
<Card>
  <p>Conteúdo do cartão</p>
</Card>

// Cartão estruturado
<Card padding="none">
  <CardHeader>Detalhes da Receita</CardHeader>
  <CardBody>
    <p>Ingredientes e passos…</p>
  </CardBody>
  <CardFooter>
    <Button>Começar a cozinhar</Button>
  </CardFooter>
</Card>

// Cartão interativo (elevação ao passar o rato)
<Card variant="interactive" onClick={handleClick}>
  <p>Clique em mim</p>
</Card>

Badge

Indicador de estado compacto com ponto opcional e botão de remoção.

Props

PropTipoPadrãoDescrição
variant"default" | "success" | "warning" | "error" | "info""default"Variante de cor
size"sm" | "md" | "lg""md"Tamanho do badge
dotbooleanfalseMostra um ponto colorido antes do rótulo
removablebooleanfalseMostra um botão de remoção (×)
onRemove() => voidChamado quando o botão de remoção é clicado
classNamestringClasses adicionais

Exemplos

<Badge variant="success">Ativo</Badge>
<Badge variant="warning" dot>A expirar em breve</Badge>
<Badge variant="error" size="sm">Sem stock</Badge>
<Badge removable onRemove={() => removeTag(id)}>Vegan</Badge>

Avatar

Avatar do utilizador com imagem, fallback de iniciais e agrupamento em pilha.

Props do Avatar

PropTipoPadrãoDescrição
srcstringURL da imagem — renderiza <img> quando fornecido
altstringobrigatórioTexto alternativo (também usado para derivar iniciais)
initialsstringSobrepõe as iniciais derivadas automaticamente
size"xs" | "sm" | "md" | "lg" | "xl""md"Tamanho do avatar
classNamestringClasses adicionais

Quando src está ausente, o componente renderiza um <span> com as duas primeiras iniciais sobre fundo verde-salva.

Props do AvatarGroup

PropTipoPadrãoDescrição
maxnumberMáximo de avatares a mostrar — excedente renderizado como +N
childrenReactNodeobrigatórioComponentes Avatar
classNamestringClasses adicionais

Exemplos

// Com imagem
<Avatar src="/utilizadores/alice.jpg" alt="Alice Silva" size="lg" />

// Fallback de iniciais
<Avatar alt="Bob Jones" size="md" />

// Grupo
<AvatarGroup max={3}>
  <Avatar alt="Alice Silva" />
  <Avatar alt="Bob Jones" />
  <Avatar alt="Carla Branco" />
  <Avatar alt="David Verde" />
</AvatarGroup>

Overlay de diálogo acessível com foco preso e fechar por teclado.

Props

PropTipoPadrãoDescrição
openbooleanobrigatórioControla a visibilidade
onClose() => voidobrigatórioChamado ao dispensar
titlestringRenderiza uma linha de cabeçalho com botão de fechar
size"sm" | "md" | "lg""md"Largura máxima do diálogo
closeOnBackdropbooleantrueFecha ao clicar no fundo
closeOnEscbooleantrueFecha com a tecla Escape
footerReactNodeConteúdo na linha do rodapé
classNamestringAplicado ao painel do diálogo

Exemplo

const [aberto, setAberto] = useState(false);

<Button onClick={() => setAberto(true)}>Abrir modal</Button>

<Modal
  open={aberto}
  onClose={() => setAberto(false)}
  title="Confirmar eliminação"
  footer={
    <>
      <Button variant="ghost" onClick={() => setAberto(false)}>Cancelar</Button>
      <Button variant="danger" onClick={handleEliminar}>Eliminar</Button>
    </>
  }
>
  <p>Esta ação não pode ser desfeita.</p>
</Modal>

Tooltip

Tooltip posicionado com seta animada.

Props

PropTipoPadrãoDescrição
contentReactNodeobrigatórioTexto ou JSX do tooltip
position"top" | "bottom" | "left" | "right""top"Direção da seta
delaynumber0Atraso de exibição em milissegundos
classNamestringAplicado ao painel do tooltip
childrenReactNodeobrigatórioElemento de acionamento

Exemplo

<Tooltip content="Guardar alterações" position="top">
  <Button variant="ghost" size="sm">
    <SaveIcon />
  </Button>
</Tooltip>

Toggle

Interruptor com rótulo opcional.

Props

PropTipoPadrãoDescrição
checkedbooleanobrigatórioEstado do interruptor
onChange(checked: boolean) => voidobrigatórioTratador de alteração de estado
labelstringTexto do rótulo
size"sm" | "md" | "lg""md"Tamanho do interruptor
disabledbooleanfalseImpede a interação
classNamestringClasses adicionais

Exemplo

const [ativado, setAtivado] = useState(false);

<Toggle
  checked={ativado}
  onChange={setAtivado}
  label="Ativar notificações"
/>

Select

Dropdown personalizado com navegação por teclado e pesquisa opcional.

Props

PropTipoPadrãoDescrição
optionsSelectOption[]obrigatórioArray de { value, label, disabled? }
valuestringValor selecionado controlado
onChange(value: string) => voidTratador de seleção
placeholderstring"Select…"Texto de substituição
labelstringRótulo acima do acionador
errorstringMensagem de erro abaixo
disabledbooleanfalseImpede a interação
searchablebooleanfalseAdiciona campo de pesquisa dentro do dropdown
classNamestringAplicado ao contentor

Exemplo

const [dieta, setDieta] = useState("");

<Select
  label="Preferência alimentar"
  options={[
    { value: "none", label: "Sem preferência" },
    { value: "vegan", label: "Vegan" },
    { value: "vegetarian", label: "Vegetariano" },
    { value: "gluten-free", label: "Sem glúten" },
  ]}
  value={dieta}
  onChange={setDieta}
  searchable
/>

Skeleton

Placeholder de carregamento com animação de pulso.

Props do Skeleton

PropTipoPadrãoDescrição
variant"text" | "circular" | "rectangular""rectangular"Forma
widthstring | numberValor CSS de largura ou número em px
heightstring | numberValor CSS de altura ou número em px
linesnumber1Número de linhas de texto (apenas variant="text")
classNamestringClasses adicionais

SkeletonCard

Skeleton de cartão pré-construído para estados de carregamento:

<SkeletonCard />

Exemplos

// Linhas de texto
<Skeleton variant="text" lines={3} />

// Placeholder de avatar
<Skeleton variant="circular" width={40} height={40} />

// Placeholder de imagem
<Skeleton variant="rectangular" width="100%" height={200} />

// Cartão completo
<SkeletonCard />

Alert

Banner de feedback contextual com entrada animada e dispensa.

Props

PropTipoPadrãoDescrição
variant"info" | "success" | "warning" | "error""info"Variante de cor e ícone
titlestringLinha de título em negrito
dismissiblebooleanfalseMostra botão de dispensa (×)
onDismiss() => voidChamado ao dispensar
iconReactNodeSobrepõe o ícone padrão da variante
visiblebooleantrueControla a visibilidade AnimatePresence
classNamestringClasses adicionais

Exemplos

// Banner informativo estático
<Alert variant="info" title="Sabia que…?">
  Pode poupar até 20% ao mudar para o plano Pro.
</Alert>

// Erro dispensável
const [mostrar, setMostrar] = useState(true);
<Alert
  variant="error"
  title="Falha no envio"
  dismissible
  visible={mostrar}
  onDismiss={() => setMostrar(false)}
>
  O ficheiro excede o limite de 10 MB.
</Alert>

Divider

Separador visual, horizontal ou vertical.

Props

PropTipoPadrãoDescrição
orientation"horizontal" | "vertical""horizontal"Eixo
labelstringTexto de rótulo centrado (apenas horizontal)
classNamestringClasses adicionais

Exemplos

// Horizontal
<Divider />

// Com rótulo
<Divider label="ou continuar com" />

// Vertical (necessita contexto de altura definida)
<div className="flex h-8 items-center gap-4">
  <span>Opção A</span>
  <Divider orientation="vertical" />
  <span>Opção B</span>
</div>

On this page