TypeScript / Tailwind CSS / Functional Programming

Membuat Tailwind lebih fun(ctional) dengan menggunakan pipeable API di tailwind-fun

Kalau kamu belum membaca tentang tailwind-fun, kamu bisa membacanya di sini Singkatnya, tailwind fun adalah library yang...

Kalau kamu belum membaca tentang tailwind-fun kamu bisa membacanya di sini

Singkatnya, tailwind fun adalah library yang memungkinkan kamu menulis dan menyusun classname tailwind secara deklaratif/ekspresif.

awalnya, alasan saya membuat tailwind-fun adalah karena saya suka FP dan ingin bisa menulis tailwind dengan lebih deklaratif. artinya, saya tidak ingin membuat abstraksi class berbasis component, kecuali kalau memang sengaja sedang membangun design system tentunya.

dan saya berpikir, saat bekerja dengan library FP seperti fp-ts atau ts-belt atau lainnya, saya akan punya function pipe. lalu saya berpikir, kenapa tidak sekalian membuat pipeable API karena menurut saya ini lebih rapi daripada chainable API.

jadi sekarang, tailwind-fun mengekspos method TWSClass sebagai pipeable API.

sebagai contoh, berikut tampilan contoh dari artikel sebelumnya jika ditulis menggunakan pipeable API

import { TWS, addVariants, addWhen, removeWhen  } from 'tailwind-fun';

const pipe = <T>(value: T, ...fns: Function[]) =>
  fns.reduce((prev, next) => next(prev), value);

const overlayClass = (
  isSelected: boolean,
  isToday: boolean,
  isSameMonth: boolean
) =>
  pipe(
    TWS('absolute h-[36px] w-[36px] top-[-5.5px] left-[-7.5px] rounded-full'),
    addWhen(isSelected, 'bg-selectedBLue'),
    addWhen(isToday, 'border-selectedBlue border'),
    removeWhen(isSameMonth, 'border-selectedBlue'),
    addVariants('group-hover', 'bg-white z-10')
  );

const Overlay = () => <div className={overlayClass(isSelected,isToday,isSameMonth).className}></div>

Menyusun menjadi abstraksi berbasis component

Walaupun sebelumnya saya tidak merekomendasikannya, kalau kamu ingin menyusun class name menjadi abstraksi berbasis component, sekarang hasilnya juga lebih rapi. sebagai contoh, berikut cara menyusun class untuk button

import { TWS, addVariants, addWhen, removeWhen  } from 'tailwind-fun';

const pipe = <T>(value: T, ...fns: Function[]) =>
  fns.reduce((prev, next) => next(prev), value);

const buttonClass = ({ primary, secondary, fluid, widthPx }: any) =>
  pipe(
    TWS('block p-5'),
    addWhen(primary, 'bg-primary text-primary'),
    addWhen(secondary, 'bg-secondary'),
    addWhen(fluid, 'w-100'),
    addWhen(Number.isInteger(widthPx), `w-[${widthPx}px]`)
  );

console.log(buttonClass({ primary: true, fluid: true }).className); //block p-5 bg-primary text-primary w-100
console.log(buttonClass({ secondary: true, fluid: true }).className); // block p-5 bg-secondary w-100;
console.log(buttonClass({ primary: true, widthPx: 50 }).className); // block p-5 bg-primary text-primary w-[50px];

Memperluas alias Semuanya cuma function

karena semua function yang diekspos oleh pipeable API hanyalah function biasa, kamu sebenarnya bisa memperluasnya. begini juga cara saya menyusun API ini secara internal. sebagai contoh, addWHen menggunakan add sebagai dasarnya, dan addHoverWhen menggunakan addWhen sebagai dasarnya. kamu pasti sudah menangkap maksudnya. kamu bisa melihatnya di sini

Terima kasih sudah membaca artikel ini sampai selesai :D