Skip to content

Commit

Permalink
Update CVA docs and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
WebMamba committed Mar 1, 2024
1 parent 1a4f208 commit 057d68b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 31 deletions.
3 changes: 1 addition & 2 deletions src/TwigComponent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
- Introduce CVA to style TwigComponent #1416
- Drop Twig 2 support #1436
- Fix full context is stored in profiler #1552
- Add CVA (Class variant authority) integration #1416

## 2.15.0

- Add the ability to render specific attributes from the `attributes` variable #1442
- Restrict Twig 3.9 for now #1486
- Build reproducible TemplateMap to fix possible post-deploy breakage #1497
- Add CVA (Class variant authority) integration #1416

## 2.14.0

- Make `ComponentAttributes` traversable/countable
- Fixed lexing some `{# twig comments #}` with HTML Twig syntax
- Fix various usages of deprecated Twig code
- Add attribute rendering system

## 2.13.0

Expand Down
52 changes: 23 additions & 29 deletions src/TwigComponent/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1061,11 +1061,15 @@ Exclude specific attributes:
Component with Complex Variants (CVA)
-------------------------------------

CVA (Class Variant Authority) is a concept from the JS world (https://cva.style/docs/getting-started/variants).
It's a concept used by the famous shadcn/ui library (https://ui.shadcn.com).
.. versionadded:: 2.16

The ``CVA`` function was added in TwigComponents 2.16.

[CVA (Class Variant Authority)](https://cva.style/docs/getting-started/variants) is a concept from the JavaScript
world and used by the well-known [shadcn/ui](https://ui.shadcn.com).
CVA allows you to display a component with different variants (color, size, etc.),
to create highly reusable and customizable components.
You can use the cva function to define variants for your component.
This is powered by a ``cva()`` Twig function where you define ``base`` classes that should always be present and then different ``variants`` and the corresponding classes:
The cva function take as argument an array key-value pairs.
The base key allow you define a set of classes commune to all variants.
In the variants key you define the different variants of your component.
Expand Down Expand Up @@ -1095,9 +1099,11 @@ In the variants key you define the different variants of your component.
{% block content %}{% endblock %}
</div>

Then use the color and size variants to select the classes needed:

{# index.html.twig #}
.. code-block:: html+twig

{# index.html.twig #}
<twig:Alert color="red" size="lg">
<div>My content</div>
</twig:Alert>
Expand All @@ -1108,18 +1114,18 @@ In the variants key you define the different variants of your component.
</twig:Alert>
// class="alert bg-green text-sm"

<twig:Alert class="flex items-center justify-center">
<twig:Alert color="red" class="flex items-center justify-center">
<div>My content</div>
</twig:Alert>
// class="alert bg-blue text-md flex items-center justify-center"
// class="alert bg-red text-md flex items-center justify-center"

CVA and Tailwind CSS
~~~~~~~~~~~~~~~~~~~~

CVA work perfectly with tailwindcss. The only drawback is you can have class conflicts,
to have a better control you can use this following bundle (
https://github.com/tales-from-a-dev/twig-tailwind-extra
) in addition to the cva function:
CVA work perfectly with Tailwind CSS. The only drawback is that you can have class conflicts.
To "merge" conflicting classes together and keep only the one you need, use the
``tailwind_merge()` method from [tales-from-a-dev/twig-tailwind-extra](https://github.com/tales-from-a-dev/twig-tailwind-extra)
with the ``cva()`` function:

.. code-block:: terminal
Expand All @@ -1131,29 +1137,17 @@ https://github.com/tales-from-a-dev/twig-tailwind-extra
{% props color = 'blue', size = 'md' %}

{% set alert = cva({
base: 'alert ',
variants: {
color: {
blue: 'bg-blue',
red: 'bg-red',
green: 'bg-green',
},
size: {
sm: 'text-sm',
md: 'text-md',
lg: 'text-lg',
}
}
// ...
}) %}

<div class="{{ alert.apply({color, size}, attributes.render('class')) | tailwind_merge }}">
{% block content %}{% endblock %}
</div>

Compounds variants
Compounds Variants
~~~~~~~~~~~~~~~~~~

You can define compound variants. A compound variant is a variants that apply
You can define compound variants. A compound variant is a variant that applies
when multiple other variant conditions are met.

.. code-block:: html+twig
Expand All @@ -1175,7 +1169,8 @@ when multiple other variant conditions are met.
lg: 'text-lg',
}
},
compound: {
compoundVariants: {
// if colors=red AND size = (md or lg), add the `font-bold` class
colors: ['red'],
size: ['md', 'lg'],
class: 'font-bold'
Expand Down Expand Up @@ -1203,11 +1198,10 @@ when multiple other variant conditions are met.
</twig:Alert>
// class="alert bg-green text-lg font-bold"

Default variants
Default Variants
~~~~~~~~~~~~~~~~

You can define defaults variants, so if no variants are matching you
can still defined a default set of class to apply.
If no variants match, you can define a default set of classes to apply:

.. code-block:: html+twig

Expand Down
23 changes: 23 additions & 0 deletions src/TwigComponent/tests/Unit/CVATest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ public function testRecipes(array $recipe, array $recipes, string $expected): vo
$this->assertEquals($expected, $recipeClass->resolve($recipes));
}

public function testApply(): void
{
$recipe = new CVA('font-semibold border rounded', [
'colors' => [
'primary' => 'text-primary',
'secondary' => 'text-secondary',
],
'sizes' => [
'sm' => 'text-sm',
'md' => 'text-md',
'lg' => 'text-lg',
],
], [
[
'colors' => ['primary'],
'sizes' => ['sm'],
'class' => 'text-red-500',
],
]);

$this->assertEquals('font-semibold border rounded text-primary text-sm text-red-500', $recipe->apply(['colors' => 'primary', 'sizes' => 'sm']));
}

public static function recipeProvider(): iterable
{
yield 'base null' => [
Expand Down

0 comments on commit 057d68b

Please sign in to comment.