diff --git a/src/TwigComponent/CHANGELOG.md b/src/TwigComponent/CHANGELOG.md index fca15e5b73c..f9fd2eeeb65 100644 --- a/src/TwigComponent/CHANGELOG.md +++ b/src/TwigComponent/CHANGELOG.md @@ -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 diff --git a/src/TwigComponent/doc/index.rst b/src/TwigComponent/doc/index.rst index b0ef2c4345c..4411dd059a9 100644 --- a/src/TwigComponent/doc/index.rst +++ b/src/TwigComponent/doc/index.rst @@ -1061,14 +1061,16 @@ 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)`_ is a concept from the JavaScript world and used +by the well-known `shadcn/ui`_. 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. -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. +to create highly reusable and customizable components. 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: .. code-block:: html+twig @@ -1095,9 +1097,11 @@ In the variants key you define the different variants of your component. {% block content %}{% endblock %} +Then use the ``color`` and ``size`` variants to select the classes needed: - {# index.html.twig #} +.. code-block:: html+twig + {# index.html.twig #}
My content
@@ -1108,18 +1112,18 @@ In the variants key you define the different variants of your component. // class="alert bg-green text-sm" - +
My content
- // 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 ones you need, use the +``tailwind_merge()` method from `tales-from-a-dev/twig-tailwind-extra`_ +with the ``cva()`` function: .. code-block:: terminal @@ -1131,29 +1135,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', - } - } + // ... }) %}
{% block content %}{% endblock %}
-Compounds variants -~~~~~~~~~~~~~~~~~~ +Compound 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 @@ -1175,7 +1167,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' @@ -1203,11 +1196,10 @@ when multiple other variant conditions are met.
// 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 @@ -1615,3 +1607,6 @@ https://symfony.com/doc/current/contributing/code/bc.html .. _`Live Nested Components`: https://symfony.com/bundles/ux-live-component/current/index.html#nested-components .. _`Passing Blocks to Live Components`: https://symfony.com/bundles/ux-live-component/current/index.html#passing-blocks .. _`Stimulus controller`: https://symfony.com/bundles/StimulusBundle/current/index.html +.. _`CVA (Class Variant Authority)`: https://cva.style/docs/getting-started/variants +.. _`shadcn/ui`: https://ui.shadcn.com +.. _`tales-from-a-dev/twig-tailwind-extra`: https://github.com/tales-from-a-dev/twig-tailwind-extra diff --git a/src/TwigComponent/tests/Unit/CVATest.php b/src/TwigComponent/tests/Unit/CVATest.php index 49d105ccee7..5a5bf42aa41 100644 --- a/src/TwigComponent/tests/Unit/CVATest.php +++ b/src/TwigComponent/tests/Unit/CVATest.php @@ -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' => [