CreaRack-SL

TableBubbleMenu — Menú flotante de tabla en el Cuaderno

Descripción

TableBubbleMenu es un componente React que muestra un menú flotante contextual (bubble menu) encima de cualquier tabla cuando el cursor del editor está posicionado dentro de ella. Sigue el patrón “esquina superior” popularizado por Notion, Confluence y Coda.

El componente se monta directamente en NoteEditor.tsx y delega el posicionamiento al BubbleMenu de @tiptap/react/menus, usando @floating-ui/dom internamente.

Ubicación en el código

ArtefactoRuta
Componentesrc/components/notebook/TableBubbleMenu.tsx
Estilossrc/styles/tools.css (clases .cuaderno-table-menu*)
Punto de montajesrc/components/notebook/NoteEditor.tsx

Props

PropTipoDescripción
editorEditor | nullInstancia del editor TipTap. Si es null el componente no renderiza nada.

Comportamiento

  • Trigger: shouldShow evalúa editor.isActive('table'). Solo aparece cuando el cursor está dentro de un nodo table de TipTap/ProseMirror.
  • Posicionamiento: placement: 'top-start' con offset de 8 px (flotante encima de la tabla, alineado a la izquierda).
  • pluginKey: "tableBubbleMenu" — evita conflictos con otros BubbleMenus presentes en el editor (ej. formateo de texto).

Botones expuestos

LabelComando TipTapAcción
+ fila ↑addRowBefore()Inserta fila encima de la celda actual
+ fila ↓addRowAfter()Inserta fila debajo
+ col ←addColumnBefore()Inserta columna a la izquierda
+ col →addColumnAfter()Inserta columna a la derecha
− filadeleteRow()Elimina fila actual
− coldeleteColumn()Elimina columna actual
⇈ headertoggleHeaderRow()Alterna la fila de cabecera <th>
⊟mergeOrSplit()Fusiona celdas seleccionadas o divide celda fusionada
✕ Eliminar tabladeleteTable()Elimina la tabla entera (con confirm() de seguridad)

Patrón onMouseDown + preventDefault

Todos los botones usan onMouseDown={(e) => e.preventDefault()} para evitar que el editor pierda el foco antes de ejecutar el comando. Sin esto, el cursor se mueve y isActive('table') devuelve false en el momento del onClick.

Estilos CSS relevantes

/* Contenedor */
.cuaderno-table-menu { display: flex; gap: 2px; padding: 4px; background: var(--bg-raised); border-radius: 8px; }

/* Botones */
.cuaderno-table-menu button { padding: 4px 8px; border-radius: 5px; color: var(--fg-muted); }

/* Separadores visuales */
.cuaderno-table-menu-sep { width: 1px; height: 18px; background: var(--border); }

/* Botón destructivo */
.cuaderno-table-menu-danger { color: var(--danger) !important; }

Dependencias clave

  • @tiptap/extension-bubble-menu v3.23.1 (bump desde 3.22.5 en este commit — la dependencia pasa de optional a directa en el lockfile).
  • @floating-ui/dom (transitiva, gestionada por TipTap).
  • Extensiones TipTap de tablas: @tiptap/extension-table, @tiptap/extension-table-row, @tiptap/extension-table-cell, @tiptap/extension-table-header.

Notas de mantenimiento

  • Si se añaden más BubbleMenus al editor (ej. para imágenes o código), cada uno debe tener un pluginKey único.
  • La clase .cuaderno-table-menu-danger usa !important para superar la especificidad del selector de botones base — revisar si la arquitectura CSS del cuaderno crece.
  • El confirm() nativo de bloqueo síncrono puede reemplazarse por un modal personalizado si se requiere un UX más refinado.

Véase también

  • [[feature—cuaderno—editor-rich-text]]
  • [[workspace—que-es-workspace]]
  • [[crearack—conceptos—interfaz-general]]