Skip to content

Commit

Permalink
apply review
Browse files Browse the repository at this point in the history
  • Loading branch information
WebMamba committed Aug 16, 2024
1 parent 253f57d commit e7f676f
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 57 deletions.
61 changes: 31 additions & 30 deletions doc/functions/html_cva.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
``cva``
``html_cva``
=======

`CVA (Class Variant Authority)`_ is a concept from the JavaScript world and used
by the well-known `shadcn/ui`_.
The Cva concept is used to render multiple variations of components, applying
The CVA concept is used to render multiple variations of components, applying
a set of conditions and recipes to dynamically compose CSS class strings (color, size, etc.),
to create highly reusable and customizable templates. This function work best by being combined with
`TwigComponent`_
to create highly reusable and customizable templates.

.. note::

Expand All @@ -19,16 +18,16 @@ to create highly reusable and customizable templates. This function work best by
Then, on Symfony projects, install the ``twig/extra-bundle``:

This is powered by a ``html_cva()`` Twig
The concept of CVA is powered by a ``html_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

{# templates/alert.html.twig #}
{% set alert = html_cva({
base: 'alert ',
variants: {
{% set alert = html_cva(
base='alert ',
variants={
color: {
blue: 'bg-blue',
red: 'bg-red',
Expand All @@ -46,18 +45,18 @@ function where you define ``base`` classes that should always be present and the
...
</div>

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

.. code-block:: twig
{# index.html.twig #}
{% include 'alert.html.twig' with {'color': 'blue', 'size': 'md'} %}
{{ include('alert.html.twig', {'color': 'blue', 'size': 'md'}) }}
// class="alert bg-red text-lg"
{% include 'alert.html.twig' with {'color': 'green', 'size': 'sm'} %}
{{ include('alert.html.twig', {'color': 'green', 'size': 'sm'}) }}
// class="alert bg-green text-sm"
{% include 'alert.html.twig' with {'color': 'red', 'class': 'flex items-center justify-center'} %}
{{ include('alert.html.twig', {'color': 'red', 'class': 'flex items-center justify-center'}) }}
// class="alert bg-red text-md flex items-center justify-center"
CVA and Tailwind CSS
Expand All @@ -74,25 +73,25 @@ with the ``html_cva()`` function:
.. code-block:: html+twig

{% set alert = html_cva({
{% set alert = html_cva(
// ...
}) %}
) %}

<div class="{{ alert.apply({color, size}, class) | tailwind_merge }}">
<div class="{{ alert.apply({color, size}, class)|tailwind_merge }}">
...
</div>

Compound Variants
~~~~~~~~~~~~~~~~~

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

.. code-block:: html+twig

{% set alert = html_cva({
base: 'alert ',
variants: {
{% set alert = html_cva(
base='alert',
variants={
color: {
blue: 'bg-blue',
red: 'bg-red',
Expand All @@ -104,27 +103,27 @@ when multiple other variant conditions are met.
lg: 'text-lg',
}
},
compoundVariants: [{
compoundVariants=[{
// if color = red AND size = (md or lg), add the `font-bold` class
color: ['red'],
size: ['md', 'lg'],
class: 'font-bold'
}]
}) %}
) %}

<div class="{{ alert.apply({color, size}) }}">
...
</div>

{# index.html.twig #}

{% include 'alert.html.twig' with {color: 'red', size: 'lg'} %}
{{ include('alert.html.twig', {color: 'red', size: 'lg'}) }}
// class="alert bg-red text-lg font-bold"

{% include 'alert.html.twig' with {color: 'green', size: 'sm'} %}
{{ include('alert.html.twig', {color: 'green', size: 'sm'}) }}
// class="alert bg-green text-sm"

{% include 'alert.html.twig' with {color: 'red', size: 'md'} %}
{{ include('alert.html.twig', {color: 'red', size: 'md'}) }}
// class="alert bg-green text-lg font-bold"

Default Variants
Expand All @@ -134,9 +133,9 @@ If no variants match, you can define a default set of classes to apply:

.. code-block:: html+twig

{% set alert = html_cva({
base: 'alert ',
variants: {
{% set alert = html_cva(
base='alert ',
variants={
color: {
blue: 'bg-blue',
red: 'bg-red',
Expand All @@ -153,20 +152,22 @@ If no variants match, you can define a default set of classes to apply:
lg: 'rounded-lg',
}
},
defaultVariants: {
defaultVariants={
rounded: 'md',
}
}) %}
) %}

<div class="{{ alert.apply({color, size}) }}">
...
</div>

{# index.html.twig #}

{% include 'alert.html.twig' with {color: 'red', size: 'lg'} %}
{{ include('alert.html.twig', {color: 'red', size: 'lg'}) }}
// class="alert bg-red text-lg font-bold rounded-md"

This function works best when used with `TwigComponent`_.

.. _`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
Expand Down
11 changes: 1 addition & 10 deletions extra/html-extra/Cva.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,9 @@
namespace Twig\Extra\Html;

/**
* Class Variant Authority (Cva) resolver.
*
* The Cva concept is used to render multiple variations of components, applying
* a set of conditions and recipes to dynamically compose CSS class strings.
*
* @see https://cva.style/docs
*
* @doc https://symfony.com/bundles/ux-twig-component/current/index.html
* Class Variant Authority (CVA) resolver.
*
* @author Mathéo Daninos <[email protected]>
*
* @experimental
*/
final class Cva
{
Expand Down
14 changes: 2 additions & 12 deletions extra/html-extra/HtmlExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,24 +113,14 @@ public static function htmlClasses(...$args): string
}

/**
* base some base class you want to have in every matching recipes
* variants your recipes class
* compoundVariants compounds allow you to add extra class when multiple variation are matching in the same time
* defaultVariants allow you to add a default class when no recipe is matching
*
* @param string|list<string|null>|null $base
* @param string|list<string|null> $base
* @param array<string, array<string, string|array<string>> $variants
* @param array<array<string, string|array<string>>> $compoundVariants
* @param array<string, string> $defaultVariant
* @internal
*/
public static function htmlCva(array|string $base = [], array $variants = [], array $compoundVariants = [], array $defaultVariant = []): Cva
{
return new Cva(
$base,
$variants,
$compoundVariants,
$defaultVariant
);
return new Cva($base, $variants, $compoundVariants, $defaultVariant);
}
}
2 changes: 1 addition & 1 deletion extra/html-extra/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This package is a Twig extension that provides the following:
* [`html_classes`][2] function: returns a string by conditionally joining class
names together.

* [`html_cva`][3] function: return a Cva object to handle class variants.
* [`html_cva`][3] function: returns a `Cva object to handle class variants.

[1]: https://twig.symfony.com/data_uri
[2]: https://twig.symfony.com/html_classes
Expand Down
15 changes: 11 additions & 4 deletions extra/html-extra/Tests/CVATest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
use PHPUnit\Framework\TestCase;
use Twig\Extra\Html\Cva;

class CVATest extends TestCase
class CvaTest extends TestCase
{
/**
* @dataProvider recipeProvider
Expand Down Expand Up @@ -51,7 +51,7 @@ public function testApply()

public function testApplyWithNullString()
{
$recipe = new CVA('font-semibold border rounded', [
$recipe = new Cva('font-semibold border rounded', [
'colors' => [
'primary' => 'text-primary',
'secondary' => 'text-secondary',
Expand Down Expand Up @@ -360,6 +360,7 @@ public static function recipeProvider(): iterable
['colors' => 'primary', 'sizes' => 'sm'],
'font-semibold border rounded text-primary text-sm',
];

yield 'default variables' => [
[
'base' => 'font-semibold border rounded',
Expand Down Expand Up @@ -395,6 +396,7 @@ public static function recipeProvider(): iterable
['colors' => 'primary', 'sizes' => 'sm'],
'font-semibold border rounded text-primary text-sm rounded-md',
];

yield 'default variables all overwrite' => [
[
'base' => 'font-semibold border rounded',
Expand Down Expand Up @@ -430,6 +432,7 @@ public static function recipeProvider(): iterable
['colors' => 'primary', 'sizes' => 'sm', 'rounded' => 'lg'],
'font-semibold border rounded text-primary text-sm rounded-lg',
];

yield 'default variables without matching variants' => [
[
'base' => 'font-semibold border rounded',
Expand Down Expand Up @@ -622,8 +625,8 @@ public static function recipeProvider(): iterable
*/
public function testAdditionalClasses(string|array $base, array|string $additionals, string $expected)
{
$cva = new CVA($base);
if ([] === $additionals || '' === $additionals) {
$cva = new Cva($base);
if (!$additionals) {
$this->assertEquals($expected, $cva->apply([]));
} else {
$this->assertEquals($expected, $cva->apply([], ...(array) $additionals));
Expand All @@ -637,21 +640,25 @@ public static function provideAdditionalClassesCases(): iterable
'foo',
'foo',
];

yield 'additional_are_used' => [
'',
'foo',
'foo',
];

yield 'additionals_are_used' => [
'',
['foo', 'bar'],
'foo bar',
];

yield 'additionals_preserve_order' => [
['foo'],
['bar', 'foo'],
'foo bar',
];

yield 'additional_are_deduplicated' => [
'',
['bar', 'bar'],
Expand Down
File renamed without changes.

0 comments on commit e7f676f

Please sign in to comment.