Trechos do apêndice "React, Tailwind e o CSS que o agente ainda não conhece" Curso Frontends com Vibecoding alexandrecaramaschi.com/educacao/frontends-com-vibecoding#react-tailwind-na-pratica Oito trechos: três pedidos prontos para o agente e cinco trechos de folha de estilo, quase todos de recursos que o agente não escreve sozinho. Leia antes o LEIA-ME.txt desta pasta. AVISO DE FAIXA. Vários recursos deste arquivo ainda não estão em todos os navegadores na data da revisão do capítulo. Nenhuma linha aqui afirma a faixa de hoje: confirme no painel de compatibilidade antes de adotar, e mantenha o plano B que cada trecho já traz. ================================================================================ ### O que faz: pede ao agente a refatoração do estado pela regra dos quatro tipos ### Onde entra: a caixa de conversa do agente, com o componente de painel aberto ### Cuidado: descreva o seu componente no lugar do painel de pedidos do exemplo Refatore o estado deste componente seguindo a regra dos quatro tipos. Contexto: um que hoje usa SEIS useState: lista de pedidos vinda da API, lista filtrada, total, termo de busca, aba ativa (Todos/Pendentes/Pagos) e número da página, todos sincronizados na mão dentro de vários useEffect. Classifique cada pedaço de estado em: local, derivado, compartilhado de cliente ou de servidor. Depois reescreva assim: - dado da API (pedidos): mover para cache de servidor com TanStack Query (useQuery, queryKey ['pedidos']); remover o useEffect de fetch. - lista filtrada e total: NÃO são estado, então derive na renderização a partir dos pedidos e do termo de busca. - busca, aba ativa e página: mover para a URL com nuqs (useQueryState), para sobreviver a reload e ser compartilhável. - só o que for genuinamente local fica em useState. Stack-alvo: React 19 + TypeScript + Tailwind v4. Mantenha acessibilidade (role/aria nas abas, foco visível) e os estados de carregando/erro/vazio. NÃO traga Redux nem um store global para dado que já vem do servidor. Explique, em comentários, por que cada peça foi para onde foi. ================================================================================ ### O que faz: galeria em mural com o nome novo do recurso e plano B em colunas de CSS ### Onde entra: folha de estilo da galeria de fotos ou de cartões de alturas diferentes ### Cuidado: grid-lanes estreou num navegador só e segue fora do Baseline; a sintaxe antiga com masonry foi abandonada /* Galeria masonry com o nativo de 2026 e fallback honesto */ .galeria { /* Fallback universal: CSS columns (funciona em todo lugar) */ columns: 3; column-gap: 1rem; } @supports (display: grid-lanes) { .galeria { columns: unset; /* desliga o fallback */ display: grid-lanes; grid-template-columns: repeat(3, 1fr); gap: 1rem; } } ================================================================================ ### O que faz: pede a galeria em mural pelo nome certo, com o plano B exigido no próprio pedido ### Onde entra: a caixa de conversa do agente, com os cartões da galeria abertos ### Cuidado: sem citar o nome novo, o que volta é a sintaxe abandonada, escrita com toda a confiança Monte uma galeria masonry para estes cards usando display: grid-lanes (a sintaxe nova do CSSWG, NÃO grid-template-rows: masonry, que foi abandonada). Requisitos: - fallback em CSS columns dentro de @supports not (display: grid-lanes), de modo que a galeria fique utilizável em todo navegador atual; - 3 colunas no desktop, 2 no tablet, 1 no mobile, via container queries; - gap de 1rem; sem nenhuma biblioteca de masonry em JavaScript. Critérios de aceite: - em um navegador sem grid-lanes, a galeria renderiza em colunas sem quebrar; - nenhuma dependência nova foi adicionada; - me explique em uma frase por que grid-template-rows: masonry NÃO foi usado. ================================================================================ ### O que faz: troca o carrossel em JavaScript pelo carrossel do navegador, com a biblioteca antiga de retaguarda ### Onde entra: a caixa de conversa do agente, com o componente de carrossel aberto ### Cuidado: o carrossel só com CSS segue fora do Baseline; a biblioteca continua no projeto como plano B Este componente usa Embla (uma biblioteca de carrossel em JavaScript). Refaça-o como carrossel 100% CSS dentro de @supports, mantendo o Embla como fallback quando o navegador não for compatível com os pseudo-elementos novos. Use: scroll-snap para alinhar os slides, ::scroll-button(left)/(right) para os botões anterior e próximo, ::scroll-marker() para os pontos indicadores e :target-current para marcar o slide ativo. Critérios de aceite (auditáveis via Chrome MCP): - navegação completa por Tab e setas do teclado, sem armadilha de foco; - os pontos e botões são anunciados por leitor de tela (semântica tablist); - o botão "anterior" fica desabilitado no primeiro slide e o "próximo" no último; - onde o suporte não existe, o Embla assume e a UX não quebra; - me diga quantos KB de JavaScript deixaram de ser carregados no caminho CSS. ================================================================================ ### O que faz: quatro técnicas de plataforma numa folha só, o cabeçalho que sabe quando grudou, a variante por token, a conta de tamanho fluido escrita uma vez e a entrada escalonada da lista ### Onde entra: folha de estilo global do projeto e do design system ### Cuidado: a consulta de estado de rolagem, a regra @function e as funções de índice de irmão seguem fora do Baseline na data da revisão; a consulta por estilo passou a recém-disponível e pede verificação com plano B /* Header sticky que reage a 'grudar' sem IntersectionObserver */ .header { position: sticky; top: 0; container-type: scroll-state; } @supports (container-type: scroll-state) { @container scroll-state(stuck: top) { .header__inner { box-shadow: 0 2px 12px rgb(0 0 0 / 0.12); background: color-mix(in oklch, canvas 92%, transparent); } } } /* Style query: variante do card pelo valor de uma custom property */ .card { container-type: inline-size; } @container style(--card-variant: promo) { .card__badge { display: inline-flex; } } /* @function: um clamp() fluido reaproveitável em vez de copiar a conta */ @function --fluid(--min, --max) { result: clamp( var(--min), var(--min) + (var(--max) - var(--min)) * ((100vw - 20rem) / (60rem - 20rem)), var(--max) ); } h1 { font-size: --fluid(1.75rem, 3rem); } /* Stagger sem JS: delay proporcional ao índice do irmão */ .lista > li { transition: opacity 0.4s, translate 0.4s; transition-delay: calc(sibling-index() * 60ms); } @media (prefers-reduced-motion: reduce) { .lista > li { transition-delay: 0ms; } } ================================================================================ ### O que faz: acordeão em que abrir um item fecha os outros, com abertura animada e sem uma linha de JavaScript ### Onde entra: a seção de perguntas frequentes e qualquer revelação simples de conteúdo ### Cuidado: a interpolação de tamanho segue fora do Baseline; onde ela não existe, a abertura é instantânea e nada quebra /* Acordeão nativo, exclusivo e animado, sem JavaScript */ :root { interpolate-size: allow-keywords; } /* opt-in global; degrada sozinho */ details[name="faq"]::details-content { block-size: 0; overflow: hidden; transition: block-size 0.3s ease, content-visibility 0.3s allow-discrete; } details[name="faq"][open]::details-content { block-size: auto; /* interpolate-size torna esta transição possível */ } ================================================================================ ### O que faz: quatro polimentos de plataforma, o canto com geometria própria, o texto aparado, a divisória no vão da grade e a ordem de foco seguindo a ordem visual ### Onde entra: folha de estilo dos botões, das grades e das barras de ferramentas ### Cuidado: as quatro propriedades seguem fora do Baseline na data da revisão e degradam limpas; entram como melhoria, nunca como requisito /* Polimentos de plataforma como enhancement: sem suporte, degradam limpos */ .btn { border-radius: 12px; corner-shape: squircle; /* sem suporte -> arredondado normal */ text-box: trim-both cap alphabetic; /* sem suporte -> texto normal */ } .grid { display: grid; gap: 1rem; column-rule: 1px solid var(--border); /* divisória no gap, sem border hack */ row-rule: 1px solid var(--border); } /* Ordem de foco segue a ordem visual reordenada por 'order' */ .toolbar { display: flex; reading-flow: flex-visual; } ================================================================================ ### O que faz: a política de adoção de CSS que o agente relê em cada sessão ### Onde entra: o arquivo de instruções do projeto, na raiz do repositório ### Cuidado: a política envelhece; anote a data da última revisão ao lado dela ## Política de CSS de plataforma (Baseline) - Features **Widely Available** no Baseline: use livremente, sem @supports. - Features **Newly Available**: use SEMPRE atrás de @supports com fallback funcional. Nunca deixe a UI quebrar em navegador sem suporte. - Features **fora do Baseline** (falta um navegador): só entram se EU pedir, sempre como progressive enhancement que degrada sem quebrar. - Antes de afirmar o status de uma feature, confirme no digest do Baseline (web.dev) ou no caniuse; não presuma pelo seu treinamento. - Prefira o nativo do navegador a uma dependência nova (carrossel, acordeão, posicionamento, animação de altura) quando ele cobrir o requisito.