Componentes
A biblioteca
src/components/ui/* — shadcn/ui sobre Radix, editados pro canon. As demonstrações destas páginas importam os componentes de verdade: o que você vê aqui é literalmente o que a tela do app renderiza.Por assunto
Inventário
| Export | Arquivo | O que é |
|---|---|---|
| Button | ui/button.tsx | 7 variantes · 7 tamanhos · cva |
| Input | ui/input.tsx | Campo de uma linha, pílula |
| Textarea | ui/textarea.tsx | Multi-linha, canto 16 |
| SelectNative | ui/select-native.tsx | A caixinha da casa: painel no desktop, roleta do sistema no celular |
| SearchInput | ui/search-input.tsx | Input + lupa decorativa |
| LupaDeBusca | ui/lupa-de-busca.tsx | A lupa que vira pílula de busca: por cima da barra com achados (sobre, a Agenda) ou no lugar da lupa empurrando os vizinhos (empurra, o filtro de uma lista); com palavra ela fica aberta |
| InputOTP | ui/input-otp.tsx | Código de verificação, 6 slots |
| Checkbox | ui/checkbox.tsx | Radix · a única forma de 6px do app |
| Escolha | ui/escolha.tsx | Uma regra em duas palavras (“Ligado / Desligado”), no lugar do interruptor; radiogroup |
| Interruptor · LinhaDoInterruptor | ui/interruptor.tsx | Liga e desliga numa coluna de linhas iguais (o “Aparece” das origens e dos motivos) e na tela de Serviços; role switch |
| AlcaDeOrdem · useArrastoNaLista | ui/alca-de-ordem.tsx | Mudar a ordem de uma lista: arrasto em prévia, ↑/↓ com a alça em foco |
| Label | ui/label.tsx | Radix · liga rótulo e controle |
| Field · SelectField · TextareaField | ui/field.tsx | Rótulo + controle + erro + dica, já costurados |
| FormAlert · FieldError · useFieldErrors | ui/form-feedback.tsx | Erro de formulário e de campo |
| PositiveBanner | ui/positive-banner.tsx | A contraparte calma do FormAlert |
| Card · CardHeader · CardTitle · CardDescription · CardContent | ui/card.tsx | A superfície padrão |
| Dialog | ui/dialog.tsx | Radix · modal do canon |
| ConfirmDialog | ui/confirm-dialog.tsx | Sim/não sobre o Dialog |
| ConfirmStrip · ConfirmTrigger · useConfirm | ui/confirm-strip.tsx | Confirmação destrutiva sem modal |
| DropdownMenu | ui/dropdown-menu.tsx | Radix · menu de AÇÃO (e de escolha curta) |
| InsumoPickerDialog | ajustes/precificacao/insumo-picker-dialog.tsx | O molde do picker: escolher entre muitos, com busca, dentro de um Dialog |
| StatusPill | ui/status-pill.tsx | Selo de status — fonte visual única |
| EmptyState | ui/empty-state.tsx | Vazio padrão, moldura tracejada; densidade bloco dentro de cartão |
| ChipDeRecorte | ui/chip-de-recorte.tsx | Chip que liga e desliga um recorte de lista (filtro), com aria-pressed |
| CampoDeLista | ui/campo-de-lista.tsx | Lista fechada que se digita: a busca só procura; janela de 4 itens com o deslize da roleta, que FLUTUA por cima do formulário (posicionada no campo, sem portal: não empurra nada e não conta como clique fora pra bolha da Agenda), e uma opção fixa no fim ("Outro"). Com a prop criar, o nome que não existe vira a última linha ("+ Criar grupo"), e criar é um gesto, nunca efeito de digitar. CaixaDeLista é a mesma lista só com a caixa, pra uma linha que já tem rótulo (o serviço da Agenda: detalhe à direita, "3 de 128 serviços" no pé) |
| BotaoFiltrar · BotaoFiltrarVarios | ui/botao-filtrar.tsx | Filtro de lista: botão Filtrar ao lado da busca, menu de recortes com contagem, um por vez; ou vários, com caixinha e sem contagem (o Funil); preferido à fileira de chips, que não cresce bem |
| SkeletonBlocos | ui/skeleton-blocos.tsx | Esqueleto das telas de rail |
| DicasDaCasa | ui/dicas-da-casa.tsx | A dica da casa, montada uma vez no layout raiz: parar o mouse num botão só de ícone ou em algo com title mostra o nome numa pílula em 0,3 s (a vizinha vem na hora); data-sem-dica fica de fora |
| BarraFlutuante · AcaoDaBarra · FioDaBarra · RESERVA_DA_BARRA | ui/barra-flutuante.tsx | A barra de seleção: ilha ink-950 na base da tela, só ícones com o nome no balão da dica, vermelho negative-dark no gesto que tira, nome curto embaixo do ícone no toque; a folga do pé da tela mora na constante |
| Rolagem · useVeuDaRolagem · VeuDaRolagem | ui/rolagem.tsx | Lista com teto dentro de janela, painel, menu ou caixa de busca: o fio da barra (que vem do globals.css pra toda rolagem) mais o véu de 36px no pé, que só aparece quando tem mais embaixo. Coluna que enche a tela fica só com o fio: véu fixo no pé de uma tela inteira cobriria a última linha |
| Toaster | ui/sonner.tsx | Sonner com os ícones e o raio do canon |
| BotaoCopiar · useCopiar | ui/copiar.tsx | Ícone de copiar no hover do dado (sempre à vista no toque) + aviso “Copiado” com o dado |
| AvatarBubble | ui/avatar-bubble.tsx | Retrato de conta, 32px |
| CardIconBadge | ui/card-icon-badge.tsx | Selo circular no topo de cards de fluxo |
| SettingsRow | ui/settings-row.tsx | Linha de configuração: texto à esquerda, ação à direita |
| RailLinks · RailGroups · RailAnchors | ui/rail-nav.tsx | Miolo dos rails laterais; RailAnchors é o rail que indexa a própria página |
| CrudCard · EditSurface · CrudRowShell … | ui/crud-block.tsx | Vocabulário da edição no lugar |
| Gaveta | ui/gaveta.tsx | O vão que cresce e encolhe no lugar |
| PageBar · PageBody · PageStage | components/page-*.tsx | Os cabeçalhos e o corpo de uma tela |
Como um componente entra
Primeiro, procure
Quase tudo já existe com outro nome. Escolher 1 entre N é SearchSelect; agir é DropdownMenu; confirmar destruição é ConfirmStrip; editar no lugar é CrudCard + Gaveta.
Depois, componha
Card + Field + Button resolvem a maioria das telas novas. Componente novo é o último recurso, não o primeiro.
Se entrar, entra em ui/
Com data-slot, className por cn(), props do elemento nativo repassadas e comentário dizendo QUAL regra do canon ele veste.
E entra nesta página
Componente sem página aqui é componente que vai divergir. A regra de manutenção é: mudou o canon, muda o guia no mesmo commit.
NotaA convenção data-slot
data-slot="button", data-slot="card" e afins. Não é enfeite: é o que permite uma regra global alcançar “todo card da tela” sem que nenhum card precise saber disso — é assim que o foco em camadas aplica a película sem tocar em um único componente.Os primitivos aceitam className e passam adiante as props do elemento nativo. A classe do chamador entra por último no cn(), então ela vence — mas sobrepor a forma (trocar o raio, mudar a altura de um botão) é sinal de que a tela está fugindo do canon, não de que o componente falta uma prop.