UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

339 lines (337 loc) 15.3 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import React from 'react'; import { TableSortOrder as SortOrder } from '@atlaskit/custom-steps'; import { INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { addColumnAfter, addColumnBefore, addRowAfter, addRowBefore, backspace, deleteColumn, deleteRow, moveColumnLeftOld, moveColumnLeft, moveColumnRightOld, moveColumnRight, moveRowDownOld, moveRowDown, moveRowUpOld, moveRowUp, tooltip } from '@atlaskit/editor-common/keymaps'; import SortAscendingIcon from '@atlaskit/icon/core/sort-ascending'; import SortDescendingIcon from '@atlaskit/icon/core/sort-descending'; import TableCellClearIcon from '@atlaskit/icon/core/table-cell-clear'; import TableColumnAddLeftIcon from '@atlaskit/icon/core/table-column-add-left'; import TableColumnAddRightIcon from '@atlaskit/icon/core/table-column-add-right'; import TableColumnDeleteIcon from '@atlaskit/icon/core/table-column-delete'; import TableColumnMoveLeftIcon from '@atlaskit/icon/core/table-column-move-left'; import TableColumnMoveRightIcon from '@atlaskit/icon/core/table-column-move-right'; import TableColumnsDistributeIcon from '@atlaskit/icon/core/table-columns-distribute'; import TableRowAddAboveIcon from '@atlaskit/icon/core/table-row-add-above'; import TableRowAddBelowIcon from '@atlaskit/icon/core/table-row-add-below'; import TableRowDeleteIcon from '@atlaskit/icon/core/table-row-delete'; import TableRowMoveDownIcon from '@atlaskit/icon/core/table-row-move-down'; import TableRowMoveUpIcon from '@atlaskit/icon/core/table-row-move-up'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { getClosestSelectionRect } from '../../ui/toolbar'; import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, sortColumnWithAnalytics } from '../commands/commands-with-analytics'; import { moveSourceWithAnalytics } from '../drag-and-drop/commands-with-analytics'; import { getPluginState as getTablePluginState } from '../plugin-factory'; import { getNewResizeStateFromSelectedColumns } from '../table-resizing/utils/resize-state'; import { hasMergedCellsInSelection, hasMergedCellsWithColumnNextToColumnIndex, hasMergedCellsWithRowNextToRowIndex } from './merged-cells'; import { getSelectedColumnIndexes, getSelectedRowIndexes } from './selection'; export var getTargetIndex = function getTargetIndex(selectedIndexes, direction) { return Math[direction < 0 ? 'min' : 'max'].apply(Math, _toConsumableArray(selectedIndexes)) + direction; }; export var canMove = function canMove(sourceType, direction, totalItemsOfSourceTypeCount, selection, selectionRect) { if (!selectionRect) { return false; } var isRow = sourceType === 'table-row'; var selectedIndexes = isRow ? getSelectedRowIndexes(selectionRect) : getSelectedColumnIndexes(selectionRect); var targetIndex = getTargetIndex(selectedIndexes, direction); var isValidTargetIndex = targetIndex >= 0 && targetIndex < totalItemsOfSourceTypeCount; if (!isValidTargetIndex) { return false; } // We can't move column when target has merged cells with other columns // We can't move row when target has merged cells with other rows var hasMergedCellsInTarget = isRow ? hasMergedCellsWithRowNextToRowIndex(targetIndex, selection) : hasMergedCellsWithColumnNextToColumnIndex(targetIndex, selection); if (hasMergedCellsInTarget) { return false; } // We can't move if selection in the source is not a rectangle if (hasMergedCellsInSelection(selectedIndexes, isRow ? 'row' : 'column')(selection)) { return false; } return true; }; var isDistributeColumnsEnabled = function isDistributeColumnsEnabled(state) { var rect = getClosestSelectionRect(state); if (rect) { var selectedColIndexes = getSelectedColumnIndexes(rect); return selectedColIndexes.length > 1; } return false; }; var defaultSelectionRect = { left: 0, top: 0, right: 0, bottom: 0 }; export var getDragMenuConfig = function getDragMenuConfig(direction, getEditorContainerWidth, hasMergedCellsInTable, editorView, api, tableMap, index, targetCellPosition, selectionRect, editorAnalyticsAPI, isHeaderRowRequired) { var _tableMap$height, _tableMap$height2, _tableMap$width, _tableMap$width2; var isTableScalingEnabled = arguments.length > 11 && arguments[11] !== undefined ? arguments[11] : false; var isTableFixedColumnWidthsOptionEnabled = arguments.length > 12 && arguments[12] !== undefined ? arguments[12] : false; var shouldUseIncreasedScalingPercent = arguments.length > 13 && arguments[13] !== undefined ? arguments[13] : false; var ariaNotifyPlugin = arguments.length > 14 ? arguments[14] : undefined; var isCommentEditor = arguments.length > 15 && arguments[15] !== undefined ? arguments[15] : false; var isColumnSortingEnabled = arguments.length > 16 && arguments[16] !== undefined ? arguments[16] : true; var selection = editorView.state.selection; var _getTablePluginState = getTablePluginState(editorView.state), getIntl = _getTablePluginState.getIntl; var addOptions = direction === 'row' ? [{ label: 'above', offset: 0, icon: function icon() { return /*#__PURE__*/React.createElement(TableRowAddAboveIcon, { spacing: 'spacious', label: '' }); }, keymap: addRowBefore }, { label: 'below', offset: 1, icon: function icon() { return /*#__PURE__*/React.createElement(TableRowAddBelowIcon, { spacing: 'spacious', label: '' }); }, keymap: addRowAfter }] : [{ label: 'left', offset: 0, icon: function icon() { return /*#__PURE__*/React.createElement(TableColumnAddLeftIcon, { spacing: 'spacious', label: '' }); }, keymap: addColumnBefore }, { label: 'right', offset: 1, icon: function icon() { return /*#__PURE__*/React.createElement(TableColumnAddRightIcon, { spacing: 'spacious', label: '' }); }, keymap: addColumnAfter }]; var isNewKeymapExperiment = expValEquals('editor-a11y-fy26-keyboard-move-row-column', 'isEnabled', true); var moveOptions = direction === 'row' ? [{ label: 'up', icon: function icon() { return /*#__PURE__*/React.createElement(TableRowMoveUpIcon, { spacing: 'spacious', label: '' }); }, keymap: isNewKeymapExperiment ? moveRowUp : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveRowUpOld, canMove: canMove('table-row', -1, (_tableMap$height = tableMap === null || tableMap === void 0 ? void 0 : tableMap.height) !== null && _tableMap$height !== void 0 ? _tableMap$height : 0, selection, selectionRect), getOriginIndexes: getSelectedRowIndexes, getTargetIndex: function getTargetIndex(selectionRect) { return selectionRect.top - 1; } }, { label: 'down', icon: function icon() { return /*#__PURE__*/React.createElement(TableRowMoveDownIcon, { spacing: 'spacious', label: '' }); }, keymap: isNewKeymapExperiment ? moveRowDown : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveRowDownOld, canMove: canMove('table-row', 1, (_tableMap$height2 = tableMap === null || tableMap === void 0 ? void 0 : tableMap.height) !== null && _tableMap$height2 !== void 0 ? _tableMap$height2 : 0, selection, selectionRect), getOriginIndexes: getSelectedRowIndexes, getTargetIndex: function getTargetIndex(selectionRect) { return selectionRect.bottom; } }] : [{ label: 'left', icon: function icon() { return /*#__PURE__*/React.createElement(TableColumnMoveLeftIcon, { spacing: 'spacious', label: '' }); }, keymap: isNewKeymapExperiment ? moveColumnLeft : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveColumnLeftOld, canMove: canMove('table-column', -1, (_tableMap$width = tableMap === null || tableMap === void 0 ? void 0 : tableMap.width) !== null && _tableMap$width !== void 0 ? _tableMap$width : 0, selection, selectionRect), getOriginIndexes: getSelectedColumnIndexes, getTargetIndex: function getTargetIndex(selectionRect) { return selectionRect.left - 1; } }, { label: 'right', icon: function icon() { return /*#__PURE__*/React.createElement(TableColumnMoveRightIcon, { spacing: 'spacious', label: '' }); }, keymap: isNewKeymapExperiment ? moveColumnRight : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion moveColumnRightOld, canMove: canMove('table-column', 1, (_tableMap$width2 = tableMap === null || tableMap === void 0 ? void 0 : tableMap.width) !== null && _tableMap$width2 !== void 0 ? _tableMap$width2 : 0, selection, selectionRect), getOriginIndexes: getSelectedColumnIndexes, getTargetIndex: function getTargetIndex(selectionRect) { return selectionRect.right; } }]; var sortOptions = direction === 'column' ? [{ label: 'increasing', order: SortOrder.ASC, icon: function icon() { return /*#__PURE__*/React.createElement(SortAscendingIcon, { spacing: 'spacious', label: '' }); } }, { label: 'decreasing', order: SortOrder.DESC, icon: function icon() { return /*#__PURE__*/React.createElement(SortDescendingIcon, { spacing: 'spacious', label: '' }); } }] : []; var sortConfigs = _toConsumableArray(sortOptions.map(function (_ref) { var label = _ref.label, order = _ref.order, icon = _ref.icon; return { id: "sort_column_".concat(order), title: "Sort ".concat(label), disabled: hasMergedCellsInTable, icon: icon, onClick: function onClick(state, dispatch) { sortColumnWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.TABLE_CONTEXT_MENU, index !== null && index !== void 0 ? index : 0, order)(state, dispatch); return true; } }; })); var restConfigs = [].concat(_toConsumableArray(addOptions.map(function (_ref2) { var label = _ref2.label, offset = _ref2.offset, icon = _ref2.icon, keymap = _ref2.keymap; return { id: "add_".concat(direction, "_").concat(label), title: "Add ".concat(direction, " ").concat(label), icon: icon, onClick: function onClick(state, dispatch) { if (direction === 'row') { insertRowWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.TABLE_CONTEXT_MENU, { index: (index !== null && index !== void 0 ? index : 0) + offset, moveCursorToInsertedRow: true })(state, dispatch); } else { insertColumnWithAnalytics(api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(INPUT_METHOD.TABLE_CONTEXT_MENU, (index !== null && index !== void 0 ? index : 0) + offset)(state, dispatch, editorView); } return true; }, keymap: keymap && tooltip(keymap) }; })), [direction === 'column' ? { id: 'distribute_columns', title: 'Distribute columns', disabled: !isDistributeColumnsEnabled(editorView.state), onClick: function onClick(state, dispatch) { var selectionRect = getClosestSelectionRect(state); if (selectionRect) { var newResizeState = getNewResizeStateFromSelectedColumns(selectionRect, state, editorView.domAtPos.bind(editorView), getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor); if (newResizeState) { distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI, api)(INPUT_METHOD.TABLE_CONTEXT_MENU, newResizeState)(state, dispatch); return true; } return false; } return false; }, icon: function icon() { return /*#__PURE__*/React.createElement(TableColumnsDistributeIcon, { spacing: 'spacious', label: '' }); } } : undefined, { id: 'clear_cells', title: 'Clear cells', onClick: function onClick(state, dispatch) { emptyMultipleCellsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.TABLE_CONTEXT_MENU, targetCellPosition)(state, dispatch); return true; }, icon: function icon() { return /*#__PURE__*/React.createElement(TableCellClearIcon, { spacing: 'spacious', label: '' }); }, keymap: tooltip(backspace) }, { id: "delete_".concat(direction), title: "Delete ".concat(direction), onClick: function onClick(state, dispatch) { if (direction === 'row') { deleteRowsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.TABLE_CONTEXT_MENU, selectionRect !== null && selectionRect !== void 0 ? selectionRect : defaultSelectionRect, !!isHeaderRowRequired)(state, dispatch); } else { deleteColumnsWithAnalytics(editorAnalyticsAPI, api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(INPUT_METHOD.TABLE_CONTEXT_MENU, selectionRect !== null && selectionRect !== void 0 ? selectionRect : defaultSelectionRect)(state, dispatch, editorView); } return true; }, icon: direction === 'row' ? function () { return /*#__PURE__*/React.createElement(TableRowDeleteIcon, { spacing: 'spacious', label: '' }); } : function () { return /*#__PURE__*/React.createElement(TableColumnDeleteIcon, { spacing: 'spacious', label: '' }); }, keymap: direction === 'row' ? tooltip(deleteRow) : tooltip(deleteColumn) }], _toConsumableArray(moveOptions.map(function (_ref3) { var label = _ref3.label, canMove = _ref3.canMove, icon = _ref3.icon, keymap = _ref3.keymap, getOriginIndexes = _ref3.getOriginIndexes, getTargetIndex = _ref3.getTargetIndex; return { id: "move_".concat(direction, "_").concat(label), title: "Move ".concat(direction, " ").concat(label), disabled: !canMove, icon: icon, onClick: function onClick(_state, _dispatch) { if (canMove) { requestAnimationFrame(function () { moveSourceWithAnalytics(editorAnalyticsAPI, ariaNotifyPlugin, getIntl)(INPUT_METHOD.TABLE_CONTEXT_MENU, "table-".concat(direction), // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion getOriginIndexes(selectionRect), // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion getTargetIndex(selectionRect))(editorView.state, editorView.dispatch); }); return true; } return false; }, keymap: keymap && tooltip(keymap) }; }))); var allConfigs = _toConsumableArray(restConfigs); if (isColumnSortingEnabled && fg('platform_editor_enable_table_dnd') || !fg('platform_editor_enable_table_dnd')) { allConfigs.unshift.apply(allConfigs, _toConsumableArray(sortConfigs)); } return allConfigs.filter(Boolean); };