Botones
Estado: BetaBotón con estados
El botón cuenta lo que pasa con la acción: gira mientras reserva, dibuja una palomita al terminar y regresa solo a su estado normal; si algo falla, se sacude y lo dice. El ancho cambia con resorte entre estados. Dentro de un formulario escucha a Turbo, así que funciona con el submit de siempre.
- Resorte
- Turbo
- aria-live
app/views/… (la demo de arriba)
<div class="flex flex-wrap items-center justify-center gap-3">
<%= render Ui::ActionButtonComponent.new(label: "Reservar clase", simulate: true) do %>
<%= render Ui::IconComponent.new(:calendar, size: :sm) %>
<% end %>
<%= render Ui::ActionButtonComponent.new(label: "Usar 1 crédito", loading_label: "Cobrando…", success_label: "Listo", error_label: "Sin créditos", variant: :secondary, simulate: :error) %>
</div>Qué hace
- Con Turbo: turbo:submit-start → cargando; turbo:submit-end → éxito si detail.success, si no error.
- Solo reacciona si este botón envió el formulario; un segundo clic mientras carga no reenvía.
- El ancho de cada estado se mide y el botón lo sigue con el resorte "responsive".
- La sacudida del error es un impulso de velocidad sobre un resorte, no una animación fija.
- Controlable desde fuera: action-button#start / #succeed / #fail / #reset o data-action-button-state-value (Turbo Stream).
Props
| Nombre | Tipo | Default | Descripción |
|---|---|---|---|
| label | String | — | Texto en reposo (y nombre accesible). Un bloque opcional se pinta antes, p. ej. un ícono. |
| loading_label | String | "Reservando…" | Mientras carga; se anuncia. |
| success_label | String | "Reservado" | Al terminar bien; se anuncia. |
| error_label | String | "No se pudo" | Si falla; se anuncia. |
| variant | :primary | :secondary | :primary | Superficie del botón; en error toma el color de error. |
| size | :sm | :md | :lg | :md | Alto (sigue el dial de densidad) y tipografía. |
| simulate | true | :success | :error | nil | Solo para demos: simula ~1.2s de carga y luego éxito o error. |
| reset_after | Integer (ms) | 2000 | Cuánto se queda el resultado antes de volver a idle (el error, medio segundo más); 0 = se queda. |
| type | String | "submit" | Tipo del <button>. |
| data | Hash | {} | Atributos data del <button>; la acción del controlador se combina con las tuyas. |
Accesibilidad
- Es un <button> nativo; aria-busy="true" mientras carga.
- Cada cambio de estado se anuncia en una región aria-live fuera del botón.
- Si Turbo lo deshabilita mientras envía, al terminar le regresa el foco.
- Con movimiento reducido el ancho salta, el spinner se queda quieto y no hay sacudida.