Skip to content

Commit 057d68b

Browse files
committed
Update CVA docs and fixes
1 parent 1a4f208 commit 057d68b

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

src/TwigComponent/CHANGELOG.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@
55
- Introduce CVA to style TwigComponent #1416
66
- Drop Twig 2 support #1436
77
- Fix full context is stored in profiler #1552
8+
- Add CVA (Class variant authority) integration #1416
89

910
## 2.15.0
1011

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

1616
## 2.14.0
1717

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

2322
## 2.13.0
2423

src/TwigComponent/doc/index.rst

+23-29
Original file line numberDiff line numberDiff line change
@@ -1061,11 +1061,15 @@ Exclude specific attributes:
10611061
Component with Complex Variants (CVA)
10621062
-------------------------------------
10631063

1064-
CVA (Class Variant Authority) is a concept from the JS world (https://cva.style/docs/getting-started/variants).
1065-
It's a concept used by the famous shadcn/ui library (https://ui.shadcn.com).
1064+
.. versionadded:: 2.16
1065+
1066+
The ``CVA`` function was added in TwigComponents 2.16.
1067+
1068+
[CVA (Class Variant Authority)](https://cva.style/docs/getting-started/variants) is a concept from the JavaScript
1069+
world and used by the well-known [shadcn/ui](https://ui.shadcn.com).
10661070
CVA allows you to display a component with different variants (color, size, etc.),
10671071
to create highly reusable and customizable components.
1068-
You can use the cva function to define variants for your component.
1072+
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:
10691073
The cva function take as argument an array key-value pairs.
10701074
The base key allow you define a set of classes commune to all variants.
10711075
In the variants key you define the different variants of your component.
@@ -1095,9 +1099,11 @@ In the variants key you define the different variants of your component.
10951099
{% block content %}{% endblock %}
10961100
</div>
10971101

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

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

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

1111-
<twig:Alert class="flex items-center justify-center">
1117+
<twig:Alert color="red" class="flex items-center justify-center">
11121118
<div>My content</div>
11131119
</twig:Alert>
1114-
// class="alert bg-blue text-md flex items-center justify-center"
1120+
// class="alert bg-red text-md flex items-center justify-center"
11151121

11161122
CVA and Tailwind CSS
11171123
~~~~~~~~~~~~~~~~~~~~
11181124

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

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

11331139
{% set alert = cva({
1134-
base: 'alert ',
1135-
variants: {
1136-
color: {
1137-
blue: 'bg-blue',
1138-
red: 'bg-red',
1139-
green: 'bg-green',
1140-
},
1141-
size: {
1142-
sm: 'text-sm',
1143-
md: 'text-md',
1144-
lg: 'text-lg',
1145-
}
1146-
}
1140+
// ...
11471141
}) %}
11481142

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

1153-
Compounds variants
1147+
Compounds Variants
11541148
~~~~~~~~~~~~~~~~~~
11551149

1156-
You can define compound variants. A compound variant is a variants that apply
1150+
You can define compound variants. A compound variant is a variant that applies
11571151
when multiple other variant conditions are met.
11581152

11591153
.. code-block:: html+twig
@@ -1175,7 +1169,8 @@ when multiple other variant conditions are met.
11751169
lg: 'text-lg',
11761170
}
11771171
},
1178-
compound: {
1172+
compoundVariants: {
1173+
// if colors=red AND size = (md or lg), add the `font-bold` class
11791174
colors: ['red'],
11801175
size: ['md', 'lg'],
11811176
class: 'font-bold'
@@ -1203,11 +1198,10 @@ when multiple other variant conditions are met.
12031198
</twig:Alert>
12041199
// class="alert bg-green text-lg font-bold"
12051200

1206-
Default variants
1201+
Default Variants
12071202
~~~~~~~~~~~~~~~~
12081203

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

12121206
.. code-block:: html+twig
12131207

src/TwigComponent/tests/Unit/CVATest.php

+23
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,29 @@ public function testRecipes(array $recipe, array $recipes, string $expected): vo
2929
$this->assertEquals($expected, $recipeClass->resolve($recipes));
3030
}
3131

32+
public function testApply(): void
33+
{
34+
$recipe = new CVA('font-semibold border rounded', [
35+
'colors' => [
36+
'primary' => 'text-primary',
37+
'secondary' => 'text-secondary',
38+
],
39+
'sizes' => [
40+
'sm' => 'text-sm',
41+
'md' => 'text-md',
42+
'lg' => 'text-lg',
43+
],
44+
], [
45+
[
46+
'colors' => ['primary'],
47+
'sizes' => ['sm'],
48+
'class' => 'text-red-500',
49+
],
50+
]);
51+
52+
$this->assertEquals('font-semibold border rounded text-primary text-sm text-red-500', $recipe->apply(['colors' => 'primary', 'sizes' => 'sm']));
53+
}
54+
3255
public static function recipeProvider(): iterable
3356
{
3457
yield 'base null' => [

0 commit comments

Comments
 (0)