Design system interno · uso exclusivo da Up Web Studio

Icon Provider · Lucide

Ajuda do Up Web DS

Como classificar, importar, criar, validar e distribuir componentes do Design System interno da Up Web Studio.

Importar não significa aprovar.

Todo item externo entra como matéria-prima e precisa passar por normalização, examples, testes, preview e validação antes de stable.

Introdução

O Up Web DS é uma camada de normalização entre fontes externas, componentes internos e os produtos da equipe. Nada entra por conveniência: cada item declara o que é, de onde veio, sob qual licença, e o que já foi verificado nele.

Esta página é a referência rápida para pessoas. AGENTS.md continua sendo a referência de engenharia para agentes, e as duas descrevem a mesma política — a taxonomia e as tabelas aqui são lidas de src/catalog/taxonomy.ts, o mesmo módulo que o CLI e o ds:validate usam para aceitar ou recusar um item.

Como classificar um item

A metadata tem três eixos independentes. Responder aos três é o que transforma um arquivo em um item do design system.

type
Onde o item vive na arquitetura.
category
O que o item faz na interface.
domain
Em qual contexto de produto ele ganha significado.

Os três eixos são independentes. Nunca use um deles para representar outro: category não é layer, domain não é categoria, e type não é o lugar onde o arquivo mora.

Guia de decisão

É uma unidade genérica de UI?
primitive
É só uma aparência diferente de um primitive existente?
recipe
É uma composição reutilizável com significado?
component
Resolve um fluxo recorrente?
pattern
É uma seção grande de página?
block
É um ponto de partida de página ou app?
template

Type

type é o nível de abstração — o que o item é arquiteturalmente. São seis valores, e a lista é fechada.

Types do Up Web DS
TypeO que éDomain
primitiveA menor unidade genérica de UI.Button · Input · Textarea · Checkbox · Radio Group · Select · Switch · Dialog · Popover · Tooltip · Tabs · Accordionnull
recipeUma variação visual construída sobre um primitive que já existe.Shimmer Button · Neumorph Button · Glass Card · Glow Buttonnull
componentComposição reutilizável com significado próprio, acima de um primitive.Search Field · Data Toolbar · Question Card · Product Card · Course Cardobrigatório
patternSolução recorrente para um fluxo ou problema de interação.Search Filters · Delete Confirmation · File Upload Flow · Quiz Navigation · Checkout Stepsobrigatório
blockSeção grande e reutilizável de uma página ou experiência.Hero · Pricing Section · Product Grid · Course Sidebar · Checkout Summaryobrigatório
templateEstrutura quase completa, usada como ponto de partida.Learning App Shell · Dashboard · Product Page · Storefront · Marketing Landing Pageobrigatório

layout não é um type. Uma estrutura pequena e genérica é primitive com category: 'layout'; uma estrutura grande é block ou template. Foundation também não é um type: tokens, tipografia e a escala de motion vivem na folha de estilo da Foundation, não em um diretório de item.

Category

category é a família funcional: o que o item faz na interface. Não representa layer e não representa domínio.

Primitives e recipes

Categorias de primitives e recipes
CategoryCobre
actionButton, Toggle, Toggle Group.
inputInput, Textarea.
selectionCheckbox, Radio Group, Select, Combobox, Switch. Select usa popup internamente, mas a função é seleção.
overlayDialog, Alert Dialog, Popover, Tooltip, Hover Card, Sheet, Drawer.
navigationTabs, Breadcrumb, Pagination.
disclosureAccordion, Collapsible.
feedbackAlert, Progress, Skeleton, Spinner.
data-displayBadge, Avatar, Separator, Table.
layoutScroll Area, Resizable, Aspect Ratio.

Um Select abre um popup para funcionar, mas a função é escolher um valor: ele é selection, não overlay.

Por domínio

Componentes de domínio não são forçados nas categorias de primitive quando isso destrói o significado. O domínio application reaproveita as famílias funcionais: uma Command Palette é overlay e uma Filter Bar é selection.

