@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
339 lines (337 loc) • 15.3 kB
JavaScript
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);
};