Saltar al contenido

La barra de menús

Lo primero que delata a una aplicación web disfrazada. Cómo se construye un menú nativo, qué espera cada sistema, y el menú sin el cual copiar y pegar dejan de funcionar.

Lo que cada sistema espera

La quinta fila es la que causa el fallo más desconcertante de este nivel y merece su apartado.

El menú de edición en macOS

En macOS, los atajos de copiar, pegar, cortar, deshacer y seleccionar todo funcionan porque están en el menú. El sistema los enruta a través de él, no directamente a la ventana.

Consecuencia: una aplicación de Tauri en macOS sin menú, o con un menú propio que no incluye edición, deja al usuario sin poder copiar ni pegar con el teclado — en una aplicación hecha con tecnología web, donde eso debería funcionar solo.

Y es un fallo especialmente malo porque:

  • No da ningún error. El atajo simplemente no hace nada.
  • Funciona en desarrollo, si tu configuración deja el menú por omisión.
  • Y el usuario no lo reporta como un fallo del menú, sino como «no puedo pegar», que suena a otra cosa.

La solución es incluir los elementos predefinidos de edición, que Tauri ofrece hechos:

Rust
let edicion = SubmenuBuilder::new(app, "Edición")    .undo().redo()    .separator()    .cut().copy().paste().select_all()    .build()?;

Usar los predefinidos y no entradas propias es lo correcto: traen el atajo estándar, el texto traducido al idioma del sistema, y el comportamiento que el sistema espera.

Construir la barra

Rust
let menu = MenuBuilder::new(app)    .items(&[        &SubmenuBuilder::new(app, "Archivo")            .text("nuevo", "Nuevo proyecto")            .text("abrir", "Abrir…")            .separator()            .text("guardar", "Guardar")            .build()?,        &edicion,        &SubmenuBuilder::new(app, "Ayuda").text("docs", "Documentación").build()?,    ])    .build()?;app.set_menu(menu)?;app.on_menu_event(|app, ev| match ev.id().as_ref() {    "nuevo" => { /* … */ }    "abrir" => { /* … */ }    _ => {}});

Tres detalles:

  • Los identificadores son cadenas, y conviene que sean constantes de un enumerado en vez de literales sueltos — el mismo argumento del nivel 47.1.
  • Los puntos suspensivos en «Abrir…» son una convención real: significan que la acción abre un diálogo en vez de hacer algo directamente. Los usuarios lo leen aunque no sepan que lo leen.
  • Y el manejador vive en el core, así que puede hacer el trabajo o emitir un evento al frontend. Ver el nivel 49.3.

Conectar el menú con el estado

Lo que separa un menú decorativo de uno útil: las entradas se activan y desactivan según lo que se pueda hacer.

  • «Guardar» desactivado si no hay cambios.
  • «Deshacer» desactivado si no hay nada que deshacer.
  • «Cerrar proyecto» desactivado si no hay ninguno abierto.

Un menú donde todo está siempre activo obliga al usuario a probar para averiguar qué se puede hacer, y produce mensajes de error que no deberían existir. Mantener el estado sincronizado cuesta un poco y es lo que hace que un menú informe además de ejecutar.