Estudo de caso

Design System como infraestrutura de produto

Sisloc · Tokens, componentes e implementação

Transformando uma biblioteca visual em uma fundação de interface implementável, com tokens, APIs de componentes e documentação em código.

  • Design Systems
  • Design Engineering
  • Vue 3
  • Vuetify 3
  • Storybook
  • Design Tokens
baseprimitivemeaningsemanticinterfacecomponent
Componentes do Sisloc Design System executados no Storybook, incluindo diferentes estados do Stepper.
Componentes e estados em funcionamento no Storybook, incluindo o Stepper.

Do Figma a uma fundação implementável

O Sisloc já possuía padrões visuais definidos no Figma, mas transformar esses padrões em componentes reutilizáveis exigia mais do que reproduzir interfaces.

O trabalho passou a envolver decisões sobre:

  • como estruturar tokens;
  • como separar estado visual de comportamento;
  • como desenhar APIs de componentes;
  • quando reutilizar capacidades do Vuetify e quando criar abstrações próprias;
  • como manter Figma e implementação próximos sem depender de overrides frágeis;
  • como documentar os componentes para que pudessem ser reutilizados posteriormente.

A stack utilizada foi Vue 3, Vuetify 3, Vite e Storybook.

Tokens organizados em três camadas

O sistema começou com duas camadas de tokens:

primitive → semantic

Durante a implementação, ficou evidente que alguns valores pertenciam especificamente aos componentes. A estrutura evoluiu para:

primitive → semantic → component

Antes

primitivesemantic

Decisões específicas de componentes chegavam à camada semântica compartilhada.

Depois

primitivesemanticcomponent

Button, Input, Select, Modal, Snackbar, Chip e Tabs passaram a poder ter decisões próprias.

A terceira camada desacopla decisões locais dos significados compartilhados pelo sistema.

A arquitetura passou a contemplar cores primitivas, tokens semânticos para texto, feedback, bordas, tipografia e elevação, além de tokens específicos para componentes como Button, Input, Select, Modal, Snackbar, Chip e Tabs.

Prevendo conflitos antes que eles acontecessem

Outro problema apareceu antes mesmo de existirem muitos overlays: como garantir que dropdowns, elementos sticky, modais, tooltips e notificações não começassem uma guerra de z-index?

Em vez de definir valores isoladamente em cada componente, criei uma escala semântica:

  1. 01base
  2. 02raised
  3. 03dropdown
  4. 04sticky
  5. 05overlay
  6. 06modal
  7. 07toast
  8. 08tooltip
Uma regra arquitetural única substitui valores locais definidos componente a componente.

Isso transformou uma decisão normalmente local de CSS em uma regra de arquitetura do sistema.

O Stepper revelou um problema de modelagem

O Stepper foi o componente que mais expôs essa mudança de mentalidade.

As primeiras implementações tentavam resolver sua geometria alternando SVG, clip-path, sombras, pseudo-elementos e margens negativas.

Mas havia um problema mais profundo. O modelo misturava dois conceitos independentes: estado da etapa, com ativo, passado e próximo, e posição da etapa, com início, meio e fim.

Isso levou à criação de estados como passadoFinal e proximoFinal. Esses nomes pareciam representar estados, mas na prática eram combinações de estado e posição.

Redesenhando o modelo

Em vez de adicionar mais exceções, reorganizei o componente em dimensões independentes.

Modelo anterior

STATEativopassadopróximo
POSITIONiníciomeiofim
passadoFinalproximoFinal

Novo modelo

Estado controla aparência. Shape controla geometria.

Separar as dimensões remove estados combinados como completedEnd.

Agora, uma última etapa concluída não precisa de um estado específico como completedEnd. Ela é simplesmente state = completed e shape = end.

O estado passou a controlar aparência e a posição passou a controlar geometria.

Um modelo mais claro simplificou a implementação

A geometria também foi reconstruída. Em vez de tentar simular a forma usando recortes e sombras, passei a utilizar um path SVG explícito.

Antes

margin-left: -14px

overlap / composição frágil

Depois

CSS Grid · path SVG · gap

geometria explícita / composição previsível

Mudança estrutural da geometria do Stepper.
Stepper do Sisloc Design System executado no Storybook com cinco etapas e a segunda etapa ativa.
Stepper no Storybook após a separação entre estado e geometria.

