Twig icon indicating copy to clipboard operation
Twig copied to clipboard

Introduce CVA to html-extra

Open WebMamba opened this issue 5 months ago • 0 comments

Hey! This PR introduces CVA to Twig. All of this has already been merged into SymfonyUX (https://github.com/symfony/ux/pull/1416), but @kbond suggested that this repo can be a better place for this feature.

Here is a description from the PR merged in to SymfonyUX:


This PR introduces a new concept CVA (Class Variance Authority), by adding a1 twig function, to help you manage your class in your component.

Let's take an example an Alert component. In your app, an alert can have a lot of different styles one for success, one for alert, one for warning, and different sizes, with icons or not... You need something that lets you completely change the style of your component without creating a new component, and without creating too much complexity in your template.

Here is the reason came CVA.

Your Alert component can now look like this:

{% props color = 'blue', size = 'md' %}

{% set alert =  cva({
     base: 'alert rounded-lg',
     variants: {
        color: {
            blue: 'text-blue-800 bg-blue-50 dark:bg-gray-800 dark:text-blue-400',
            red: 'text-red-800 bg-red-50 dark:bg-gray-800 dark:text-red-400',
            green: 'text-green-800 bg-green-50 dark:bg-gray-800 dark:text-green-400',
            yellow: 'text-yellow-800 bg-yellow-50 dark:bg-gray-800 dark:text-yellow-400',
        },
        size: {
            sm: 'px-4 py-3 text-sm',
            md: 'px-6 py-4 text-base',
            lg: 'px-8 py-5 text-lg',
        }
    },
    compoundVariants: [{
           color: ['red'],
           size: ['lg'],
          class: 'font-semibold'
    }],
    defaultVariants: {
           rounded: 'md'
    }
}) %}

<div class="{{ cva.apply({color, size}, attribute.render('class'), 'flex p-4') }}">
    ...
</div>

So here you have a cva function that lets you define different variants of your component.

You can now use your component like this:

<twig:Alert color="red" size="md"/>

<twig:Alert color="green" size="sm"/>

<twig:Alert color="yellow" size="lg"/>

<twig:Alert color="red" size="md" class="dark:bg-gray-800"/>

And then you get the following result:

Capture d’écran 2024-01-24 à 00 52 33

If you want to know more about the concept I implement here you can look at:

  • CVA (js version): https://cva.style/docs
  • tailwind merge: https://github.com/gehrisandro/tailwind-merge-php, https://github.com/dcastil/tailwind-merge
  • this implementation by using tailwind-merge and cva is inspired a lot by: https://ui.shadcn.com/ (shadcn is the most starred library on github in 2023)
  • a really good article that explains the philosophy behind https://manupa.dev/blog/anatomy-of-shadcn-ui
  • this PR works great in a LASTstack: https://symfonycasts.com/screencast/last-stack/last-stack

Tell me what you think about it! Thanks for your time! Cheers 🧡


WebMamba avatar Mar 09 '24 16:03 WebMamba