Wir entwickeln moderne Web Applikationen und bieten erstklassigen Kunden Support

IN LI TW

Erstellung von Tailwindcss-Plugins

29. Februar 2024
Development

Für alle, die es noch nicht wissen: Tailwindcss ist ein extrem raffiniertes CSS-Framework, das das Styling über vorkonfigurierte CSS-Klassen handhabt. Es ist unglaublich einfach und schnell damit eine UI zu erstellen.

Rasend schnelles Erstellen und Ändern von Stilen. Aber um welchen Preis?

Nehmen wir zum Beispiel an, wir haben ein Body-Element und darin eine div. Man nimmt einfach den Body-Tag, fügt etwas wie class="flex" hinzu und erhält sofort das Styling für eine Flexbox, fügt dann justify-center hinzu und man hat das Unmögliche geschafft - eine div zu zentrieren.

Vor kurzem wurde ich jedoch auf ein Abenteuer geführt, das ich gerne mit euch teilen möchte.

Da Tailwindcss so mächtig ist und gleichzeitig völlig kurzlebige Eigenschaften hat, bedeutet es Abstraktion. Normalerweise würde ich empfehlen, einen Blick in die Tailwindcss-Dokumentation zu werfen, und in diesem Fall tue ich das auch. Im Falle von Plugins würde ich jedoch sagen, dass ihre Dokumentation im Grunde nur der Vorläufer ist.

Aber wozu braucht man Plugins?

Zunächst einmal möchte ich erklären, warum ich ein Plugin erstellen wollte.

Unser Design erforderte eine extravagante Animation, die ich mittels linear-gradients erstellen konnte. Aber dieses Styling wäre für mehrere Farben, Schaltflächen usw. ziemlich mühsam zu implementieren. Es war einfach nicht konfigurierbar, und wie die meisten Programmierer habe ich mehr Angst davor, dieselbe Codezeile mehrmals zu schreiben, als vor dem Zorn des Gottes Zeus selbst.

So begann ich meine Reise damit, herauszufinden, wie man ein Tailwind-Plugin erstellt. Wie in den Tailwind-Dokumenten erwähnt, braucht man einfach eine Funktion, die man in den Configs übergibt, etwa so:

1const plugin = require('tailwindcss/plugin');
2 
3module.exports = {
4 plugins: [
5 plugin(function ({ addUtilities, addComponents, e, config }) {
6 // Add your custom styles here
7 }),
8 ],
9};

Eine umfangreiche Repository-Suche später

Nachdem ich dies hinzugefügt hatte, war mein Grundbedürfnis, die Farben in meinem linear-gradient zu überschreiben zu können. Nun, das ist, wo ich mit meinem Kopf gegen die Wand lief.

Es gab absolut keine Dokumentation darüber, wie man bestehende Stile über die Plugin-Funktion manipuliert. Das Einzige, was sie zeigen, ist im Grunde die Erstellung einer normalen CSS-Klasse Styling.

Nach der Suche weit und breit, fand ich zwei große Repos, die ich als Grundlage verwendete. Das erste ist sehr grundlegend, gibt aber einen guten Überblick über das Wesentliche.

Das zweite jedoch hat mich umgehauen. Es ist ein Plugin zum Erstellen und Verwalten von CSS-Variablen. Rund 1000 Zeilen Code, nur für die Logik der Erstellung von Variablen.

Nicht genau das, was ich brauche, aber es hat mich inspiriert. Von dem, begann ich mit einer Funktion, die die grundlegenden tailwind Variablen, die ich zum Überschreiben brauche, erstellt:

1type Color = [string, string]; // [colorName, colorValue]
2 
3function getGradientStyling([key, value]: Color, e: (className: string) => string): CSSRuleObject {
4 return {
5 // create a new utility class for each key/color
6 [`.${e(`gradient-animate-${key}`)}`]: {
7 // overwrite the default tailwind variables for gradients
8 ['--tw-gradient-to']: `rgba(0,0,0,0) var(--tw-gradient-to-position)`,
9 ['--tw-gradient-from']: `${value} var(--tw-gradient-from-position)`,
10 ['--tw-gradient-stops']: `var(--tw-gradient-from), ${value} var(--tw-gradient-via-position), var(--tw-gradient-to)`,
11 },
12 };
13}

Im Wesentlichen nimmt es einen Namen, welches es verwenden würde, um die Klasse zu erstellen, und einen Wert für die Erstellung der Variablen innerhalb dieser Klasse. Auf diese Weise können wir gradient-animate- + 'eine beliebige Farbe in unserer Konfiguration' verwenden und es funktioniert sofort.

Der nächste Schritt war ehrlich gesagt der lästigste Teil. Ich habe mein Bestes getan, um diesen Aspekt zu vermeiden. Ich brauchte jetzt natürlich ein Array mit all meinen Farben. Die Tailwind-Plugin-Funktionen haben Zugriff auf das theme, so dass die Verwendung von etwas wie theme(colors) einem ermöglicht den Zugriff auf alle Farben in der Konfiguration, wie hier:

1module.exports = {
2 theme: {
3 colors: {
4 primary: { DEFAULT: '#F9F6EE' },
5 secondary: { DEFAULT: '#E5D8C7', light: '#EEE4D6' },
6 tertiary: { green: '#B4D59A', yellow: '#FECF55', red: '#DD6972' },
7 stroke: '#B5B5B526',
8 white: '#FFF',
9 black: '#232323',
10 gray: { DEFAULT: '#979797', light: '#CDCDCD' },
11 current: 'currentColor',
12 transparent: 'transparent',
13 },
14 },
15 plugins: [
16 ...,
17 ],
18};

Allerdings ist das Verarbeiten von diesen eine ganz andere Geschichte. Ich hatte gehofft, dass Tailwind eine Hilfsfunktion hat, aber ich konnte keine Informationen darüber finden, also habe ich meine eigene Lösung erstellt:

1function getColors(object: Record<string, string | object> | object, parentKey: string): Color[] {
2 let colorArray: Color[] = [];
3 Object.entries(object).forEach(([key, value]) => {
4 if (typeof value === 'string') {
5 const parentKeyName = parentKey === '' ? '' : parentKey + '-';
6 const keyName = key === 'DEFAULT' ? parentKey : parentKeyName + key;
7 colorArray.push([keyName, value]);
8 } else if (typeof value === 'object') {
9 colorArray = colorArray.concat(getColors(value, key));
10 }
11 });
12 return colorArray;
13}

Dies schafft ein Array von Namen/Werten, die ich an meine getGradientStyling übergebe, um dann eine einzigartige Klasse und Styling zu erstellen.

Dann fügen wir eine einfache Plugin-Funktion ein, die die erforderlichen Funktionen aufruft.

1plugin(function ({ addUtilities, theme, e }) {
2 const colors = theme('colors') || {}; // get all colors object
3 const colorArray = getColors(colors, ''); // create [key, value] array for each color
4 
5 // map through each color
6 const utilities = colorArray.map(([key, value]) => {
7 console.log('ADDING COLORS: ', { key, value, style: getGradientStyling([key, value], e) });
8 return getGradientStyling([key, value], e);
9 });
10 addUtilities(utilities);
11});

Und voilà, wir haben eine benutzerdefinierte Tailwind-Klasse, die wir so konfigurieren können, dass sie mit jeder Farbe funktioniert. Wie hier mit gradient-animate-black gezeigt.

Fertige Animation