Full document, spreadsheet, slideshow, and diagram tooling
1/**
2 * Table Toolbar
3 *
4 * Floating toolbar that appears when the cursor is in a table,
5 * providing commands for row/column manipulation, cell merging,
6 * header toggling, and cell background color.
7 */
8import type { TableCommand, TableCommandMap, CellAttrs, TooltipPosition } from './types.js';
9
10/**
11 * Command definitions for all table operations.
12 * Each maps to a TipTap table extension command.
13 */
14export const TABLE_COMMANDS: TableCommandMap = {
15 addRowBefore: {
16 label: 'Add row above',
17 icon: '↑',
18 command: 'addRowBefore',
19 },
20 addRowAfter: {
21 label: 'Add row below',
22 icon: '↓',
23 command: 'addRowAfter',
24 },
25 addColumnBefore: {
26 label: 'Add column left',
27 icon: '←',
28 command: 'addColumnBefore',
29 },
30 addColumnAfter: {
31 label: 'Add column right',
32 icon: '→',
33 command: 'addColumnAfter',
34 },
35 deleteRow: {
36 label: 'Delete row',
37 icon: '✕',
38 command: 'deleteRow',
39 },
40 deleteColumn: {
41 label: 'Delete column',
42 icon: '✕',
43 command: 'deleteColumn',
44 },
45 mergeCells: {
46 label: 'Merge cells',
47 icon: '⧉',
48 command: 'mergeCells',
49 },
50 splitCell: {
51 label: 'Split cell',
52 icon: '⧈',
53 command: 'splitCell',
54 },
55 toggleHeaderRow: {
56 label: 'Toggle header row',
57 icon: '𝐓',
58 command: 'toggleHeaderRow',
59 },
60};
61
62/**
63 * Manages visibility and position of the floating table toolbar.
64 */
65export class TableToolbarState {
66 visible: boolean;
67 position: TooltipPosition | null;
68
69 constructor() {
70 this.visible = false;
71 this.position = null;
72 }
73
74 show(pos: TooltipPosition): void {
75 this.visible = true;
76 this.position = { ...pos };
77 }
78
79 hide(): void {
80 this.visible = false;
81 this.position = null;
82 }
83
84 updatePosition(pos: TooltipPosition): void {
85 this.position = { ...pos };
86 }
87}
88
89/**
90 * Parse cell background color from TipTap cell attributes.
91 */
92export function parseCellColor(attrs: CellAttrs | null | undefined): string | null {
93 if (!attrs) return null;
94 if (attrs.background) return attrs.background;
95 if (attrs.backgroundColor) return attrs.backgroundColor;
96 return null;
97}
98
99/**
100 * Normalize a color string to lowercase hex.
101 * Handles 3-digit shorthand (#f00 -> #ff0000).
102 */
103export function normalizeCellColor(color: string | null | undefined): string | null {
104 if (!color) return null;
105 const trimmed = color.trim();
106 if (!trimmed) return null;
107
108 let hex = trimmed.toLowerCase();
109
110 // Expand 3-digit hex to 6-digit
111 if (/^#[0-9a-f]{3}$/.test(hex)) {
112 hex = '#' + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
113 }
114
115 return hex;
116}