Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions src/extensions/markdown/Table/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import type {Node, ResolvedPos} from '#pm/model';
import {type Command, type EditorState, TextSelection, type Transaction} from '#pm/state';
import type {EditorView} from '#pm/view';
import {pType} from 'src/extensions/base/specs';
import {findParentTableFromPos} from 'src/table-utils';
import {getChildByIndex} from 'src/utils/node-children';

import {
findParentBodyOnPos,
findParentCellOnPos,
findParentHeadOnPos,
findParentRowOnPos,
} from './helpers';

const moveToNextRow = (
$pos: ResolvedPos,
state: EditorState,
dispatch: EditorView['dispatch'] | undefined,
) => {
const tableRes = findParentTableFromPos($pos);
if (!tableRes) return false;

const tableHeadResult = findParentHeadOnPos($pos);
const tableBodyResult = findParentBodyOnPos($pos);
if (!tableHeadResult && !tableBodyResult) return false;

const tableRowResult = findParentRowOnPos($pos);
const tableCellResult = findParentCellOnPos($pos);
if (!tableRowResult || !tableCellResult) return false;

const cellIndex = $pos.index(tableCellResult.depth - 1);
const rowIndex = $pos.index(tableRowResult.depth - 1);

if (!dispatch) return true;

const goToNextRow = (tr: Transaction, nextRow: Node, nextRowPos: number) => {
const cell = getChildByIndex(nextRow, cellIndex);
if (cell) {
const cellPos = nextRowPos + 1 + cell.offset;
tr.setSelection(TextSelection.create(tr.doc, cellPos + cell.node.nodeSize - 1));
} else {
// fallback if cell not found
const $rowEnd = tr.doc.resolve(nextRowPos + nextRow.nodeSize - 1);
tr.setSelection(TextSelection.near($rowEnd, -1));
}
};

const exitTable = (tr: Transaction) => {
const afterTablePos = tableRes.pos + tableRes.node.nodeSize;
tr.insert(afterTablePos, pType(state.schema).create());
tr.setSelection(TextSelection.create(tr.doc, afterTablePos + 1));
};

const tr = state.tr;

if (tableHeadResult) {
// in table head
const tableBody = getChildByIndex(tableRes.node, tableRes.node.childCount - 1);
if (tableBody && tableBody.node !== tableHeadResult.node && tableBody.node.firstChild) {
goToNextRow(tr, tableBody.node.firstChild, tableRes.start + tableBody.offset + 1);
} else {
// no table body or it is empty
exitTable(tr);
}
} else {
// in table body
const nextRow = getChildByIndex(tableBodyResult!.node, rowIndex + 1);
if (nextRow) {
goToNextRow(tr, nextRow.node, tableBodyResult!.start + nextRow.offset);
} else {
// pos in last row
exitTable(tr);
}
}

dispatch(tr.scrollIntoView());

return true;
};

export const moveToNextRowCommand: Command = (state, dispatch) => {
return (
moveToNextRow(state.selection.$head, state, dispatch) ||
moveToNextRow(state.selection.$anchor, state, dispatch)
);
};
26 changes: 22 additions & 4 deletions src/extensions/markdown/Table/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type {Node, Schema} from 'prosemirror-model';
import type {EditorState} from 'prosemirror-state';
import type {Node, ResolvedPos, Schema} from '#pm/model';
import type {EditorState} from '#pm/state';
import {
findChildren,
findChildrenByType,
findParentNodeOfType,
findParentNodeOfTypeClosestToPos,
hasParentNodeOfType,
// @ts-ignore // TODO: fix cjs build
} from 'prosemirror-utils';
} from '#pm/utils';

import {TableNode} from './const';

Expand All @@ -16,18 +16,36 @@ export const isIntoTable = (state: EditorState) =>
export const findParentTable = (state: EditorState) =>
findParentNodeOfType(state.schema.nodes[TableNode.Table])(state.selection);

export const findParentTableOnPosOnPos = ($pos: ResolvedPos) =>
findParentNodeOfTypeClosestToPos($pos, $pos.doc.type.schema.nodes[TableNode.Table]);

export const findParentHeadOnPos = ($pos: ResolvedPos) =>
findParentNodeOfTypeClosestToPos($pos, $pos.doc.type.schema.nodes[TableNode.Head]);

export const findParentBody = (state: EditorState) =>
findParentNodeOfType(state.schema.nodes[TableNode.Body])(state.selection);

export const findParentBodyOnPos = ($pos: ResolvedPos) =>
findParentNodeOfTypeClosestToPos($pos, $pos.doc.type.schema.nodes[TableNode.Body]);

export const findParentRow = (state: EditorState) =>
findParentNodeOfType(state.schema.nodes[TableNode.Row])(state.selection);

export const findParentRowOnPos = ($pos: ResolvedPos) =>
findParentNodeOfTypeClosestToPos($pos, $pos.doc.type.schema.nodes[TableNode.Row]);

export const findParentCell = (state: EditorState) =>
findParentNodeOfType([
state.schema.nodes[TableNode.HeaderCell],
state.schema.nodes[TableNode.DataCell],
])(state.selection);

export const findParentCellOnPos = ($pos: ResolvedPos) =>
findParentNodeOfTypeClosestToPos($pos, [
$pos.doc.type.schema.nodes[TableNode.HeaderCell],
$pos.doc.type.schema.nodes[TableNode.DataCell],
]);

export const findTableRows = (table: Node, schema: Schema) =>
findChildrenByType(table, schema.nodes[TableNode.Row]);

Expand Down
7 changes: 5 additions & 2 deletions src/extensions/markdown/Table/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type {Action, ExtensionAuto} from '../../../core';
import {goToNextCell} from '../../../table-utils';
import type {Action, ExtensionAuto} from '#core';
import {goToNextCell} from 'src/table-utils';

import {TableSpecs} from './TableSpecs';
import {createTableAction, deleteTableAction} from './actions/tableActions';
import * as TableActions from './actions/tableActions';
import {moveToNextRowCommand} from './commands';
import * as TableHelpers from './helpers';
import {tableCellContextPlugin} from './plugins/TableCellContextPlugin';

Expand All @@ -16,6 +17,8 @@ export const Table: ExtensionAuto = (builder) => {
builder.addKeymap(() => ({
Tab: goToNextCell('next'),
'Shift-Tab': goToNextCell('prev'),
Enter: moveToNextRowCommand,
'Shift-Enter': moveToNextRowCommand,
}));

builder.addAction('createTable', createTableAction);
Expand Down
Loading