Dit is een bericht over Schoenveter, een componentenbibliotheek van Cory LaViska, maar met een twist. Het definieert al uw standaard UX-componenten: tabbladen, modals, accordeons, auto-completes en veel, veel meer. Ze zien er direct uit de doos prachtig uit, zijn toegankelijk en volledig aanpasbaar. Maar in plaats van deze componenten te maken in React, of Solid, of Svelte, enz., maakt het ze met Webcomponenten; dit betekent dat je ze kunt gebruiken met: elke kader.
Enkele voorbereidende dingen
Webcomponenten zijn geweldig, maar er zijn momenteel een paar kleine haperingen om op te letten.
Reageren
Ik zei dat ze in elk JavaScript-framework werken, maar zoals ik eerder heb geschreven, is de ondersteuning van React voor webcomponenten: momenteel slecht. Om dit aan te pakken, schoenveter eigenlijk gemaakte wrappers alleen voor Reageren.
Een andere optie, die ik persoonlijk leuk vind, is om een dunne React-component te maken die de tagnaam van een webcomponent en al zijn attributen en eigenschappen accepteert, en vervolgens het vuile werk doet om de tekortkomingen van React aan te pakken. Ik had het over deze optie in een vorige post. Ik vind deze oplossing leuk omdat deze is ontworpen om te worden verwijderd. Het interoperabiliteitsprobleem van Web Component is momenteel opgelost in de experimentele tak van React, dus als dat eenmaal is verzonden, kan elk dun Web Component-interoperabel onderdeel dat je gebruikt worden doorzocht en verwijderd, zodat je direct Web Component-gebruik hebt, zonder enige React-wrappers.
Server-side rendering (SSR)
Ondersteuning voor SSR is ook slecht op het moment van schrijven. In theorie is er iets dat Declaratieve schaduw DOM (DSD) die SSR mogelijk zou maken. Maar browserondersteuning is minimaal, en in ieder geval vereist DSD eigenlijk serverondersteuning om goed te werken, wat betekent: Volgende, Remix, of wat u ook maar op de server gebruikt, het moet op een speciale manier kunnen worden afgehandeld.
Dat gezegd hebbende, zijn er andere manieren om webcomponenten te krijgen: gewoon werk
met een web-app die is SSR'd met zoiets als Next. De korte versie is dat de scripts die uw webcomponenten registreren, in een blokkerend script moeten worden uitgevoerd voordat uw opmaak wordt geparseerd. Maar dat is een onderwerp voor een andere post.
Als u een door de klant gegenereerde SPA bouwt, is dit natuurlijk geen probleem. Dit is waar we in dit bericht mee aan de slag gaan.
Laten we beginnen
Omdat ik wil dat dit bericht zich richt op schoenveter en op de aard van de webcomponenten, zal ik gebruik maken van slank voor alles. Deze ga ik ook gebruiken Stackblitz-project voor demonstratie. We zullen deze demo samen stap voor stap bouwen, maar voel je vrij om die REPL op elk moment te openen om het eindresultaat te zien.
Ik zal je laten zien hoe je Shoelace gebruikt, en nog belangrijker, hoe je het kunt aanpassen. We zullen het hebben over Schaduw DOM's en welke stijlen ze blokkeren van de buitenwereld (en welke niet). We zullen het ook hebben over de ::part
CSS-selector — die misschien helemaal nieuw voor je is — en we zullen zelfs zien hoe Shoelace ons in staat stelt de verschillende animaties te negeren en aan te passen.
Als je na het lezen van dit bericht vindt dat je van Schoenveter houdt en het wilt proberen in een React-project, is mijn advies om te gebruiken een wikkel zoals ik in de inleiding al aangaf. Hierdoor kun je alle componenten van Shoelace gebruiken, en het kan helemaal worden verwijderd zodra React de Web Component-fixes verzendt die ze al hebben (kijk daarvoor in versie 19).
Introductie van schoenveter
Schoenveter is redelijk gedetailleerd Installatie instructies. Op zijn eenvoudigst kun je dumpen en
tags in uw HTML-document, en dat is dat. Voor elke productie-app wil je waarschijnlijk alleen selectief importeren wat je wilt, en daar zijn ook instructies voor.
Laten we, met Shoelace geïnstalleerd, een Svelte-component maken om wat inhoud weer te geven, en vervolgens de stappen doorlopen om deze volledig aan te passen. Om iets vrij niet-triviaal te kiezen, ging ik met de tabbladen en een dialoog (meestal aangeduid als een modaal) componenten. Hier is wat opmaak grotendeels overgenomen uit de documenten:
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!
Dit levert een aantal mooie, gestileerde tabbladen op. De onderstreping op het actieve tabblad animeert zelfs mooi en schuift van het ene actieve tabblad naar het andere.
Ik zal uw tijd niet verspillen aan het doornemen van elke centimeter van de API's die al goed gedocumenteerd zijn op de Shoelace-website. Laten we in plaats daarvan eens kijken hoe we het beste kunnen communiceren met deze webcomponenten en deze volledig kunnen aanpassen.
Interactie met de API: methoden en gebeurtenissen
Het aanroepen van methoden en het abonneren op gebeurtenissen op een webcomponent kan iets anders zijn dan wat u gewend bent met uw normale raamwerk naar keuze, maar het is niet te ingewikkeld. Laten we eens kijken hoe.
Tabs
Het tabbladen onderdeel () heeft een
show
methode, die handmatig een bepaald tabblad toont. Om dit aan te roepen, moeten we toegang krijgen tot het onderliggende DOM-element van onze tabbladen. In Svelte betekent dat het gebruik van bind:this
. In React zou het een zijn ref
. Enzovoort. Aangezien we Svelte gebruiken, laten we een variabele declareren voor onze tabs
voorbeeld:
let tabs;
...en bind het:
Nu kunnen we een knop toevoegen om het te noemen:
Het is hetzelfde idee voor evenementen. Er is een sl-tab-show
gebeurtenis die wordt geactiveerd wanneer een nieuw tabblad wordt weergegeven. We zouden kunnen gebruiken addEventListener
op onze tabs
variabele, of we kunnen Svelte's . gebruiken on:event-name
snelkoppeling.
console.log(e)}>
Dat werkt en registreert de gebeurtenisobjecten terwijl u verschillende tabbladen laat zien.
Meestal renderen we tabbladen en laten we de gebruiker ertussen klikken, dus dit werk is meestal niet eens nodig, maar het is er als je het nodig hebt. Laten we nu de dialoogcomponent interactief maken.
Dialoog
De dialoogcomponent () duurt een
open
prop die bepaalt of het dialoogvenster... open is. Laten we het aangeven in onze Svelte-component:
let tabs;
let open = false;
Het heeft ook een sl-hide
gebeurtenis voor wanneer het dialoogvenster is verborgen. Laten we onze . doorgeven open
prop en bind aan de hide
gebeurtenis, zodat we het kunnen resetten wanneer de gebruiker buiten de inhoud van het dialoogvenster klikt om het te sluiten. En laten we een klik-handler toevoegen aan die knop Sluiten om onze open
steunen op false
, waarmee ook het dialoogvenster zou worden gesloten.
open = false}>
Hello World!
Laten we ten slotte onze open dialoogknop aansluiten:
En dat is dat. Interactie met de API van een componentenbibliotheek is min of meer eenvoudig. Als dat alles is wat dit bericht deed, zou het behoorlijk saai zijn.
Maar Schoenveter - gebouwd met webcomponenten - betekent dat sommige dingen, met name stijlen, een beetje anders zullen werken dan we misschien gewend zijn.
Pas alle stijlen aan!
Op het moment van schrijven bevindt Shoelace zich nog in de bètafase en de maker overweegt enkele standaardstijlen te wijzigen, mogelijk zelfs enkele standaardinstellingen te verwijderen, zodat ze niet langer de stijlen van je hosttoepassing overschrijven. De concepten die we zullen behandelen zijn hoe dan ook relevant, maar wees niet verbaasd als sommige van de schoenveterspecificaties die ik noem anders zijn wanneer je het gaat gebruiken.
Hoe mooi de standaardstijlen van Shoelace ook zijn, we hebben misschien onze eigen ontwerpen in onze web-app en we willen dat onze UX-componenten overeenkomen. Laten we eens kijken hoe we dat zouden aanpakken in een wereld van Web Components.
We zullen het eigenlijk niet proberen verbeteren iets. De maker van de schoenveter is een veel betere ontwerper dan ik ooit zal zijn. In plaats daarvan zullen we kijken naar hoe u verandering dingen, zodat u zich kunt aanpassen aan uw eigen web-apps.
Een korte rondleiding door Shadow DOM's
Neem een kijkje in een van die tabbladkoppen in uw DevTools; het zou er ongeveer zo uit moeten zien:
Ons tab-element heeft een . gemaakt div
container met een .tab
en .tab--active
klasse, en een tabindex
, terwijl ook de tekst wordt weergegeven die we voor dat tabblad hebben ingevoerd. Maar merk op dat het in een zit schaduw wortel. Hierdoor kunnen auteurs van webcomponenten hun eigen opmaak toevoegen aan de webcomponent en tegelijkertijd een plaats bieden voor de inhoud we voorzien in. let op de element? Dat betekent in feite "zet de inhoud die de gebruiker heeft weergegeven" tussen de Web Component-tags hier. '
Dus de component maakt een schaduwwortel, voegt er wat inhoud aan toe om de mooi gestileerde tabkop weer te geven samen met een tijdelijke aanduiding (
) die onze inhoud binnenin weergeeft.
Ingekapselde stijlen
Een van de klassieke, meer frustrerende problemen bij webontwikkeling zijn altijd stijlen geweest trapsgewijze naar plaatsen waar we ze niet willen. Je zou je zorgen kunnen maken dat stijlregels in onze applicatie die iets specificeren als div.tab
zou interfereren met deze tabbladen. Het blijkt dat dit geen probleem is; schaduwwortels kapselen stijlen in. Stijlen van buiten de schaduwwortel hebben geen invloed op wat zich binnen de schaduwwortel bevindt (met enkele uitzonderingen waar we het over zullen hebben), en vice versa.
De uitzonderingen hierop zijn erfelijke stijlen. U hoeft natuurlijk geen font-family
stijl voor elk element in uw web-app. In plaats daarvan kunt u uw font-family
een keer, op :root
or html
en laat het overal eronder erven. Deze erfenis zal in feite ook de schaduwwortel doorboren.
Aangepaste CSS-eigenschappen (vaak "css-variabelen" genoemd) zijn een gerelateerde uitzondering. Een schaduwwortel kan absoluut een CSS-eigenschap lezen die buiten de schaduwwortel is gedefinieerd; dit wordt zo relevant.
::part
keuzeschakelaar
De Hoe zit het met stijlen die? niet erven. Wat als we iets willen aanpassen als cursor
, die niet erft, op iets in de schaduwwortel. Hebben we pech? Het blijkt dat we dat niet zijn. Kijk nog eens naar de afbeelding van het tabbladelement hierboven en de schaduwwortel. let op de part
attribuut op het div
? Hiermee kunt u dat element van buiten de schaduwwortel richten en stylen met behulp van de ::part
keuzeschakelaar. We lopen door een voorbeeld is een beetje.
Schoenveterstijlen overschrijven
Laten we elk van deze benaderingen in actie zien. Vanaf nu, veel van schoenveterstijlen, inclusief lettertypen, ontvangen standaardwaarden van aangepaste CSS-eigenschappen. Om die lettertypen uit te lijnen met de stijlen van uw toepassing, overschrijft u de betreffende aangepaste rekwisieten. Zien de documenten voor informatie over welke CSS-variabelen Shoelace gebruikt, of je kunt eenvoudig de stijlen in een bepaald element in DevTools inspecteren.
Stijlen overnemen via de schaduwwortel
Open de app.css
bestand in de src
directory van de StackBlitz-project. In de :root
gedeelte onderaan, zou u een moeten zien letter-spacing: normal;
verklaring. sinds de letter-spacing
eigenschap is overerfbaar, probeer een nieuwe waarde in te stellen, zoals 2px
. Bij het opslaan wordt alle inhoud, inclusief de tabkoppen die zijn gedefinieerd in de schaduwhoofdmap, dienovereenkomstig aangepast.
CSS-variabelen voor schoenveters overschrijven
De component leest an
--indicator-color
Aangepaste CSS-eigenschap voor de onderstreping van het actieve tabblad. We kunnen dit overschrijven met wat basis-CSS:
sl-tab-group {
--indicator-color: green;
}
En zo hebben we nu een groene indicator!
Onderdelen opvragen
In de versie van Schoenveter die ik nu gebruik (2.0.0-beta.83), heeft elk niet-uitgeschakeld tabblad een pointer
cursor. Laten we dat veranderen in een standaardcursor voor het actieve (geselecteerde) tabblad. We zagen al dat de element voegt a . toe
part="base"
attribuut op de container voor de tabkop. Ook ontvangt het momenteel geselecteerde tabblad een active
attribuut. Laten we deze feiten gebruiken om het actieve tabblad te targeten en de cursor te wijzigen:
sl-tab[active]::part(base) {
cursor: default;
}
En dat is dat!
Animaties aanpassen
Laten we voor wat kers op de metaforische taart eens kijken hoe Shoelace ons in staat stelt animaties aan te passen. Schoenveter gebruikt de API voor webanimaties, en onthult een setDefaultAnimation
API om te bepalen hoe verschillende elementen hun verschillende interacties animeren. Zie de documenten voor details, maar als voorbeeld, hier is hoe je de standaard dialooganimatie van Shoelace zou kunnen veranderen van naar buiten uitbreiden en naar binnen krimpen, om in plaats daarvan van boven naar binnen te animeren en naar beneden te laten vallen terwijl je je verbergt.
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)" },
});
Die code staat in de App.svelte
het dossier. Reageer erop om de originele, standaardanimatie te zien.
Afsluiten
Shoelace is een ongelooflijk ambitieuze componentenbibliotheek die is gebouwd met webcomponenten. Omdat Web Components framework-onafhankelijk zijn, kunnen ze in elk project, met elk framework worden gebruikt. Nu er nieuwe frameworks verschijnen met zowel verbluffende prestatiekenmerken als gebruiksgemak, is de mogelijkheid om hoogwaardige widgets voor gebruikerservaringen te gebruiken die niet aan een enkel framework zijn gebonden, nog nooit zo aantrekkelijk geweest.