-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathCva.php
129 lines (115 loc) · 3.88 KB
/
Cva.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Extra\Html;
/**
* Class Variant Authority (CVA) resolver.
*
* @author Mathéo Daninos <[email protected]>
*/
final class Cva
{
/**
* @var list<string|null>
*/
private array $base;
/**
* @param string|list<string|null> $base The base classes to apply to the component
*/
public function __construct(
string|array $base = [],
/**
* The variants to apply based on recipes.
*
* Format: [variantCategory => [variantName => classes]]
*
* Example:
* 'colors' => [
* 'primary' => 'bleu-8000',
* 'danger' => 'red-800 text-bold',
* ],
* 'size' => [...],
*
* @var array<string, array<string, string|list<string>>>
*/
private array $variants = [],
/**
* The compound variants to apply based on recipes.
*
* Format: [variantsCategory => ['variantName', 'variantName'], class: classes]
*
* Example:
* [
* 'colors' => ['primary'],
* 'size' => ['small'],
* 'class' => 'text-red-500',
* ],
* [
* 'size' => ['large'],
* 'class' => 'font-weight-500',
* ]
*
* @var array<array<string, string|array<string>>>
*/
private array $compoundVariants = [],
/**
* The default variants to apply if specific recipes aren't provided.
*
* Format: [variantCategory => variantName]
*
* Example:
* 'colors' => 'primary',
*
* @var array<string, string>
*/
private array $defaultVariants = [],
) {
$this->base = (array) $base;
}
public function apply(array $recipes, ?string ...$additionalClasses): string
{
$classes = $this->base;
// Resolve recipes against variants
foreach ($recipes as $recipeName => $recipeValue) {
if (\is_bool($recipeValue)) {
$recipeValue = $recipeValue ? 'true' : 'false';
}
$recipeClasses = $this->variants[$recipeName][$recipeValue] ?? [];
$classes = [...$classes, ...(array) $recipeClasses];
}
// Resolve compound variants
foreach ($this->compoundVariants as $compound) {
$compoundClasses = $this->resolveCompoundVariant($compound, $recipes) ?? [];
$classes = [...$classes, ...$compoundClasses];
}
// Apply default variants if specific recipes aren't provided
foreach ($this->defaultVariants as $defaultVariantName => $defaultVariantValue) {
if (!isset($recipes[$defaultVariantName])) {
$variantClasses = $this->variants[$defaultVariantName][$defaultVariantValue] ?? [];
$classes = [...$classes, ...(array) $variantClasses];
}
}
$classes = [...$classes, ...array_values($additionalClasses)];
$classes = implode(' ', array_filter($classes, 'is_string'));
$classes = preg_split('#\s+#', $classes, -1, \PREG_SPLIT_NO_EMPTY) ?: [];
return implode(' ', array_unique($classes));
}
private function resolveCompoundVariant(array $compound, array $recipes): array
{
foreach ($compound as $compoundName => $compoundValues) {
if ('class' === $compoundName) {
continue;
}
if (!isset($recipes[$compoundName]) || !\in_array($recipes[$compoundName], (array) $compoundValues)) {
return [];
}
}
return (array) ($compound['class'] ?? []);
}
}