Os 56 blocos de base do Design System, alinhados com o shadcn/ui, e as 4 composições iGRP da camada Custom — quando usá-los e como acrescentar um componente.
Além dos componentes IGRP* da camada Horizon, o Design System exporta duas camadas: os Primitives, os blocos de base, e os Custom, composições próprias da plataforma. Todos saem da raiz do pacote:
'use client';
import { Button, Dialog, DialogContent, DialogTitle } from '@igrp/igrp-framework-react-design-system';
import { IGRPStatsCardMini } from '@igrp/igrp-framework-react-design-system';Os Primitives são exportados com o nome do shadcn, sem prefixo nem sufixo: Button, Dialog, Table, Sheet… Os Horizon e os Custom usam o prefixo IGRP.
Secção em construção
Primitive ou Horizon
| Primitives | Horizon | |
|---|---|---|
| Para quê | Blocos de base: estilo mínimo, máxima flexibilidade | Componentes opinativos para os padrões comuns do iGRP |
| Assenta em | Radix UI e variantes CVA | Nos Primitives (são wrappers) |
| Props | Props HTML/React + variantes (variant, size, asChild) | Props iGRP (label, helperText, showIcon, iconName, loading…) |
| Formulários | Nenhuma ligação | Ligados ao IGRPForm e ao react-hook-form |
| Usa quando | Precisas de controlo total ou de uma composição própria | Queres formulários, botões com ícone/carregamento, campos com label… |
Prefere sempre o Horizon
Desce para um Primitive só quando o componente Horizon é demasiado opinativo para o caso. O gerador do Studio emite componentes Horizon (e o IGRPStatusBanner da camada Custom), nunca Primitives.
// Primitive — um botão estilizado; tudo o resto é contigo
<Button variant="outline" size="sm">Guardar</Button>
// Horizon — ícone, estado de carregamento e atributos iGRP
<IGRPButton showIcon iconName="ArrowRight" loading={isSubmitting} loadingText="A guardar...">
Guardar
</IGRPButton>Catálogo dos Primitives
Cada linha é um ficheiro em src/components/primitives/. A coluna Exports lista o componente raiz; as partes (DialogTitle, TableRow…) seguem a nomenclatura do shadcn.
Formulário
| Exports | Para quê | Horizon equivalente |
|---|---|---|
Form, FormField, FormItem, FormLabel, FormControl, FormMessage, useFormField | Contexto react-hook-form (sem submissão nem Zod) | IGRPForm |
Field, FieldLabel, FieldError, FieldSet… | Estrutura de campo: label, descrição, erro, grupos | — |
Input | Campo de texto | IGRPInputText, IGRPInputNumber, IGRPInputPassword, IGRPInputUrl, IGRPInputSearch |
InputGroup, InputGroupInput, InputGroupAddon… | Campo com ícone, botão ou prefixo | IGRPInputAddOn |
InputOTP, InputOTPSlot… | Código de uso único (OTP) | — |
Textarea | Texto multilinha | IGRPTextarea |
Label | Label acessível | IGRPLabel |
Checkbox | Caixa de seleção | IGRPCheckbox |
RadioGroup, RadioGroupItem | Escolha única | IGRPRadioGroup |
Switch | Interruptor on/off | IGRPSwitch |
Select, SelectTrigger, SelectItem… | Lista de opções | IGRPSelect |
NativeSelect, NativeSelectOption | <select> nativo estilizado | — |
Slider | Valor num intervalo | — |
Calendar | Calendário | IGRPCalendarSingle, IGRPCalendarRange, IGRPCalendarMultiple |
Toggle, ToggleGroup | Botões de alternar | — |
Button | Botão | IGRPButton |
ButtonGroup | Grupo de botões encostados | — |
Overlays
| Exports | Para quê | Horizon equivalente |
|---|---|---|
Dialog, DialogContent, DialogTitle… | Diálogo modal (DialogTitle obrigatório) | IGRPModalDialog |
AlertDialog… | Confirmação | IGRPAlertDialog |
Sheet, SheetContent, SheetTitle… | Painel lateral | — |
Drawer, DrawerContent, DrawerTitle… | Painel inferior (bottom sheet) | — |
Popover, PopoverContent… | Conteúdo flutuante ancorado | — |
HoverCard… | Cartão ao passar o rato | — |
Tooltip, TooltipProvider… | Dica curta | — |
DropdownMenu, DropdownMenuItem… | Menu de ações | IGRPDropdownMenu |
ContextMenu… | Menu do botão direito | — |
Command, CommandDialog, CommandInput… | Lista pesquisável, paleta de comandos | IGRPCommand, IGRPCombobox |
Navegação
| Exports | Para quê | Horizon equivalente |
|---|---|---|
NavigationMenu… | Menu de navegação | IGRPMenuNavigation |
Menubar, MenubarMenu… | Barra de menus | IGRPMenubar |
Sidebar, SidebarMenu, SidebarProvider… | Barra lateral da aplicação | — |
Breadcrumb, BreadcrumbList… | Trilho de navegação | — |
Pagination… | Paginação | — |
Tabs, TabsList, TabsTrigger, TabsContent | Separadores | IGRPTabs |
Stepper, StepperItem… | Passos numerados | — (para processos, IGRPStepperProcess) |
Dados e layout
| Exports | Para quê | Horizon equivalente |
|---|---|---|
Table, TableRow, TableCell… | Tabela HTML estilizada | IGRPDataTable |
Card, CardHeader, CardContent… | Superfície em cartão | IGRPCard, IGRPCardDetails, IGRPInfoCard, IGRPStatsCard |
Item, ItemContent, ItemActions… | Linha de lista com media e ações | — |
ChartContainer, ChartTooltip, ChartLegend… | Base para gráficos Recharts | IGRPAreaChart, IGRPLineChart, IGRPPieChart… |
Accordion, AccordionItem… | Secções colapsáveis | IGRPAccordion |
Collapsible… | Um bloco que abre e fecha | — |
Carousel, CarouselItem… | Carrossel | — |
ScrollArea | Área com scroll estilizado | — |
ResizablePanelGroup, ResizablePanel, ResizableHandle | Painéis redimensionáveis | — |
Separator | Linha divisória | IGRPSeparator |
AspectRatio | Proporção fixa | — |
Avatar, AvatarImage, AvatarFallback | Avatar (fallback obrigatório) | IGRPAvatar |
Badge | Etiqueta | IGRPBadge |
Kbd, KbdGroup | Tecla de atalho | — |
Feedback
| Exports | Para quê | Horizon equivalente |
|---|---|---|
Alert, AlertTitle, AlertDescription | Mensagem em bloco | IGRPAlert, IGRPBanner |
Empty, EmptyTitle… | Estado vazio | — |
Toaster | Toasts (com toast() do sonner) | IGRPToaster / useIGRPToast |
Progress | Barra de progresso | — |
Skeleton | Placeholder de carregamento | — |
Spinner | Indicador de carregamento | IGRPLoadingSpinner |
Outros
| Exports | Para quê | Horizon equivalente |
|---|---|---|
Cropper, CropperImage, CropperCropArea | Recorte de imagem | IGRPImageCropper |
Diferenças face ao shadcn
Estes Primitives divergem de propósito do shadcn — tem-nas em conta antes de copiar código do site do shadcn.
| Primitive | Diferença |
|---|---|
Button | Tamanhos extra xs, icon-xs, icon-sm, icon-lg, além de sm, default, lg, icon |
Accordion | AccordionTrigger aceita iconName, showIcon e iconPlacement (o indicador pode ser escondido, trocado ou ir para o início); respeita prefers-reduced-motion |
Form | FormItem usa flex flex-col gap-2 em vez de grid; FormMessage tem role="alert" para os leitores de ecrã anunciarem os erros |
Popover | PopoverContent aceita container, para abrir dentro de um Dialog ou Drawer sem partir o foco |
RadioGroup | RadioGroupItem tem variant (default, outline, soft) e size (sm, md, lg) |
Componentes Custom
Composições iGRP sobre os Horizon e os Primitives, em src/components/custom/. As cores aceitam primary, secondary, success, warning, info, destructive e indigo; os estilos aceitam solid, soft e outline.
IGRPStatsCardMini
Cartão de indicador compacto: título, valor e ícone com contorno, numa só cor. Aceita as props de conteúdo do IGRPStatsCard, mas a aparência resume-se a variant.
| Prop | Tipo | Descrição |
|---|---|---|
title | string | Título |
value | string | number | Valor em destaque |
iconName | string | Ícone Lucide |
variant | cor | Cor do valor e do ícone (por defeito primary) |
titleSize / valueSize | tamanho | Por defeito sm / 2xl |
onClick | () => void | Torna o cartão clicável |
<IGRPStatsCardMini title="Pedidos abertos" value={128} iconName="Inbox" variant="info" />IGRPStatsCardTopBorderColored
Cartão de indicador com uma borda colorida no topo e o ícone à direita.
| Prop | Tipo | Descrição |
|---|---|---|
title | string | Título |
value | string | number | Valor em destaque |
iconName | string | Ícone Lucide |
cardVariant | cor | Cor da borda e do ícone |
<IGRPStatsCardTopBorderColored title="Concluídos" value="94%" iconName="CircleCheck" cardVariant="success" />IGRPStatusBanner
Gerado pelo StudioFaixa de estado: um IGRPAlert com um ponto colorido e o texto, mais um IGRPBadge à direita.
| Prop | Tipo | Descrição |
|---|---|---|
text | string | Texto do estado |
color / variant | cor / estilo | Cor e estilo da faixa (por defeito success / soft) |
badgeText | string | Texto do badge |
badgeColor / badgeVariant | cor / estilo | Cor e estilo do badge (por defeito primary / outline) |
<IGRPStatusBanner text="Pedido em análise" color="warning" badgeText="Em curso" badgeColor="warning" />IGRPUserAvatar
Avatar de utilizador: mostra a imagem e, se não houver ou falhar, o conteúdo de fallback.
| Prop | Tipo | Descrição |
|---|---|---|
image | string | null | URL da imagem |
alt | string | Texto alternativo (por defeito Current User) |
fallbackContent | ReactNode | Obrigatório. Normalmente as iniciais |
fallbackClass | string | Classes do fallback |
<IGRPUserAvatar image={user.avatarUrl} alt={user.name} fallbackContent="AS" />Acrescentar um componente
Existe no shadcn? Primeiro um Primitive
Copia-o do shadcn para src/components/primitives/, comparando com o upstream (o fluxo --diff do CLI do shadcn, num diretório temporário).
Todas as aplicações vão querer o mesmo? Um wrapper Horizon
Se todas as aplicações precisam das mesmas labels, ícones, estado de carregamento ou ligação ao formulário, acrescenta um componente IGRP* em src/components/horizon/ por cima do Primitive.
É específico do domínio iGRP? Custom
Variantes de cartões de indicadores, avatares, faixas de estado e afins vão para src/components/custom/.
Cada Primitive guarda no comentário inicial a data da última sincronização com o shadcn (por exemplo /* shadcn: 2026-09-15 */; // shadcn: … também é aceite). Para saber se o upstream mudou desde então, a partir de packages/design-system/:
pnpm drift:shadcn # node scripts/check-shadcn-drift.mjs
pnpm drift:shadcn:update # novo baseline, depois de rever as mudançasSe o upstream mudou algo de que divergimos de propósito, regista a diferença em COMPONENTS.md antes de atualizar o baseline.
Explorar no Storybook
O monorepo tem um Storybook com os componentes, no pacote packages/design-system-storybook:
cd shared/frontend/nextjs/packages/design-system-storybook
pnpm storybook # http://localhost:6006Última atualização:
