Files
outline/shared/editor/queries/table.ts
Tom Moor da19054555 Table improvements (#6958)
* Header toggling, resizable columns

* Allow all blocks in table cells, disable column resizing in read-only

* Fixed dynamic scroll shadows

* Refactor, scroll styling

* fix scrolling, tweaks

* fix: Table layout lost on sort

* fix: Caching of grip decorators

* refactor

* stash

* fix first render shadows

* stash

* First add column grip, styles

* Just add column/row click handlers left

* fix: isTableSelected for single cell table

* Refactor mousedown handlers

* fix: 'Add row before' command missing on first row

* fix overflow on rhs

* fix: Error clicking column grip when menu is open

* Hide table controls when printing

* Restore table header background

* fix: Header behavior when adding columns and rows at the edges

* Tweak header styling

* fix: Serialize and parsing of column attributes when copy/pasting
fix: Column width is lost when changing column alignment
2024-05-31 14:52:39 -07:00

134 lines
3.2 KiB
TypeScript

import { EditorState } from "prosemirror-state";
import {
CellSelection,
TableRect,
isInTable,
selectedRect,
} from "prosemirror-tables";
export function getColumnIndex(state: EditorState): number | undefined {
if (state.selection instanceof CellSelection) {
if (state.selection.isColSelection()) {
const rect = selectedRect(state);
return rect.left;
}
}
return undefined;
}
export function getRowIndex(state: EditorState): number | undefined {
if (state.selection instanceof CellSelection) {
if (state.selection.isRowSelection()) {
const rect = selectedRect(state);
return rect.top;
}
}
return undefined;
}
export function getCellsInColumn(index: number) {
return (state: EditorState): number[] => {
if (!isInTable(state)) {
return [];
}
const rect = selectedRect(state);
const cells = [];
for (let i = index; i < rect.map.map.length; i += rect.map.width) {
const cell = rect.tableStart + rect.map.map[i];
cells.push(cell);
}
return cells;
};
}
export function getCellsInRow(index: number) {
return (state: EditorState): number[] => {
if (!isInTable(state)) {
return [];
}
const rect = selectedRect(state);
const cells = [];
for (let i = 0; i < rect.map.width; i += 1) {
const cell = rect.tableStart + rect.map.map[index * rect.map.width + i];
cells.push(cell);
}
return cells;
};
}
export function isColumnSelected(index: number) {
return (state: EditorState): boolean => {
if (state.selection instanceof CellSelection) {
if (state.selection.isColSelection()) {
const rect = selectedRect(state);
return rect.left <= index && rect.right > index;
}
}
return false;
};
}
/**
* Check if the header is enabled for the given type and table rect
*
* @param state The editor state
* @param type The type of header to check
* @param rect The table rect
* @returns Boolean indicating if the header is enabled
*/
export function isHeaderEnabled(
state: EditorState,
type: "row" | "column",
rect: TableRect
): boolean {
// Get cell positions for first row or first column
const cellPositions = rect.map.cellsInRect({
left: 0,
top: 0,
right: type === "row" ? rect.map.width : 1,
bottom: type === "column" ? rect.map.height : 1,
});
for (let i = 0; i < cellPositions.length; i++) {
const cell = rect.table.nodeAt(cellPositions[i]);
if (cell && cell.type !== state.schema.nodes.th) {
return false;
}
}
return true;
}
export function isRowSelected(index: number) {
return (state: EditorState): boolean => {
if (state.selection instanceof CellSelection) {
if (state.selection.isRowSelection()) {
const rect = selectedRect(state);
return rect.top <= index && rect.bottom > index;
}
}
return false;
};
}
export function isTableSelected(state: EditorState): boolean {
const rect = selectedRect(state);
return (
rect.top === 0 &&
rect.left === 0 &&
rect.bottom === rect.map.height &&
rect.right === rect.map.width &&
!state.selection.empty &&
state.selection instanceof CellSelection
);
}