跳转到正文

变体

variants() 是 PHP 移植版,基于 CVA (Class Variance Authority)。它会将声明式配置——基础类、命名变体轴和默认值——转换为一个可调用函数,用于将 props 映射为类字符串。当组件的样式维度(如尺寸和意图)需要组合时,可以使用它。

PHP
use function TailwindPHP\variants;

$button = variants([
    'base' => 'btn font-semibold border rounded',
    'variants' => [
        'intent' => [
            'primary'   => 'bg-blue-500 text-white',
            'secondary' => 'bg-gray-200 text-gray-800',
        ],
        'size' => [
            'sm' => 'text-sm px-2 py-1',
            'md' => 'text-base px-4 py-2',
        ],
    ],
    'defaultVariants' => [
        'intent' => 'primary',
        'size'   => 'md',
    ],
]);

$button();
// => 'btn font-semibold border rounded bg-blue-500 text-white text-base px-4 py-2'

variants() 返回一个 callable;传入 props 数组(也可以不传)即可获得解析后的字符串。

配置

键 类型 用途
base string 应用于每个输出的类。
variants array 命名轴,每个轴将值名称映射到类字符串。
compoundVariants array 仅当多个变体值组合时应用的类字符串。
defaultVariants array 未提供 prop 时各轴使用的值。

所有键均为可选项。不提供 variants 时,结果会返回 base 以及任何自定义类:

PHP
$x = variants(['base' => 'box']);
$x();                          // => 'box'
$x(['class' => 'p-4']);        // => 'box p-4'

变体值可以映射到 null,表示不添加任何内容——这适合作为轴中的显式“未设置”选项。

调用结果

像使用 CVA 一样传入单个 props 数组。键名对应变体轴名称;未提供的轴会回退到 defaultVariants。

PHP
$button(['intent' => 'secondary']);
// => 'btn font-semibold border rounded bg-gray-200 text-gray-800 text-base px-4 py-2'

$button(['size' => 'sm', 'class' => 'mt-4']);
// => 'btn font-semibold border rounded bg-blue-500 text-white text-sm px-2 py-1 mt-4'

class 键(及其别名 className)会追加到输出末尾。仅追加本身不会解决冲突——请参阅下方的组件模式。

compoundVariants

compoundVariants 中的每个条目都是一个变体条件数组,以及一个额外类的 class(或 className)。只有在所有条件都与已解析的 props(包括默认值)匹配时,这些类才会应用。条件值可以是单个字符串,也可以是字符串数组,用于匹配多个值中的任意一个。

PHP
$button = variants([
    'base' => 'btn',
    'variants' => [
        'intent' => [
            'primary' => 'bg-blue-500',
            'warning' => 'bg-yellow-500',
            'danger'  => 'bg-red-500',
        ],
        'size' => ['sm' => 'text-sm', 'md' => 'text-base'],
    ],
    'compoundVariants' => [
        // Applies only when intent=primary AND size=md
        ['intent' => 'primary', 'size' => 'md', 'class' => 'uppercase'],
        // Applies when intent is warning OR danger
        ['intent' => ['warning', 'danger'], 'class' => '!border-red-500'],
    ],
    'defaultVariants' => ['intent' => 'primary', 'size' => 'md'],
]);

$button();
// => 'btn bg-blue-500 text-base uppercase'

$button(['intent' => 'danger']);
// => 'btn bg-red-500 text-base !border-red-500'

组件模式

variants() 只会追加 class;要让调用方真正覆盖变体默认值,请将输出包装在 cn() 中,这样发生冲突时就会以调用方为准。

PHP
use function TailwindPHP\variants;
use function TailwindPHP\cn;

function Button(array $props = []): string {
    static $styles = null;
    $styles ??= variants([
        'base' => 'inline-flex items-center justify-center rounded-md font-medium',
        'variants' => [
            'variant' => [
                'default' => 'bg-primary text-primary-foreground hover:bg-primary/90',
                'outline' => 'border border-input bg-background hover:bg-accent',
                'ghost'   => 'hover:bg-accent hover:text-accent-foreground',
            ],
            'size' => [
                'default' => 'h-10 px-4 py-2',
                'sm'      => 'h-9 px-3',
                'lg'      => 'h-11 px-8',
            ],
        ],
        'defaultVariants' => ['variant' => 'default', 'size' => 'default'],
    ]);

    // cn() merges variant output with custom classes, resolving conflicts
    $class = cn($styles($props), $props['class'] ?? null);
    $text  = $props['children'] ?? 'Button';
    return "<button class=\"{$class}\">{$text}</button>";
}

// The custom px-8 wins over the variant's px-3 via cn()
Button(['variant' => 'outline', 'size' => 'sm', 'class' => 'mt-4 px-8']);

static $styles 缓存会构建一次变体配置,并在后续调用中重复使用。

compose()

compose() 会将多个变体组件合并为一个。组合后的可调用函数会把每个 prop 传递给所有组件,收集它们的输出,并追加任何 class/className。

PHP
use function TailwindPHP\variants;
use function TailwindPHP\compose;

$box   = variants(['variants' => ['shadow' => ['sm' => 'shadow-sm', 'md' => 'shadow-md']]]);
$stack = variants(['variants' => ['gap' => ['1' => 'gap-1', '2' => 'gap-2']]]);
$card  = compose($box, $stack);

$card(['shadow' => 'md', 'gap' => '2']);
// => 'shadow-md gap-2'

这样,可复用的轴(间距、阴影、布局)可以分别定义,再按组件组合。

导入

PHP
use function TailwindPHP\variants;
use function TailwindPHP\compose;

两者都位于主 TailwindPHP 命名空间中,并随软件包一起打包——是 Joe Bell 编写的 CVA 的 PHP 移植版。