
# Complementos personalizados

Un complemento personalizado es una clase PHP que implementa `TailwindPHP\Plugin\PluginInterface`. Recibe una instancia de `PluginAPI` y la usa para registrar utilidades estáticas y funcionales, componentes y variantes. Una vez registrado con `registerPlugin()`, el complemento se resuelve por nombre en una directiva `@plugin`, mediante el mismo mecanismo que usan los complementos integrados de tipografía y formularios.

## `PluginInterface`

Implementa tres métodos:

```php
namespace TailwindPHP\Plugin;

interface PluginInterface
{
    public function getName(): string;
    public function __invoke(PluginAPI $api, array $options = []): void;
    public function getThemeExtensions(array $options = []): array;
}
```

- `getName()` devuelve el identificador que se usa en `@plugin "..."`.
- `__invoke()` ejecuta el complemento y registra todo mediante `$api`. El arreglo `$options` contiene los valores del bloque `@plugin` CSS.
- `getThemeExtensions()` devuelve los espacios de nombres del tema que se combinarán antes de generar las utilidades (devuelve `[]` si no hay ninguno).

## Ejemplo

```php
use TailwindPHP\Plugin\PluginInterface;
use TailwindPHP\Plugin\PluginAPI;

class MyCustomPlugin implements PluginInterface
{
    public function getName(): string
    {
        return 'my-custom-plugin';
    }

    public function __invoke(PluginAPI $api, array $options = []): void
    {
        // Static utilities
        $api->addUtilities([
            '.btn' => [
                'padding' => '0.5rem 1rem',
                'border-radius' => '0.25rem',
                'font-weight' => '600',
            ],
            '.btn-primary' => [
                'background-color' => 'blue',
                'color' => 'white',
            ],
        ]);

        // Functional utilities (generates .gutter-sm, .gutter-md, .gutter-lg)
        $api->matchUtilities(
            [
                'gutter' => fn ($value) => ['padding-inline' => $value],
            ],
            ['values' => ['sm' => '1rem', 'md' => '2rem', 'lg' => '3rem']]
        );

        // Component classes (sorted into the components layer)
        $api->addComponents([
            '.card' => [
                'background-color' => 'white',
                'border-radius' => '0.5rem',
                'padding' => '1rem',
            ],
        ]);

        // Custom variant (see the note below the API reference)
        $api->addVariant('hocus', '&:hover, &:focus');

        // Read a theme value
        $primary = $api->theme('colors.blue.500', '#3b82f6');
    }

    public function getThemeExtensions(array $options = []): array
    {
        return []; // Return theme additions if needed
    }
}
```

## Referencia de `PluginAPI`

La API refleja la TailwindCSS del complemento API:

| Método | Firma | Propósito |
|--------|-----------|---------|
| `addBase` | `addBase(array $css): void` | Añadir estilos a la capa base. |
| `addUtilities` | `addUtilities(array $utilities, array $options = []): void` | Registrar clases de utilidad estáticas asociadas a un selector. |
| `matchUtilities` | `matchUtilities(array $utilities, array $options = []): void` | Registrar utilidades funcionales; `$options['values']` proporciona el mapa de valores y `$options['supportsNegativeValues']` habilita los valores negativos. |
| `addComponents` | `addComponents(array $components, array $options = []): void` | Registrar clases de componentes (capa de componentes). |
| `matchComponents` | `matchComponents(array $components, array $options = []): void` | Registrar componentes funcionales con un mapa de valores. |
| `addVariant` | `addVariant(string $name, string\|array $variant): void` | Registrar una variante estática a partir de un selector. |
| `matchVariant` | `matchVariant(string $name, callable $callback, array $options = []): void` | Registrar una variante funcional; `$options['values']` proporciona el mapa de valores. |
| `theme` | `theme(string $path, mixed $defaultValue = null): mixed` | Leer un valor del tema mediante una ruta con puntos (e.g. `colors.blue.500`). |
| `config` | `config(?string $path = null, mixed $defaultValue = null): mixed` | Leer un valor de configuración mediante una ruta con puntos, o toda la configuración si `$path` es null. |
| `prefix` | `prefix(string $className): string` | Aplicar el prefijo configurado a un nombre de clase. |

La función de retorno que se pasa a `matchUtilities`, `matchComponents` y `matchVariant` recibe el valor y un arreglo de segundo argumento que contiene una clave `modifier`.

Elige nombres de utilidad que el núcleo de Tailwind no use ya. Si una utilidad del complemento tiene el mismo nombre que una del núcleo (por ejemplo, `tab-*`, que el núcleo de Tailwind usa para `tab-size` desde v4.3), ambas declaraciones quedan en la misma regla y la del núcleo aparece al final, por lo que prevalece: una `tab-4` del complemento asignada a `7` sigue generando `tab-size: 4`.

> **Problema conocido:** las variantes registradas con `addVariant()` y las variantes por valor que registra `matchVariant()` no se aplican en la versión actual. `hocus:flex` del ejemplo anterior se compila como `.hocus\:flex { display: flex; }` sin selector `:hover`/`:focus` ([#10](https://github.com/inline0/tailwindphp/issues/10)). Hasta que se corrija, define la variante en CSS con [`@custom-variant`](https://tailwindphp.inline0.dev/es/docs/usage/directives#custom-variant), que sí funciona: `@custom-variant hocus (&:hover, &:focus);`.

## Registro y uso

Registra la instancia del complemento y luego haz referencia a ella con el nombre de `getName()`:

```php
use TailwindPHP\tw;
use function TailwindPHP\registerPlugin;

registerPlugin(new MyCustomPlugin());

$css = tw::generate(
    '<div class="btn btn-primary card gutter-md">…</div>',
    '@plugin "my-custom-plugin"; @import "tailwindcss/utilities.css";'
);
```

Consulta [Complementos](https://tailwindphp.inline0.dev/es/docs/plugins) para la directiva `@plugin` y [Tema](https://tailwindphp.inline0.dev/es/docs/usage/theme) para los valores disponibles mediante `$api->theme()`.
