# Spinner

> El indicador de carga: tres tamaños, el color del texto y nombre accesible opcional.

```tsx
import { Spinner } from "sebs7n-ui/spinner"
```

Sin `"use client"`: sirve en un Server Component.

## Ejemplos

### Tamaños y color

16 / 20 / 24px. Hereda el color del texto: no tiene prop de color.

```tsx
import { Spinner } from "sebs7n-ui/spinner"

function Tamanos() {
  return (
    <div className="flex flex-wrap items-center gap-6 text-label-secondary">
      <Spinner size="sm" />
      <Spinner />
      <Spinner size="lg" />
      <Spinner className="text-brand-700" size="lg" />
    </div>
  )
}
```

### Con nombre accesible

Con `label` es una región `role="status"`: el lector anuncia «Buscando facturas» al aparecer.

```tsx
import { Spinner } from "sebs7n-ui/spinner"

function ConNombre() {
  return (
    <div className="flex items-center gap-2 text-callout text-label-secondary">
      <Spinner label="Buscando facturas" size="sm" />
      <span aria-hidden="true">Buscando facturas…</span>
    </div>
  )
}
```

### Dentro de un botón

`Button loading` ya usa este mismo Spinner: no lo pongas a mano.

```tsx
import { Button } from "sebs7n-ui/button"
import { useState } from "react"

function EnUnBoton() {
  const [loading, setLoading] = useState(false)
  return (
    <div className="flex flex-wrap items-center gap-3">
      <Button
        loading={loading}
        onClick={() => {
          setLoading(true)
          setTimeout(() => setLoading(false), 2000)
        }}
      >
        Emitir factura
      </Button>
      <Button loading size="lg">
        Grande
      </Button>
    </div>
  )
}
```

## Props

### Spinner

Hereda las props de `<svg>`.

| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
| `label` | `string` | — | Nombre accesible. Con `label` el spinner es una región `role="status"` y el lector anuncia el texto al aparecer; sin `label` es decoración (`aria-hidden`), que es lo que corresponde cuando quien anuncia la espera es otro elemento —el `Button` con `aria-busy`, una lista con `aria-busy`—. |
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | `sm` 16px (el del botón) · `md` 20px · `lg` 24px. |
| `className` | `string` | — | Se fusiona con las clases del componente vía `cn()` (tailwind-merge): lo que pongas gana. |

## Teclado

| Tecla | Qué hace |
|---|---|
| — | No es interactivo. |

## Accesibilidad

- Sin `label` es decoración (`aria-hidden`): quien anuncia la espera es el contenedor, con `aria-busy`.
- Con `label` emite `role="status"` y el lector anuncia el texto al aparecer, sin robar el foco.
- Con `prefers-reduced-motion` deja de girar pero **no se esconde**: un spinner que desaparece borra la única señal de que algo está pasando.
- Sin `"use client"`: sirve en un Server Component.

## Reglas de uso

- **Dentro de un `Button` no lo pongas a mano**: `Button loading` ya usa este mismo Spinner, lo centra y pone `aria-busy`.
- Hereda el color del texto (`currentColor`): no tiene prop de color, se pinta con `text-*` del contenedor.
- Para una carga que reemplaza contenido que ya tiene forma —una tabla, una card— va `Skeleton`, no un spinner.
- Un solo nombre accesible por región: si el spinner está al lado de un texto «Buscando…», el que lleva `label` es uno de los dos.

## Relacionados

[button](/docs/components/button.md) · [skeleton](/docs/components/skeleton.md) · [empty-state](/docs/components/empty-state.md)