Categorias aceitas por domínio
DomainCategories
Applicationactioninputselectionoverlaynavigationdisclosurefeedbackdata-displaylayout
Educationassessmentlearningcourseprogresscontentlayout
Ecommerceproductcartcheckoutpricingorderlayout
Marketingherosocial-prooffeaturespricingctacontentlayout
Legallegislationjurisprudencecitationannotationlegal-contentlayout

Domain

domain é o contexto de produto em que o item ganha significado. primitive e recipe são sempre null; os demais types exigem um domínio.

Domínios do Up Web DS
DomainCobreExemplos
applicationComposições genéricas de dashboards, sistemas administrativos e ferramentas internas.Search Field · Data Toolbar · Command Palette · Filter Bar
educationAprendizagem, avaliação e progresso do aluno.Question Card · Flashcard · Lesson Progress · Course Card
ecommerceCatálogo, carrinho, checkout e pós-venda.Product Card · Cart Item · Checkout Steps · Product Gallery
marketingPáginas de aquisição, prova social e conversão.Hero · Pricing Section · Testimonials · CTA Section
legalLegislação, jurisprudência e material jurídico anotado.Legal Citation · Legislation Viewer · Jurisprudence Card · Annotation Panel

Domínio é classificação, nunca comportamento: nenhum item muda o que faz em runtime por causa do seu domain.

Exemplos de classificação

Exemplos de classificação
ItemTypeCategoryDomain
ButtonprimitiveactionDomain-free
InputprimitiveinputDomain-free
Radio GroupprimitiveselectionDomain-free
SelectprimitiveselectionDomain-free
DialogprimitiveoverlayDomain-free
AccordionprimitivedisclosureDomain-free
Question Cardcomponentassessmenteducation
Product Cardcomponentproductecommerce
Pricing Sectionblockpricingmarketing
Learning App Shelltemplatelayouteducation

Na interface, domain: null aparece como Domain-free. No código continua sendo null.

Lifecycle

Todo item nasce incoming e sobe por prova, não por decisão. Somente stable entra no registry consumível.

  1. incomingAparece no catálogo, fora do registry.Scaffold ou matéria-prima recém-ingerida. A normalização ainda não aconteceu.
  2. experimentalAparece no catálogo, fora do registry.Implementação em avaliação: existe, funciona, mas o contrato ainda pode mudar.
  3. stableÚnico status publicado no registry consumível.Contrato aprovado. Exige metadata, examples, testes, tokens, acessibilidade, dark mode, responsivo, ícones semânticos, motion e validators verdes.
  4. deprecatedAparece no catálogo, não é distribuído como item novo.Mantido por compatibilidade e documentação, com substituto planejado.

Adicionar do shadcn/ui

O caminho tem duas etapas separadas de propósito: inspecionar não baixa nada para src/, e promover é uma decisão explícita.

1. Inspecionar

Inspecionar Select
npm run ds:inspect -- \
  --source shadcn \
  --name select

Mostra staging, licença, dependências, ícones semânticos, normalizações conhecidas e findings — sem escrever em src/.

2. Adicionar — fluxo interativo

Adicionar Select (interativo)
npm run ds:add -- \
  --source shadcn \
  --name select \
  --type primitive \
  --category selection

O CLI pergunta se deve criar o scaffold. Responder `y` cria o item em src/ como incoming.

3. Adicionar — fluxo explícito

Adicionar Select sem prompts
npm run ds:add -- \
  --source shadcn \
  --name select \
  --type primitive \
  --category selection \
  --promote

Sem --promote, ds:add escreve apenas em .tmp/ds-ingest (staging) e .ds/ingestion (proveniência).

Um scaffold, não dois

Não execute --promote depois de já responder y ao scaffold. O item já existe e o CLI reporta conflito — corretamente.

Outros exemplos

Inspecionar Dialog
npm run ds:inspect -- \
  --source shadcn \
  --name dialog
Adicionar Dialog
npm run ds:add -- \
  --source shadcn \
  --name dialog \
  --type primitive \
  --category overlay
