Capas
Estado: EstableConfirmación
Se monta una vez en el layout y reemplaza el confirm() nativo en todas las confirmaciones de Turbo (Turbo.config.forms.confirm): cada form, button_to o link_to con data-turbo-confirm la usa tal cual. Toma el título de la pregunta, el texto del botón de lo que se presionó y se vuelve destructiva sola en un DELETE. Para lo irreversible, data-confirm-hold pide mantener presionado mientras un relleno avanza.
- Turbo
- data-turbo-confirm
- Mantener presionado
- alertdialog
app/views/… (la demo de arriba)
<%# En la app va una sola vez en el layout; desde ahí toma TODOS los
data-turbo-confirm. %>
<%= render Ui::ConfirmDialogComponent.new %>
<%# Botones de verdad (button_to, como en el admin). Cada uno manda un GET a
esta ficha que actualiza el frame de abajo: si cancelas, no se envía. %>
<% demo_form = { class: "contents", data: { turbo_frame: "confirm-dialog-result" } } %>
<div class="flex w-full max-w-sm flex-col items-center gap-5">
<div class="flex flex-wrap items-center justify-center gap-2">
<%= button_to "Reenviar guía", ui_component_path("confirm-dialog"), method: :get, params: { hecho: "Correo con la guía reenviado" }, form: demo_form,
class: Ui::ButtonComponent.classes(variant: :secondary),
data: { turbo_confirm: "¿Reenviar a Ana López el correo con el número de guía?" } %>
<%= button_to "Cancelar reserva", ui_component_path("confirm-dialog"), method: :get, params: { hecho: "Reservación cancelada" }, form: demo_form,
class: Ui::ButtonComponent.classes(variant: :secondary),
data: { turbo_confirm: "¿Cancelar tu reservación de Vinyasa Flow? Faltan menos de 12 horas: el crédito no se devuelve.",
confirm_tone: "danger", confirm_cancel: "Conservar mi lugar" } %>
<%= button_to "Eliminar a Ana López", ui_component_path("confirm-dialog"), method: :get, params: { hecho: "Ana López eliminada" }, form: demo_form,
class: Ui::ButtonComponent.classes(tone: :danger),
data: { turbo_confirm: "¿Eliminar a Ana López? Se borrarán también sus reservaciones, paquetes, pagos y demás datos asociados. Esta acción no se puede deshacer.",
confirm_hold: true, confirm_accept: "Eliminar" } %>
</div>
<%= turbo_frame_tag "confirm-dialog-result", class: "block min-h-5 text-center text-xs text-muted-foreground" do %>
<% if params[:hecho].present? %>
<span class="text-foreground"><%= params[:hecho] %></span> · <span class="font-mono"><%= Time.current.strftime("%H:%M:%S") %></span>
<% else %>
Nada se ha enviado todavía
<% end %>
<% end %>
</div>Qué hace
- Las 25 vistas con data-turbo-confirm la usan sin cambios; resuelve la promesa en false con Cancelar, Esc o el fondo.
- Dos confirmaciones seguidas no se mezclan; la que queda pendiente se responde "no" antes de mostrar la nueva.
- Montarla dos veces no rompe nada; gana la última conectada y al desconectarse vuelve la anterior.
- También confirma los botones con data-turbo="false" (Turbo ignoraba su data-turbo-confirm) y los link_to con data-turbo-method (lee sus data-confirm-*).
- Desde JS: import { confirm } from "controllers/confirm_dialog_controller"; await confirm("¿Salir?", { tone: "danger" }).
Props
| Nombre | Tipo | Default | Descripción |
|---|---|---|---|
| data-turbo-confirm | String (en el botón, form o enlace) | — | La pregunta. "¿…?" al inicio es el título y el resto la descripción. |
| data-confirm-title | String | de la pregunta | Título propio; el mensaje queda como descripción. |
| data-confirm-accept | String | texto del botón | Texto del botón de aceptar ("Eliminar"). Si no, el del botón presionado. |
| data-confirm-cancel | String | "Cancelar" | Texto de cancelar; "Volver" si la acción ya empieza con Cancelar. |
| data-confirm-tone | "danger" | danger en DELETE | Botón destructivo, ícono de alerta y foco inicial en Cancelar. |
| data-confirm-hold | "true" | — | Lo irreversible: mantener presionado (o Espacio/Enter) ~1 s para aceptar. |
| id / title / accept / cancel | String | "eui-confirm" / "¿Confirmas esta acción?" / "Confirmar" / "Cancelar" | Del componente: id del dialog y textos por defecto. |
| hold_duration | Integer (ms) | 1000 | Cuánto hay que sostener en modo hold. |
Accesibilidad
- Es un <dialog role="alertdialog"> modal con título y descripción enlazados.
- Lo destructivo empieza con el foco en Cancelar; lo normal, en aceptar.
- Mantener presionado funciona con teclado (Espacio o Enter sostenidos) y se describe con "Mantén presionado para confirmar".
- Un clic suelto en "mantener" no acepta: recuerda la instrucción. Con movimiento reducido el relleno avanza sin animaciones extra y el tiempo se mantiene.
- Al cerrar, el foco regresa al botón que la abrió.