UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

464 lines (460 loc) 21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shiftArrowUpFromTable = exports.selectRows = exports.selectColumns = exports.modASelectTable = exports.arrowRightFromTable = exports.arrowLeftFromTable = void 0; var _messages = require("@atlaskit/editor-common/messages"); var _selection = require("@atlaskit/editor-common/selection"); var _state = require("@atlaskit/editor-prosemirror/state"); var _cellSelection = require("@atlaskit/editor-tables/cell-selection"); var _tableMap = require("@atlaskit/editor-tables/table-map"); var _utils = require("@atlaskit/editor-tables/utils"); var _toolbar = require("../../ui/toolbar"); var _pluginFactory = require("../plugin-factory"); var _misc = require("./misc"); var TableSelectionDirection = /*#__PURE__*/function (TableSelectionDirection) { TableSelectionDirection["TopToBottom"] = "TopToBottom"; TableSelectionDirection["BottomToTop"] = "BottomToTop"; return TableSelectionDirection; }(TableSelectionDirection || {}); var arrowLeftFromTable = exports.arrowLeftFromTable = function arrowLeftFromTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var selection = state.selection; if (selection instanceof _cellSelection.CellSelection) { return arrowLeftFromCellSelection(editorSelectionAPI)(selection)(state, dispatch); } else if (selection instanceof _selection.GapCursorSelection) { return arrowLeftFromGapCursor(editorSelectionAPI)(selection)(state, dispatch); } else if (selection instanceof _state.TextSelection) { return arrowLeftFromText(editorSelectionAPI)(selection)(state, dispatch); } return false; }; }; }; var arrowRightFromTable = exports.arrowRightFromTable = function arrowRightFromTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var selection = state.selection; if (selection instanceof _cellSelection.CellSelection) { return arrowRightFromCellSelection(editorSelectionAPI)(selection)(state, dispatch); } else if (selection instanceof _selection.GapCursorSelection) { return arrowRightFromGapCursor(editorSelectionAPI)(selection)(state, dispatch); } else if (selection instanceof _state.TextSelection) { return arrowRightFromText(editorSelectionAPI)(selection)(state, dispatch); } return false; }; }; }; var arrowLeftFromCellSelection = function arrowLeftFromCellSelection(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { if ((0, _utils.isTableSelected)(state.selection) && editorSelectionAPI) { var selectionState = editorSelectionAPI.sharedState.currentState() || {}; if ((selectionState === null || selectionState === void 0 ? void 0 : selectionState.selectionRelativeToNode) === _selection.RelativeSelectionPos.Start) { // we have full table cell selection and want to set gap cursor selection before table return setGapCursorBeforeTable(editorSelectionAPI)()(state, dispatch); } else if ((selectionState === null || selectionState === void 0 ? void 0 : selectionState.selectionRelativeToNode) === _selection.RelativeSelectionPos.End) { // we have full table cell selection and want to set selection at end of last cell return setSelectionAtEndOfLastCell(editorSelectionAPI)(selection)(state, dispatch); } else if ((selectionState === null || selectionState === void 0 ? void 0 : selectionState.selectionRelativeToNode) === undefined) { // we have full table cell selection and want to set selection at start of first cell return setSelectionAtStartOfFirstCell(editorSelectionAPI)(selection, _selection.RelativeSelectionPos.Before)(state, dispatch); } } return false; }; }; }; var arrowRightFromCellSelection = function arrowRightFromCellSelection(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { if ((0, _utils.isTableSelected)(state.selection) && editorSelectionAPI) { var _ref = editorSelectionAPI.sharedState.currentState() || {}, selectionRelativeToNode = _ref.selectionRelativeToNode; if (selectionRelativeToNode === _selection.RelativeSelectionPos.Start) { // we have full table cell selection and want to set selection at start of first cell return setSelectionAtStartOfFirstCell(editorSelectionAPI)(selection)(state, dispatch); } else if (selectionRelativeToNode === _selection.RelativeSelectionPos.End || selectionRelativeToNode === undefined) { // we have full table cell selection and want to set gap cursor selection after table return setGapCursorAfterTable(editorSelectionAPI)()(state, dispatch); } } return false; }; }; }; var selectColumns = exports.selectColumns = function selectColumns(editorSelectionAPI, ariaNotify, getIntl) { return function () { var triggeredByKeyboard = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return function (state, dispatch) { var selection = state.selection; var table = (0, _utils.findTable)(selection); var rect = (0, _utils.selectedRect)(state); if (table && (0, _utils.isRowSelected)(rect.top)(selection)) { return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } if (table && rect) { var selectColumnCommand = (0, _misc.selectColumn)(rect.left, undefined, triggeredByKeyboard)(state, dispatch); var map = _tableMap.TableMap.get(table.node); if (ariaNotify && getIntl) { ariaNotify(getIntl().formatMessage(_messages.tableMessages.columnSelected, { index: rect.left + 1, total: map.width }), { priority: 'important' }); } return selectColumnCommand; } return false; }; }; }; var selectRows = exports.selectRows = function selectRows(editorSelectionAPI, ariaNotify, getIntl) { return function () { var triggeredByKeyboard = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return function (state, dispatch) { var selection = state.selection; var table = (0, _utils.findTable)(selection); var rect = (0, _utils.selectedRect)(state); if (table && (0, _utils.isColumnSelected)(rect.left)(selection)) { return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } if (table && rect) { var selectRowCommand = (0, _misc.selectRow)(rect.top, undefined, triggeredByKeyboard)(state, dispatch); var map = _tableMap.TableMap.get(table.node); if (ariaNotify && getIntl) { ariaNotify(getIntl().formatMessage(_messages.tableMessages.rowSelected, { index: rect.top + 1, total: map.height }), { priority: 'important' }); } return selectRowCommand; } return false; }; }; }; var arrowLeftFromGapCursor = function arrowLeftFromGapCursor(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { var doc = state.doc; var $from = selection.$from, from = selection.from, side = selection.side; if (side === _selection.Side.RIGHT) { if ($from.nodeBefore && $from.nodeBefore.type.name === 'table') { // we have a gap cursor after a table node and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: $from.nodeBefore, startPos: doc.resolve(from - 1).start($from.depth + 1), dir: TableSelectionDirection.TopToBottom })(state, dispatch); } } else if (side === _selection.Side.LEFT) { var table = (0, _utils.findTable)(selection); if (table && isSelectionAtStartOfTable($from, selection) && editorSelectionAPI) { var selectionState = editorSelectionAPI.sharedState.currentState() || {}; if ((selectionState === null || selectionState === void 0 ? void 0 : selectionState.selectionRelativeToNode) === _selection.RelativeSelectionPos.Before) { // we have a gap cursor at start of first table cell and want to set a gap cursor selection before table return setGapCursorBeforeTable(editorSelectionAPI)()(state, dispatch); } else { // we have a gap cursor at start of first table cell and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } } } return false; }; }; }; var arrowRightFromGapCursor = function arrowRightFromGapCursor(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { var $from = selection.$from, from = selection.from, $to = selection.$to, side = selection.side; if (side === _selection.Side.LEFT) { if ($from.nodeAfter && $from.nodeAfter.type.name === 'table') { // we have a gap cursor before a table node and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: $from.nodeAfter, startPos: from + 1, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } } else if (side === _selection.Side.RIGHT) { var table = (0, _utils.findTable)(selection); if (table && isSelectionAtEndOfTable($to, selection)) { // we have a gap cursor at end of last table cell and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.TopToBottom })(state, dispatch); } } return false; }; }; }; var arrowLeftFromText = function arrowLeftFromText(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { var table = (0, _utils.findTable)(selection); if (table) { var $from = selection.$from; var columResizePluginState = (0, _pluginFactory.getPluginState)(state) || {}; var isColumnResizing = Boolean(columResizePluginState === null || columResizePluginState === void 0 ? void 0 : columResizePluginState.isKeyboardResize); if (isSelectionAtStartOfTable($from, selection) && $from.parent.type.name === 'paragraph' && $from.depth === table.depth + 3 && // + 3 for: row, cell & paragraph nodes editorSelectionAPI && !isColumnResizing) { var selectionState = editorSelectionAPI.sharedState.currentState() || {}; if ((selectionState === null || selectionState === void 0 ? void 0 : selectionState.selectionRelativeToNode) === _selection.RelativeSelectionPos.Before) { // we have a text selection at start of first table cell, directly inside a top level paragraph, // and want to set gap cursor selection before table return setGapCursorBeforeTable(editorSelectionAPI)()(state, dispatch); } else { // we have a text selection at start of first table cell, directly inside a top level paragraph, // and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } } } return false; }; }; }; var arrowRightFromText = function arrowRightFromText(editorSelectionAPI) { return function (selection) { return function (state, dispatch) { var table = (0, _utils.findTable)(selection); if (table) { var $to = selection.$to; var columResizePluginState = (0, _pluginFactory.getPluginState)(state) || {}; var isColumnResizing = Boolean(columResizePluginState === null || columResizePluginState === void 0 ? void 0 : columResizePluginState.isKeyboardResize); if (isSelectionAtEndOfTable($to, selection) && $to.parent.type.name === 'paragraph' && $to.depth === table.depth + 3 && // + 3 for: row, cell & paragraph nodes !isColumnResizing) { // we have a text selection at end of last table cell, directly inside a top level paragraph, // and want to set a full table cell selection return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.TopToBottom })(state, dispatch); } } return false; }; }; }; /** * Sets a cell selection over all the cells in the table node * We use this instead of selectTable from prosemirror-utils so we can control which * cell is the anchor and which is the head, and also so we can set the relative selection * pos in the selection plugin */ var selectFullTable = function selectFullTable(editorSelectionAPI) { return function (_ref2) { var node = _ref2.node, startPos = _ref2.startPos, dir = _ref2.dir; return function (state, dispatch) { var doc = state.doc; var _TableMap$get = _tableMap.TableMap.get(node), map = _TableMap$get.map; var $firstCell = doc.resolve(startPos + map[0]); var $lastCell = doc.resolve(startPos + map[map.length - 1]); var fullTableSelection; var selectionRelativeToNode; if (dir === TableSelectionDirection.TopToBottom) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any fullTableSelection = new _cellSelection.CellSelection($firstCell, $lastCell); selectionRelativeToNode = _selection.RelativeSelectionPos.End; } else { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any fullTableSelection = new _cellSelection.CellSelection($lastCell, $firstCell); selectionRelativeToNode = _selection.RelativeSelectionPos.Start; } if (editorSelectionAPI) { var tr = editorSelectionAPI.actions.selectNearNode({ selectionRelativeToNode: selectionRelativeToNode, selection: fullTableSelection })(state); if (dispatch) { dispatch(tr); return true; } } return false; }; }; }; var setSelectionAtStartOfFirstCell = function setSelectionAtStartOfFirstCell(editorSelectionAPI) { return function (selection, selectionRelativeToNode) { return function (state, dispatch) { var $anchorCell = selection.$anchorCell, $headCell = selection.$headCell; var $firstCell = $anchorCell.pos < $headCell.pos ? $anchorCell : $headCell; var $firstPosInsideCell = state.doc.resolve($firstCell.pos + 1); // check if first pos should have a gap cursor, otherwise find closest text selection var selectionAtStartOfCell = _selection.GapCursorSelection.valid($firstPosInsideCell) ? new _selection.GapCursorSelection($firstPosInsideCell, _selection.Side.LEFT) : _state.Selection.findFrom($firstPosInsideCell, 1); if (editorSelectionAPI) { var tr = editorSelectionAPI.actions.selectNearNode({ selectionRelativeToNode: selectionRelativeToNode, selection: selectionAtStartOfCell })(state); if (dispatch) { dispatch(tr); return true; } } return false; }; }; }; var setSelectionAtEndOfLastCell = function setSelectionAtEndOfLastCell(editorSelectionAPI) { return function (selection, selectionRelativeToNode) { return function (state, dispatch) { var $anchorCell = selection.$anchorCell, $headCell = selection.$headCell; var $lastCell = $anchorCell.pos > $headCell.pos ? $anchorCell : $headCell; var lastPosInsideCell = $lastCell.pos + ($lastCell.nodeAfter ? $lastCell.nodeAfter.content.size : 0) + 1; var $lastPosInsideCell = state.doc.resolve(lastPosInsideCell); // check if last pos should have a gap cursor, otherwise find closest text selection var selectionAtEndOfCell = _selection.GapCursorSelection.valid($lastPosInsideCell) ? new _selection.GapCursorSelection($lastPosInsideCell, _selection.Side.RIGHT) : _state.Selection.findFrom($lastPosInsideCell, -1); if (editorSelectionAPI) { var tr = editorSelectionAPI.actions.selectNearNode({ selectionRelativeToNode: selectionRelativeToNode, selection: selectionAtEndOfCell })(state); if (dispatch) { dispatch(tr); return true; } } return false; }; }; }; var setGapCursorBeforeTable = function setGapCursorBeforeTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var table = (0, _utils.findTable)(state.selection); if (table) { var $beforeTablePos = state.doc.resolve(table.pos); if (_selection.GapCursorSelection.valid($beforeTablePos)) { var selectionBeforeTable = new _selection.GapCursorSelection($beforeTablePos, _selection.Side.LEFT); if (editorSelectionAPI) { var tr = editorSelectionAPI.actions.selectNearNode({ selectionRelativeToNode: undefined, selection: selectionBeforeTable })(state); if (dispatch) { dispatch(tr); return true; } } } } return false; }; }; }; var setGapCursorAfterTable = function setGapCursorAfterTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var table = (0, _utils.findTable)(state.selection); if (table) { var $afterTablePos = state.doc.resolve(table.pos + table.node.nodeSize); if (_selection.GapCursorSelection.valid($afterTablePos)) { var selectionAfterTable = new _selection.GapCursorSelection($afterTablePos, _selection.Side.RIGHT); if (editorSelectionAPI) { var tr = editorSelectionAPI.actions.selectNearNode({ selectionRelativeToNode: undefined, selection: selectionAfterTable })(state); if (dispatch) { dispatch(tr); return true; } } return false; } } return false; }; }; }; var isSelectionAtStartOfTable = function isSelectionAtStartOfTable($pos, selection) { var _findTable; return (0, _selection.isSelectionAtStartOfNode)($pos, (_findTable = (0, _utils.findTable)(selection)) === null || _findTable === void 0 ? void 0 : _findTable.node); }; var isSelectionAtEndOfTable = function isSelectionAtEndOfTable($pos, selection) { var _findTable2; return (0, _selection.isSelectionAtEndOfNode)($pos, (_findTable2 = (0, _utils.findTable)(selection)) === null || _findTable2 === void 0 ? void 0 : _findTable2.node); }; var shiftArrowUpFromTable = exports.shiftArrowUpFromTable = function shiftArrowUpFromTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var selection = state.selection; var table = (0, _utils.findTable)(selection); var selectionRect = (0, _toolbar.getClosestSelectionRect)(state); var index = selectionRect === null || selectionRect === void 0 ? void 0 : selectionRect.top; if (table && index === 0) { return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } return false; }; }; }; var modASelectTable = exports.modASelectTable = function modASelectTable(editorSelectionAPI) { return function () { return function (state, dispatch) { var selection = state.selection; var table = (0, _utils.findTable)(selection); if (!table) { return false; } var $from = selection.$from, $to = selection.$to; var tableSelected = (0, _utils.isTableSelected)(selection); if (!tableSelected && $from.pos > table.start + 1 && $to.pos < table.start + table.node.nodeSize) { return selectFullTable(editorSelectionAPI)({ node: table.node, startPos: table.start, dir: TableSelectionDirection.BottomToTop })(state, dispatch); } return false; }; }; };