Inspecionar Radio Group
npm run ds:inspect -- \
  --source shadcn \
  --name radio-group
Adicionar Radio Group
npm run ds:add -- \
  --source shadcn \
  --name radio-group \
  --type primitive \
  --category selection

Adicionar de outras fontes

A fonte não define o type. Um item do Magic UI pode ser uma recipe, um do Kibo pode ser um component, e o mesmo registry pode fornecer os dois — a classificação é decidida depois do inspect, com o código à vista.

Fontes suportadas pelo CLI
SourceNomeLicençaSituação
shadcnshadcn/uiMITRegistry HTTP configurado.
cossCoss UIMITRegistry HTTP configurado.
kiboKibo UIMITRegistry HTTP configurado.
magicMagic UIMITRegistry HTTP configurado.
cultCult UIMITRegistry HTTP configurado.
ncdaiChánh ĐạiMITRegistry HTTP configurado.
tailwindPlusTailwind Plusinternal-restrictedLicenciada: entra por --from-file, sob revisão humana.

Magic UI — recipe sobre primitive

Inspecionar Shimmer Button
npm run ds:inspect -- \
  --source magic \
  --name shimmer-button
Adicionar como recipe de Button
npm run ds:add -- \
  --source magic \
  --name shimmer-button \
  --type recipe \
  --category action \
  --base button

Se é aparência de Button, é uma recipe do Button oficial. Não se cria um segundo primitive.

Kibo UI — componente composto

Inspecionar Gantt
npm run ds:inspect -- \
  --source kibo \
  --name gantt
Adicionar Gantt
npm run ds:add -- \
  --source kibo \
  --name gantt \
  --type component \
  --domain application \
  --category data-display

A categoria final é confirmada semanticamente depois do inspect, não deduzida da fonte.

Coss UI — primitive que já existe

Comparar com o Button oficial
npm run ds:compare -- \
  --source coss \
  --name button \
  --against button

Comportamento genérico melhor → incorporar ao primitive oficial. Aparência diferente → recipe.

Não existe Button2, CossButton nem ButtonV2. Se o item externo tem comportamento genérico melhor, ele é incorporado ao primitive existente para que todas as recipes herdem.

Cult UI e Chánh Đại

Inspecionar item de Cult UI
npm run ds:inspect -- \
  --source cult \
  --name <item>
Inspecionar item de Chánh Đại
npm run ds:inspect -- \
  --source ncdai \
  --name <item>

Criar do zero

Antes de implementar: procure primitives existentes, componha Button/Radio/Badge em vez de duplicar comportamento de foundation, e não acople o item a Firebase, Supabase, Prisma, Server Actions ou autenticação. Um item recebe dados e devolve eventos por props.

Criar Question Card
npm run ds:create -- \
  --type component \
  --domain education \
  --name question-card \
  --category assessment \
  --description "Enunciado, alternativas e feedback de uma questão."

O scaffold nasce incoming: implementação, examples, testes e revisão de acessibilidade são do autor.

Estrutura gerada
src/components/education/question-card/
├── question-card.tsx
├── question-card.examples.tsx
├── question-card.meta.ts
├── question-card.test.tsx
└── index.ts
API correta: dados e callbacks
<QuestionCard
  question={question}
  value={value}
  onValueChange={setValue}
/>

Adicionar código licenciado

Fontes comerciais não são baixadas automaticamente. O código chega por --from-file, sob revisão humana de licença.

Ingerir um Hero do Tailwind Plus
npm run ds:add -- \
  --source tailwindPlus \
  --name hero \
  --from-file ./hero.tsx \
  --type block \
  --domain marketing \
  --category hero

Acrescente --promote quando a revisão terminar; sem ele o item fica em staging.

Uso não é redistribuição

Tailwind Plus e outras bibliotecas comerciais nascem distribution: 'restricted'. O build do registry as exclui automaticamente (DS004). Usar em uma entrega da Up Web Studio não dá direito de redistribuir por registry.

Restrito não é isento: o código licenciado passa pelos mesmos tokens, primitives, API pública, light/dark, acessibilidade, responsividade, testes e preview que qualquer outro item.