A mudança partiu de uma releitura do próprio design: visualmente as etapas não se sobrepunham. Existia espaço entre elas.

O componente final passou a ter uma API simples:

Uso do SislocPath
<SislocPath
v-model="active"
:steps="steps"
:interactive="true"
/>

O aprendizado mais importante aqui foi não continuar corrigindo uma estrutura errada com mais CSS. Primeiro veio a arquitetura do componente; depois geometria, estados e apresentação.

A DataTable foi organizada por composição

A DataTable foi outro exercício importante de arquitetura.

Em vez de transformar tudo em um único componente, a solução foi composta por:

SislocDataTable composiçãoSislocPaginationSislocEmptyState
  • props
  • emits
  • slots
Pagination e EmptyState mantêm responsabilidades próprias e podem existir fora da tabela.
SislocDataTable no Storybook com linhas de leads, status, temperatura, menu de ações e paginação.
DataTable e paginação documentadas em um cenário de dados no Storybook.

A API da tabela utiliza props, emits e slots para permitir personalização sem criar novas variantes para cada necessidade.

Também foram implementados comportamentos como ordenação em três estados e seleção parcial usando o estado indeterminate nativo do checkbox.

No Kanban, frames não definiram a arquitetura

O Card Kanban trouxe o problema inverso. No Figma, elementos como Card, Tags, Footer Bar e Assigned Users apareciam organizados como frames distintos.

Seria fácil transformar cada frame em um componente. Mas separação visual não significa necessariamente reutilização.

Figma

CardTagsFooter BarAssigned Users
ImplementaçãoCardregiões internas
Frames separados no Figma não determinam automaticamente fronteiras de componentes.

Analisei a estrutura e tratei essas partes como regiões de um único componente, porque pertenciam ao mesmo modelo de Card.

Para reduzir aproximações durante a implementação, usei a API do Figma para inspecionar programaticamente dimensões e posições dos elementos do frame.

O comportamento do card também passou a derivar de estado, em vez de variantes visuais independentes:

Estado derivado do Card Kanban
const taskState = computed(() => {
if (!props.task) return 'empty'

return props.taskOverdue
  ? 'overdue'
  : 'scheduled'
})

Isso permitiu representar tarefa agendada, atrasada ou inexistente sem duplicar o componente.

O Accordion consolidou um contrato de API

O Accordion ajudou a consolidar um contrato entre API, estado, comportamento e apresentação.

Props

title · subtitle · defaultOpen · modelValue

Emits

update:modelValue · toggle
  • API
  • STATE
  • BEHAVIOR
  • PRESENTATION
controlled · internal state · aria-expanded · focus
O contrato reúne API, estado, comportamento e apresentação.

O componente suporta uso controlado e estado interno, com aria-expanded e estado de foco incorporados ao comportamento.

O Select definiu os limites entre Vuetify e Design System

No Select, mudanças em border-width e font-size interferiam no cálculo interno do notch do Vuetify. Entender esse comportamento permitiu definir melhor onde o componente base cuidaria das mecânicas e onde o Design System controlaria aparência e API.

Vuetify

keyboard · menu · outline mechanics

Design System

tokens · dimensions · appearance · API

border-width / font-sizenotch calculation
Entender a plataforma foi mais eficaz do que acumular overrides.

IA no processo

IA
  • exploração
  • implementação
  • debugging
  • leitura do Figma
Julgamento humano
  • arquitetura
  • fidelidade
  • trade-offs
  • decisão
Decisões de arquitetura, fidelidade e trade-offs permaneceram sob responsabilidade de design.

O sistema que começou a emergir

O fluxo de trabalho passou a aproximar design e implementação:

  1. Figma
  2. Design Tokens
  3. Component API
  4. Vue
  5. Storybook
A cadeia estava implementada até o Storybook nesta etapa. A integração ao produto final não fazia parte do escopo realizado.

Specs do Figma alimentam tokens e decisões de implementação. Os componentes expõem contratos por meio de props, emits e slots. O Storybook funciona como ambiente de desenvolvimento e documentação.

O que esse projeto mudou na minha prática

Uma variação que parece pequena no Figma pode criar uma nova combinação de estados no componente.

O trabalho deixou de ser apenas definir como a interface deve parecer. Passou também a envolver definir como ela deve ser modelada, implementada, reutilizada e mantida.