/** * Table Toolbar * * Floating toolbar that appears when the cursor is in a table, * providing commands for row/column manipulation, cell merging, * header toggling, and cell background color. */ import type { TableCommand, TableCommandMap, CellAttrs, TooltipPosition } from './types.js'; /** * Command definitions for all table operations. * Each maps to a TipTap table extension command. */ export const TABLE_COMMANDS: TableCommandMap = { addRowBefore: { label: 'Add row above', icon: '↑', command: 'addRowBefore', }, addRowAfter: { label: 'Add row below', icon: '↓', command: 'addRowAfter', }, addColumnBefore: { label: 'Add column left', icon: '←', command: 'addColumnBefore', }, addColumnAfter: { label: 'Add column right', icon: '→', command: 'addColumnAfter', }, deleteRow: { label: 'Delete row', icon: '✕', command: 'deleteRow', }, deleteColumn: { label: 'Delete column', icon: '✕', command: 'deleteColumn', }, mergeCells: { label: 'Merge cells', icon: '⧉', command: 'mergeCells', }, splitCell: { label: 'Split cell', icon: '⧈', command: 'splitCell', }, toggleHeaderRow: { label: 'Toggle header row', icon: '𝐓', command: 'toggleHeaderRow', }, }; /** * Manages visibility and position of the floating table toolbar. */ export class TableToolbarState { visible: boolean; position: TooltipPosition | null; constructor() { this.visible = false; this.position = null; } show(pos: TooltipPosition): void { this.visible = true; this.position = { ...pos }; } hide(): void { this.visible = false; this.position = null; } updatePosition(pos: TooltipPosition): void { this.position = { ...pos }; } } /** * Parse cell background color from TipTap cell attributes. */ export function parseCellColor(attrs: CellAttrs | null | undefined): string | null { if (!attrs) return null; if (attrs.background) return attrs.background; if (attrs.backgroundColor) return attrs.backgroundColor; return null; } /** * Normalize a color string to lowercase hex. * Handles 3-digit shorthand (#f00 -> #ff0000). */ export function normalizeCellColor(color: string | null | undefined): string | null { if (!color) return null; const trimmed = color.trim(); if (!trimmed) return null; let hex = trimmed.toLowerCase(); // Expand 3-digit hex to 6-digit if (/^#[0-9a-f]{3}$/.test(hex)) { hex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3]; } return hex; }