/** * The right-click menu on a table. * * The toolbar carries the same commands, but reaching them means leaving the * cell you are working in, finding the button and reading a list — for shaping * a table, where the target is the cell under the pointer, that is the long way * round. This puts the commands where the cursor already is. * * Only the entries that apply are built: merge appears when several cells are * selected, split when the cell was merged, and nothing at all outside a table * so the browser's own menu stays available for ordinary text. */ /** True when the caret or selection sits inside a table cell. */ export const inTable = (editor) => !!editor?.isActive("table"); /** * Menu items for `ContextMenu`, or null when there is no table under the click. * * Returning null rather than an empty list lets the caller tell "no menu" from * "a menu with nothing in it" and fall through to the browser's own. */ export function tableMenuItems(editor) { if (!inTable(editor)) return null; const run = (fn) => () => fn(editor.chain().focus()).run(); const can = (name) => { try { return editor.can()[name](); } catch { return false; } }; const items = [ { label: "Insert row above", action: run((c) => c.addRowBefore()) }, { label: "Insert row below", action: run((c) => c.addRowAfter()) }, { label: "Insert column left", action: run((c) => c.addColumnBefore()) }, { label: "Insert column right", action: run((c) => c.addColumnAfter()) }, { divider: true }, { label: "Header row on/off", action: run((c) => c.toggleHeaderRow()) }, ]; // mergeCells and splitCell are mutually exclusive in practice: one needs a // multi-cell selection, the other a cell that was merged earlier. if (can("mergeCells")) items.push({ label: "Merge cells", action: run((c) => c.mergeCells()) }); if (can("splitCell")) items.push({ label: "Split cell", action: run((c) => c.splitCell()) }); items.push( { divider: true }, { label: "Delete row", danger: true, action: run((c) => c.deleteRow()) }, { label: "Delete column", danger: true, action: run((c) => c.deleteColumn()) }, { label: "Delete table", danger: true, action: run((c) => c.deleteTable()) } ); return items; }