Quando o componente já existe

Se ds:add reportar conflito, não force outro nome. Compare.

Comparar antes de decidir
npm run ds:compare -- \
  --source coss \
  --name button \
  --against button
O que fazer com um item que já existe
SituaçãoDecisão
Comportamento genérico melhorIncorpore ao item existente, para que todas as recipes herdem.
Aparência diferenteRecipe sobre o primitive oficial.
Semântica de domínio novaComponent ou pattern — se realmente houver uma solução nova, não só um nome novo.

Normalização obrigatória

A automação detecta e relata; ela não decide semântica. Qual token um azul representa é decisão de quem tem contexto de produto. Esta é a lista que um item precisa fechar antes de reivindicar stable.

Classificação e origem

  • type, category e domain corretos
  • source e licença registrados
  • primitives existentes reutilizados
  • API pública normalizada

Foundation

  • tokens semânticos de cor, radius e sombra
  • ícones semânticos do adapter
  • motion semântico (duration-fast / default / slow)
  • light mode
  • dark mode
  • responsivo

Acessibilidade

  • teclado
  • foco visível
  • leitor de tela quando aplicável
  • touch quando aplicável
  • reduced motion quando aplicável

Prova

  • examples
  • testes unitários e de integração
  • E2E quando a afirmação depende de layout
  • preview

Validação

npm run check encadeia biome, typecheck, testes, ds:catalog --check, ds:validate, ds:icons:validate e registry:validate. É o portão que precisa estar verde antes de concluir qualquer tarefa.

Sequência recomendada
npm run ds:catalog
npm run ds:validate
npm run ds:icons:validate
npm run check
npm run test:e2e
npm run ds:registry

test:e2e quando a mudança envolve layout, toque ou reduced motion; ds:registry quando o item realmente virou stable.

O que cada comando responde
ComandoPergunta que responde
npm run ds:catalogO catálogo tipado reflete os *.meta.ts em disco?
npm run ds:validateAs políticas do design system estão satisfeitas (DS001–DS014)?
npm run ds:icons:validateCada papel semântico compila nos quatro providers de ícone?
npm run checkLint, tipos, testes, catálogo, políticas e registry — tudo junto.
npm run test:e2eO que só existe com layout: contraste, alvo de toque, reduced motion.
npm run ds:registryO registry consumível corresponde à metadata atual?

Publicação no registry

Catálogo e registry respondem perguntas diferentes. O preview documenta o que a equipe está construindo; o registry distribui o que um produto pode instalar.

Catálogo e registry
SuperfícieO que contém
preview / catálogoincoming, experimental, stable e deprecated.
registry consumívelApenas stable, e nunca restricted.

Interface oficial de consumo

Instalar um item em um projeto
up-web-ds add dialog

Só este CLI lê components.json → iconLibrary, instala o provider certo e gera o adapter de ícones. O registry por baixo é infraestrutura que ele consome.

Não é o caminho oficial

npx shadcn add @up-web-ds/dialog instala os arquivos sem resolver a biblioteca de ícones do projeto. O componente chega sem o adapter que ele importa.

Troubleshooting rápido

Problemas frequentes
SintomaO que fazer
ds:add reporta conflito de idO item já existe. Rode ds:compare em vez de inventar outro nome.
Invalid metadata classificationA combinação type / category / domain não é aceita. A mensagem lista os valores válidos.
DS012: item não registrado no catálogoRode npm run ds:catalog depois de criar ou alterar metadata.
DS014: duração fora da escala de motionUse duration-fast, duration-default ou duration-slow. O que não tem equivalência exata espera decisão sua.
DS_ICON_002: mapping incompletoMapeie o papel nos quatro providers em scripts/ds/icons/mappings.ts e rode npm run ds:icons.
DS004: item restrito no registryConfira distribution: a licença de uso não autoriza redistribuição.
DS011: stable sem Definition of DoneComplete examples, testes e a revisão de acessibilidade, ou volte o item para experimental.