
# クラスユーティリティ

テンプレートで`class`属性を組み立てるには、文字列を結合し、条件に応じてクラスを切り替え、後から使うユーティリティが先に使うものと競合しないようにする必要があります（`p-2`と`p-4`の両方が残るべきではありません）。JavaScriptでは、この処理を[clsx](https://github.com/lukeed/clsx)と[tailwind-merge](https://github.com/dcastil/tailwind-merge)に分けています。TailwindPHPは両方のPHP移植版を提供するため、Node.jsツールチェーンや追加のComposerパッケージなしで同じ動作を実現できます。

3つの関数で用途を網羅します。`cn()`は組み立てと競合解決、`merge()`は競合解決のみ、`join()`は結合のみを行います。

## cn()

推奨ユーティリティです。まずclsxのように条件付きでクラスを組み立て、次にtailwind-mergeでTailwindの競合を解決するため、競合するユーティリティは後に指定したものが優先されます。

```php
use function TailwindPHP\cn;

// Conflicts are resolved — px-4 overrides px-2
cn('px-2 py-1', 'px-4');
// => 'py-1 px-4'

// Conditional classes via a key => bool array
cn('btn', ['btn-primary' => true, 'btn-disabled' => false]);
// => 'btn btn-primary'
```

### 受け付ける引数

`cn()`は任意の数の引数を受け取ります。各引数はclsxのセマンティクスに従って展開・フィルタリングされます。

| 引数 | 動作 |
|----------|----------|
| `string` | そのまま追加されます。 |
| `int` / `float` | 文字列に変換して追加されます。 |
| 順序付き配列 | 各要素を再帰的に処理します。 |
| `key => bool`配列 | 値がtruthyである各キーを追加します。 |
| `null`、`false`、`0`、`''` | 無視されます。 |

```php
cn('flex', ['items-center' => true], ['p-4', ['gap-2']], null);
// => 'flex items-center p-4 gap-2'
```

### コンポーネントのパターン

`cn()`を使うとコンポーネントを上書き可能にできます。コンポーネント独自のクラスと呼び出し側から渡されたクラスをマージすると、競合時には呼び出し側の指定が優先されます。

```php
use function TailwindPHP\cn;

function Card(array $props = []): string {
    $class = cn(
        'rounded-lg border bg-card text-card-foreground shadow-sm',
        $props['class'] ?? null
    );
    return "<div class=\"{$class}\">" . ($props['children'] ?? '') . "</div>";
}

Card(['class' => 'p-6', 'children' => 'Content']);
// <div class="rounded-lg border bg-card text-card-foreground shadow-sm p-6">Content</div>
```

宣言的で複数の軸を持つコンポーネントスタイルには、`cn()`と[variants()](https://tailwindphp.inline0.dev/ja/docs/class-utilities/variants)を組み合わせます。

## merge()

競合解決のみを行い、条件付きの組み立ては行いません。クラス文字列を渡すと、同じプロパティを対象とする場合は後のクラスが前のクラスを上書きします。入力がすでに通常の文字列の場合に使います。

```php
use function TailwindPHP\merge;

merge('px-2 py-1 bg-red-500', 'px-4 bg-blue-500');
// => 'py-1 px-4 bg-blue-500'

// Conflict resolution is variant-aware
merge('hover:bg-red-500', 'hover:bg-blue-500');
// => 'hover:bg-blue-500'
```

`cn()`はclsxの上に`merge()`を組み合わせたものなので、条件付き配列構文が不要な場合に限り、`merge()`を直接使ってください。

## join()

競合解決を行わない単純な結合です。falsy値は除外されますが、競合するユーティリティはすべて残ります。競合がないとわかっていて、最小限の処理にしたい場合に使います。

```php
use function TailwindPHP\join;

join('foo', 'bar', null, 'baz');
// => 'foo bar baz'
```

## どれを使えばよいですか？

| 関数 | 組み立て（条件、配列） | 競合を解決 | 用途 |
|----------|:---:|:---:|----------|
| `cn()`    | はい | はい | 既定の選択肢。競合する可能性のあるクラス文字列の組み立てに使います。 |
| `merge()` | いいえ  | はい | 入力が通常の文字列で、競合解決だけが必要な場合に使います。 |
| `join()`  | はい | いいえ  | 競合がないとわかっていて、処理を最小限にしたい場合に使います。 |

## インポート

```php
use function TailwindPHP\cn;
use function TailwindPHP\merge;
use function TailwindPHP\join;
```

3つともメインの`TailwindPHP`名前空間にあり、パッケージに同梱されています。clsx（Luke Edwards作）とtailwind-merge（Dany Castillo作）のPHP移植版です。
