import { ProsemirrorNode, ResolvedPos, Schema } from 'prosemirror-model'; import { Selection, Transaction, NodeSelection } from 'prosemirror-state'; import { addParagraph } from '@/helper/manipulation'; import { TableOffsetMap } from '../helper/tableOffsetMap'; import { Direction } from '../nodes/table'; export type CellPosition = [rowIdx: number, colIdx: number]; type CellOffsetFn = ([rowIdx, colIdx]: CellPosition, map: TableOffsetMap) => number | null; type CellOffsetFnMap = { [key in Direction]: CellOffsetFn; }; const cellOffsetFnMap: CellOffsetFnMap = { left: getLeftCellOffset, right: getRightCellOffset, up: getUpCellOffset, down: getDownCellOffset, }; function isInFirstListItem( pos: ResolvedPos, doc: ProsemirrorNode, [paraDepth, listDepth]: number[] ) { const listItemNode = doc.resolve(pos.before(paraDepth - 1)); return listDepth === paraDepth && !listItemNode.nodeBefore; } function isInLastListItem(pos: ResolvedPos) { let { depth } = pos; let parentNode; while (depth) { parentNode = pos.node(depth); if (parentNode.type.name === 'tableBodyCell') { break; } if (parentNode.type.name === 'listItem') { const grandParent = pos.node(depth - 1); const lastListItem = grandParent.lastChild === parentNode; const hasChildren = parentNode.lastChild?.type.name !== 'paragraph'; if (!lastListItem) { return false; } return !hasChildren; } depth -= 1; } return false; } function canMoveToBeforeCell( direction: Direction, [paraDepth, listDepth, curDepth]: number[], from: ResolvedPos, doc: ProsemirrorNode, inList: boolean ) { if (direction === Direction.LEFT || direction === Direction.UP) { if (inList && !isInFirstListItem(from, doc, [paraDepth, listDepth])) { return false; } const endOffset = from.before(curDepth); const { nodeBefore } = doc.resolve(endOffset); if (nodeBefore) { return false; } } return true; } function canMoveToAfterCell( direction: Direction, curDepth: number, from: ResolvedPos, doc: ProsemirrorNode, inList: boolean ) { if (direction === Direction.RIGHT || direction === Direction.DOWN) { if (inList && !isInLastListItem(from)) { return false; } const endOffset = from.after(curDepth); const { nodeAfter } = doc.resolve(endOffset); if (nodeAfter) { return false; } } return true; } export function canMoveBetweenCells( direction: Direction, [cellDepth, paraDepth]: number[], from: ResolvedPos, doc: ProsemirrorNode ) { const listDepth = cellDepth + 3; // 3 is position of