Este é um post sobre Cadarço, uma biblioteca de componentes por Cory La Viska, mas com uma reviravolta. Ele define todos os seus componentes padrão de UX: guias, modais, acordeões, preenchimentos automáticos e muito muito mais. Eles ficam lindos fora da caixa, são acessíveis e totalmente personalizáveis. Mas ao invés de criar esses componentes em React, ou Solid, ou Svelte, etc., ele os cria com Componentes da Web; isso significa que você pode usá-los com qualquer estrutura.
Algumas coisas preliminares
Os Web Components são ótimos, mas atualmente existem alguns pequenos problemas a serem observados.
Reagir
Eu disse que eles funcionam em qualquer framework JavaScript, mas como escrevi antes, o suporte do React para Web Components é atualmente pobre. Para resolver isso, Shoelace realmente wrappers criados apenas para reagir.
Outra opção, que eu pessoalmente gosto, é criar um componente React fino que aceite o nome da tag de um Web Component e todos os seus atributos e propriedades, então faça o trabalho sujo de lidar com as deficiências do React. falei sobre essa opção em uma postagem anterior. Eu gosto desta solução porque ela foi projetada para ser excluída. O problema de interoperabilidade do Web Component está atualmente corrigido na ramificação experimental do React, portanto, uma vez enviado, qualquer componente interoperável do Web Component thin que você estiver usando pode ser pesquisado e removido, deixando você com usos diretos do Web Component, sem nenhum wrapper do React.
Renderização do lado do servidor (SSR)
O suporte para SSR também é ruim no momento da redação deste artigo. Em teoria, existe algo chamado Shadow DOM declarativo (DSD) que habilitaria o SSR. Mas o suporte ao navegador é mínimo e, em qualquer caso, o DSD realmente requer suporte do servidor trabalhar direito, o que significa Próximo, Remix, ou o que você usar no servidor precisará se tornar capaz de algum tratamento especial.
Dito isso, existem outras maneiras de fazer com que os Web Components apenas trabalhe
com um aplicativo da Web que é SSR com algo como Next. A versão curta é que os scripts que registram seus Web Components precisam ser executados em um script de bloqueio antes que sua marcação seja analisada. Mas isso é assunto para outro post.
Obviamente, se você estiver criando qualquer tipo de SPA renderizado pelo cliente, isso não será um problema. É com isso que trabalharemos neste post.
Vamos começar
Como quero que este post se concentre em cadarço e em sua natureza de componente da Web, usarei Esbelto para tudo. Eu também vou usar isso Projeto Stackblitz para demonstração. Construiremos esta demonstração juntos, passo a passo, mas sinta-se à vontade para abrir esse REPL a qualquer momento para ver o resultado final.
Mostrarei como usar cadarço e, mais importante, como personalizá-lo. Nós vamos falar sobre DOMs de sombra e quais estilos eles bloqueiam do mundo exterior (assim como quais eles não bloqueiam). Também falaremos sobre o ::part
Seletor de CSS — o que pode ser totalmente novo para você — e veremos até como o Shoelace nos permite substituir e personalizar suas várias animações.
Se você achar que gosta de Shoelace depois de ler este post e quiser experimentá-lo em um projeto React, meu conselho é usar um invólucro como mencionei na introdução. Isso permitirá que você use qualquer um dos componentes do Shoelace, e ele pode ser removido completamente assim que o React enviar as correções do Web Component que eles já possuem (procure por isso na versão 19).
Apresentando cadarço
Cadarço tem bastante detalhado instruções de instalação. Na sua forma mais simples, você pode despejar e
tags em seu documento HTML, e pronto. No entanto, para qualquer aplicativo de produção, você provavelmente desejará importar seletivamente apenas o que deseja, e também há instruções para isso.
Com o Shoelace instalado, vamos criar um componente Svelte para renderizar algum conteúdo e, em seguida, seguir as etapas para personalizá-lo totalmente. Para escolher algo bastante não trivial, usei as guias e os componentes de diálogo (comumente chamados de modal). Aqui está uma marcação retirado em grande parte dos documentos:
General
Custom
Advanced
Disabled
This is the general tab panel.
This is the custom tab panel.
This is the advanced tab panel.
This is a disabled tab panel.
Hello World!
Isso renderiza algumas guias bonitas e estilizadas. O sublinhado na guia ativa até anima bem e desliza de uma guia ativa para a próxima.
Não vou perder seu tempo percorrendo cada centímetro das APIs que já estão bem documentadas no site da Shoelace. Em vez disso, vamos ver a melhor forma de interagir e personalizar totalmente esses Web Components.
Interagindo com a API: métodos e eventos
Chamar métodos e assinar eventos em um Web Component pode ser um pouco diferente do que você está acostumado com sua estrutura normal de escolha, mas não é muito complicado. Vamos ver como.
Tabs
O componente de guias () tem um
show
método, que mostra manualmente uma guia específica. Para chamar isso, precisamos obter acesso ao elemento DOM subjacente de nossas guias. Em Svelte, isso significa usar bind:this
. Em React, seria um ref
. E assim por diante. Já que estamos usando o Svelte, vamos declarar uma variável para nosso tabs
instância:
let tabs;
… e vinculá-lo:
Agora podemos adicionar um botão para chamá-lo:
É a mesma ideia para eventos. Há um sl-tab-show
evento que é acionado quando uma nova guia é mostrada. Nós poderíamos usar addEventListener
no nosso tabs
variável, ou podemos usar Svelte on:event-name
atalho.
console.log(e)}>
Isso funciona e registra os objetos de evento à medida que você mostra guias diferentes.
Normalmente, renderizamos as guias e deixamos o usuário clicar entre elas, então esse trabalho geralmente nem é necessário, mas está lá se você precisar. Agora vamos tornar o componente de diálogo interativo.
diálogo
O componente de diálogo () leva um
open
prop que controla se a caixa de diálogo está… aberta. Vamos declará-lo em nosso componente Svelte:
let tabs;
let open = false;
Ele também tem um sl-hide
evento para quando a caixa de diálogo estiver oculta. Vamos passar nosso open
prop e ligar para o hide
evento para que possamos redefini-lo quando o usuário clicar fora do conteúdo da caixa de diálogo para fechá-lo. E vamos adicionar um manipulador de cliques a esse botão fechar para definir nosso open
prop para false
, que também fecharia a caixa de diálogo.
open = false}>
Hello World!
Por fim, vamos conectar nosso botão de diálogo aberto:
E é isso. A interação com a API de uma biblioteca de componentes é mais ou menos direta. Se isso fosse tudo o que este post fez, seria muito chato.
Mas Shoelace — sendo construído com Web Components — significa que algumas coisas, particularmente estilos, funcionarão de maneira um pouco diferente do que estamos acostumados.
Personalize todos os estilos!
Até o momento, Shoelace ainda está na versão beta e o criador está considerando alterar alguns estilos padrão, possivelmente até removendo alguns padrões completamente para que eles não substituam mais os estilos do seu aplicativo host. Os conceitos que abordaremos são relevantes de qualquer maneira, mas não se surpreenda se algumas das especificidades do cadarço que mencionei forem diferentes quando você for usá-lo.
Por mais legais que sejam os estilos padrão do Shoelace, podemos ter nossos próprios designs em nosso aplicativo da web e queremos que nossos componentes de UX correspondam. Vamos ver como faríamos isso em um mundo de Web Components.
Nós não vamos tentar realmente melhorar nada. O criador do Shoelace é um designer muito melhor do que eu jamais serei. Em vez disso, veremos apenas como alterar coisas, para que você possa se adaptar aos seus próprios aplicativos da web.
Um tour rápido pelos Shadow DOMs
Dê uma olhada em um desses cabeçalhos de guia em seu DevTools; deve ser algo assim:
Nosso elemento tab criou um div
recipiente com um .tab
e .tab--active
classe, e um tabindex
, além de exibir o texto que inserimos para essa guia. Mas observe que ele está dentro de um raiz da sombra. Isso permite que os autores do Web Component adicionem sua própria marcação ao Web Component, ao mesmo tempo em que fornecem um local para o conteúdo we providenciar. Observe o elemento? Isso basicamente significa “colocar qualquer conteúdo que o usuário renderizou entre as tags do Web Component SUA PARTICIPAÇÃO FAZ A DIFERENÇA. "
Então o O componente cria uma raiz de sombra, adiciona algum conteúdo a ela para renderizar o cabeçalho da guia bem estilizado junto com um espaço reservado (
) que renderiza nosso conteúdo dentro.
Estilos encapsulados
Um dos problemas clássicos e mais frustrantes no desenvolvimento web sempre foram os estilos cascata para lugares onde não os queremos. Você pode se preocupar que quaisquer regras de estilo em nosso aplicativo que especifiquem algo como div.tab
interferiria com essas guias. Acontece que isso não é um problema; raízes de sombra encapsulam estilos. Estilos de fora da raiz sombra não afetam o que está dentro da raiz sombra (com algumas exceções sobre as quais falaremos) e vice-versa.
As exceções a isso são estilos herdáveis. Você, é claro, não precisa aplicar um font-family
estilo para cada elemento em seu aplicativo da web. Em vez disso, você pode especificar seu font-family
uma vez, em :root
or html
e tê-lo herdar em todos os lugares abaixo dele. Essa herança, de fato, também perfurará a raiz da sombra.
Propriedades personalizadas CSS (muitas vezes chamadas de “variáveis CSS”) são uma exceção relacionada. Uma raiz sombra pode absolutamente ler uma propriedade CSS definida fora da raiz sombra; isso se tornará relevante em um momento.
::part
seletor
A E os estilos que não herdar. E se quisermos personalizar algo como cursor
, que não herda, em algo dentro da raiz sombra. Estamos sem sorte? Acontece que não somos. Dê outra olhada na imagem do elemento tab acima e sua raiz de sombra. Observe o part
atributo no div
? Isso permite que você direcione e estilize esse elemento de fora da raiz da sombra usando o ::part
seletor. Vamos percorrer um exemplo é um pouco.
Substituindo estilos de cadarço
Vamos ver cada uma dessas abordagens em ação. A partir de agora, muito dos estilos de cadarço, incluindo fontes, recebem valores padrão das propriedades personalizadas do CSS. Para alinhar essas fontes com os estilos do seu aplicativo, substitua as props personalizadas em questão. Ver os documentos para obter informações sobre quais variáveis CSS o Shoelace está usando, ou você pode simplesmente inspecionar os estilos em qualquer elemento no DevTools.
Herdando estilos por meio da raiz de sombra
Abra o app.css
arquivo no src
diretório do Projeto StackBlitz. No :root
seção na parte inferior, você deve ver um letter-spacing: normal;
declaração. Desde o letter-spacing
propriedade é herdável, tente definir um novo valor, como 2px
. Ao salvar, todo o conteúdo, incluindo os cabeçalhos das guias definidos na raiz sombra, serão ajustados de acordo.
Sobrescrevendo variáveis CSS Shoelace
A componente lê um
--indicator-color
Propriedade customizada CSS para o sublinhado da guia ativa. Podemos substituir isso com algum CSS básico:
sl-tab-group {
--indicator-color: green;
}
E assim, agora temos um indicador verde!
Peças de consulta
Na versão do Shoelace que estou usando agora (2.0.0-beta.83), qualquer aba não desativada tem um pointer
cursor. Vamos mudar isso para um cursor padrão para a guia ativa (selecionada). Já vimos que o elemento adiciona um
part="base"
atributo no contêiner para o cabeçalho da guia. Além disso, a guia selecionada atualmente recebe um active
atributo. Vamos usar esses fatos para direcionar a guia ativa e alterar o cursor:
sl-tab[active]::part(base) {
cursor: default;
}
E é isso!
Personalização de animações
Para uma cereja no topo do bolo metafórico, vamos ver como Shoelace nos permite personalizar animações. Cadarço usa o API de animações da web, e expõe uma setDefaultAnimation
API para controlar como diferentes elementos animam suas várias interações. Veja os documentos para detalhes, mas como exemplo, veja como você pode alterar a animação de diálogo padrão do Shoelace de expandir para fora e encolher para dentro, para animar a partir do topo e descer enquanto se esconde.
import { setDefaultAnimation } from "@shoelace-style/shoelace/dist/utilities/animation-registry";
setDefaultAnimation("dialog.show", {
keyframes: [
{ opacity: 0, transform: "translate3d(0px, -20px, 0px)" },
{ opacity: 1, transform: "translate3d(0px, 0px, 0px)" },
],
options: { duration: 250, easing: "cubic-bezier(0.785, 0.135, 0.150, 0.860)" },
});
setDefaultAnimation("dialog.hide", {
keyframes: [
{ opacity: 1, transform: "translate3d(0px, 0px, 0px)" },
{ opacity: 0, transform: "translate3d(0px, 20px, 0px)" },
],
options: { duration: 200, easing: "cubic-bezier(0.785, 0.135, 0.150, 0.860)" },
});
Esse código está no App.svelte
Arquivo. Comente para ver a animação padrão original.
Resumindo
Shoelace é uma biblioteca de componentes incrivelmente ambiciosa construída com Web Components. Como os Web Components são independentes de framework, eles podem ser usados em qualquer projeto, com qualquer framework. Com novas estruturas começando a surgir com características de desempenho incríveis e também facilidade de uso, a capacidade de usar widgets de experiência do usuário de qualidade que não estão vinculados a nenhuma estrutura nunca foi tão atraente.