@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
307 lines (300 loc) • 15.1 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
// #region Imports
import { AddColumnStep } from '@atlaskit/custom-steps';
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics';
import { getParentOfTypeCount, getPositionAfterTopParentNodeOfType, isNestedTablesSupported } from '@atlaskit/editor-common/nesting';
import { Selection, TextSelection } from '@atlaskit/editor-prosemirror/state';
import { hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils';
import { TableMap } from '@atlaskit/editor-tables/table-map';
import { addColumnAt as addColumnAtPMUtils, addRowAt, findTable, selectedRect } from '@atlaskit/editor-tables/utils';
import { updateRowOrColumnMovedTransform } from '../analytics/commands';
import { META_KEYS } from '../table-analytics';
import { rescaleColumns } from '../transforms/column-width';
import { createTableWithWidth } from '../utils/create';
import { getAllowAddColumnCustomStep } from '../utils/get-allow-add-column-custom-step';
import { checkIfHeaderRowEnabled } from '../utils/nodes';
import { copyPreviousRow } from '../utils/row-controls';
function addColumnAtCustomStep(column) {
return function (tr) {
var table = findTable(tr.selection);
if (table) {
return tr.step(AddColumnStep.create(tr.doc, table.pos, column));
}
return tr;
};
}
export function addColumnAt(api) {
var isTableScalingEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isTableFixedColumnWidthsOptionEnabled = arguments.length > 2 ? arguments[2] : undefined;
var shouldUseIncreasedScalingPercent = arguments.length > 3 ? arguments[3] : undefined;
var isCommentEditor = arguments.length > 4 ? arguments[4] : undefined;
return function (column) {
var allowAddColumnCustomStep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var view = arguments.length > 2 ? arguments[2] : undefined;
return function (tr) {
var updatedTr = tr;
if (allowAddColumnCustomStep) {
updatedTr = addColumnAtCustomStep(column)(updatedTr);
} else {
updatedTr = addColumnAtPMUtils(column)(updatedTr);
}
var table = findTable(updatedTr.selection);
if (table) {
// [ED-8288] Update colwidths manually to avoid multiple dispatch in TableComponent
updatedTr = rescaleColumns(isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, api, isCommentEditor)(table, view)(updatedTr);
}
if (view) {
updatedTr = updateRowOrColumnMovedTransform({
type: 'column'
}, 'addRowOrColumn')(view.state, updatedTr);
}
updatedTr.setMeta(META_KEYS.OVERFLOW_TRIGGER, {
name: TABLE_OVERFLOW_CHANGE_TRIGGER.ADDED_COLUMN
});
return updatedTr;
};
};
}
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
// Command to add a column before the column with the selection.
export var addColumnBefore = function addColumnBefore(api) {
var isTableScalingEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isTableFixedColumnWidthsOptionEnabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var shouldUseIncreasedScalingPercent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
var isCommentEditor = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
return function (state, dispatch, view) {
var table = findTable(state.selection);
if (!table) {
return false;
}
if (dispatch) {
var rect = selectedRect(state);
dispatch(addColumnAt(api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(rect.left, getAllowAddColumnCustomStep(state), view)(state.tr));
}
return true;
};
};
// :: (EditorState, dispatch: ?(tr: Transaction)) → bool
// Command to add a column after the column with the selection.
export var addColumnAfter = function addColumnAfter(api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor) {
return function (state, dispatch, view) {
var table = findTable(state.selection);
if (!table) {
return false;
}
if (dispatch) {
var rect = selectedRect(state);
dispatch(addColumnAt(api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(rect.right, getAllowAddColumnCustomStep(state), view)(state.tr));
}
return true;
};
};
export var insertColumn = function insertColumn(api) {
var isTableScalingEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
var isTableFixedColumnWidthsOptionEnabled = arguments.length > 2 ? arguments[2] : undefined;
var shouldUseIncreasedScalingPercent = arguments.length > 3 ? arguments[3] : undefined;
var isCommentEditor = arguments.length > 4 ? arguments[4] : undefined;
return function (column) {
return function (state, dispatch, view) {
var tr = addColumnAt(api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(column, getAllowAddColumnCustomStep(state), view)(state.tr);
var table = findTable(tr.selection);
if (!table) {
return false;
}
// move the cursor to the newly created column
var pos = TableMap.get(table.node).positionAt(0, column, table.node);
if (dispatch) {
dispatch(tr.setSelection(Selection.near(tr.doc.resolve(table.start + pos))));
}
return true;
};
};
};
export var insertRow = function insertRow(row, moveCursorToTheNewRow) {
return function (state, dispatch) {
// Don't clone the header row
var headerRowEnabled = checkIfHeaderRowEnabled(state.selection);
var clonePreviousRow = headerRowEnabled && row > 1 || !headerRowEnabled && row > 0;
// When the table have header row
// we should not add row on the position zero
if (row === 0 && headerRowEnabled) {
return false;
}
var tr = clonePreviousRow ? copyPreviousRow(state.schema)(row)(state.tr) : addRowAt(row, undefined)(state.tr);
var table = findTable(tr.selection);
if (!table) {
return false;
}
if (dispatch) {
var selection = state.selection;
if (moveCursorToTheNewRow) {
// move the cursor to the newly created row
var pos = TableMap.get(table.node).positionAt(row, 0, table.node);
tr.setSelection(Selection.near(tr.doc.resolve(table.start + pos)));
} else {
tr.setSelection(selection.map(tr.doc, tr.mapping));
}
updateRowOrColumnMovedTransform({
type: 'row'
}, 'addRowOrColumn')(state, tr);
dispatch(tr);
}
return true;
};
};
/**
* @private
* @deprecated This function is deprecated - please use insertTableWithNestingSupport instead.
* (To be removed with feature gate: `platform_editor_use_nested_table_pm_nodes`)
*/
export var createTable = function createTable(isTableScalingEnabled, isTableAlignmentEnabled, isFullWidthModeEnabled, isMaxWidthModeEnabled, editorAnalyticsAPI, isCommentEditor, isChromelessEditor, isTableResizingEnabled) {
return function (state, dispatch) {
var table = createTableWithWidth({
isTableScalingEnabled: isTableScalingEnabled,
isTableAlignmentEnabled: isTableAlignmentEnabled,
isFullWidthModeEnabled: isFullWidthModeEnabled,
isMaxWidthModeEnabled: isMaxWidthModeEnabled,
isCommentEditor: isCommentEditor,
isChromelessEditor: isChromelessEditor,
isTableResizingEnabled: isTableResizingEnabled
})(state.schema);
if (dispatch) {
var tr = safeInsert(table)(state.tr).scrollIntoView();
if (editorAnalyticsAPI) {
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({
action: ACTION.INSERTED,
actionSubject: ACTION_SUBJECT.DOCUMENT,
actionSubjectId: ACTION_SUBJECT_ID.TABLE,
attributes: {
inputMethod: INPUT_METHOD.SHORTCUT
},
eventType: EVENT_TYPE.TRACK
})(tr);
}
dispatch(tr);
}
return true;
};
};
/**
* @private
* @deprecated This function is deprecated - please use insertTableWithNestingSupport instead.
* (To be removed with feature gate: `platform_editor_use_nested_table_pm_nodes`)
*/
export var insertTableWithSize = function insertTableWithSize(isFullWidthModeEnabled, isMaxWidthModeEnabled, isTableScalingEnabled, isTableAlignmentEnabled, editorAnalyticsAPI, isCommentEditor, isChromelessEditor) {
return function (rowsCount, colsCount, inputMethod) {
return function (_ref) {
var tr = _ref.tr;
var tableNode = createTableWithWidth({
isTableScalingEnabled: isTableScalingEnabled,
isFullWidthModeEnabled: isFullWidthModeEnabled,
isMaxWidthModeEnabled: isMaxWidthModeEnabled,
isTableAlignmentEnabled: isTableAlignmentEnabled,
isCommentEditor: isCommentEditor,
isChromelessEditor: isChromelessEditor,
createTableProps: {
rowsCount: rowsCount,
colsCount: colsCount
}
})(tr.doc.type.schema);
var newTr = safeInsert(tableNode)(tr).scrollIntoView();
if (inputMethod) {
editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({
action: ACTION.INSERTED,
actionSubject: ACTION_SUBJECT.DOCUMENT,
actionSubjectId: ACTION_SUBJECT_ID.TABLE,
attributes: {
inputMethod: inputMethod,
totalRowCount: rowsCount,
totalColumnCount: colsCount
},
eventType: EVENT_TYPE.TRACK
})(newTr);
}
return newTr;
};
};
};
/**
* Unified command to insert a new table into the editor.
*
* @param {object} options - Configuration options for table insertion.
* @param {boolean} [options.isTableScalingEnabled=false] - Flag to enable table scaling.
* @param {boolean} [options.isTableAlignmentEnabled=false] - Flag to enable table alignment.
* @param {boolean} [options.isFullWidthModeEnabled=false] - Flag to enable full-width mode for the table.
* @param {boolean} [options.isCommentEditor=false] - Flag to indicate if the editor is in comment mode.
* @param {boolean} [options.isChromelessEditor=false] - Flag to indicate if the editor is chromeless.
* @param {boolean} [options.isTableResizingEnabled=false] - Flag to enable table resizing.
* @param {object} [options.createTableProps={}] - Additional properties for table creation, including table size.
* @param {object} api - PluginInjectinoApi object for content insertion commands.
* @param {object} analyticsPayload - Payload for analytics tracking.
*
* @returns {Function} A function that takes a transaction and inserts a table.
*/
export var insertTableWithNestingSupport = function insertTableWithNestingSupport(_ref2, api, analyticsPayload) {
var _ref2$isTableScalingE = _ref2.isTableScalingEnabled,
isTableScalingEnabled = _ref2$isTableScalingE === void 0 ? false : _ref2$isTableScalingE,
_ref2$isTableAlignmen = _ref2.isTableAlignmentEnabled,
isTableAlignmentEnabled = _ref2$isTableAlignmen === void 0 ? false : _ref2$isTableAlignmen,
_ref2$isFullWidthMode = _ref2.isFullWidthModeEnabled,
isFullWidthModeEnabled = _ref2$isFullWidthMode === void 0 ? false : _ref2$isFullWidthMode,
_ref2$isMaxWidthModeE = _ref2.isMaxWidthModeEnabled,
isMaxWidthModeEnabled = _ref2$isMaxWidthModeE === void 0 ? false : _ref2$isMaxWidthModeE,
_ref2$isCommentEditor = _ref2.isCommentEditor,
isCommentEditor = _ref2$isCommentEditor === void 0 ? false : _ref2$isCommentEditor,
_ref2$isChromelessEdi = _ref2.isChromelessEditor,
isChromelessEditor = _ref2$isChromelessEdi === void 0 ? false : _ref2$isChromelessEdi,
_ref2$isTableResizing = _ref2.isTableResizingEnabled,
isTableResizingEnabled = _ref2$isTableResizing === void 0 ? false : _ref2$isTableResizing,
_ref2$createTableProp = _ref2.createTableProps,
createTableProps = _ref2$createTableProp === void 0 ? {} : _ref2$createTableProp;
return function (_ref3) {
var _api$contentInsertion;
var tr = _ref3.tr;
var schema = tr.doc.type.schema;
// If the cursor is inside a table
var insertAt;
var isNestedTable = false;
if (hasParentNodeOfType(schema.nodes.table)(tr.selection) && isNestedTablesSupported(schema)) {
// If trying to nest deeper than one level, we insert the table after the top table
if (getParentOfTypeCount(schema.nodes.table)(tr.selection.$from) > 1) {
var positionAfterTopTable = getPositionAfterTopParentNodeOfType(schema.nodes.table)(tr.selection.$from);
if (!positionAfterTopTable) {
return tr;
}
insertAt = TextSelection.create(tr.doc, positionAfterTopTable);
} else {
// Table can be nested in parent table
isNestedTable = true;
}
}
var node = createTableWithWidth({
isTableScalingEnabled: isTableScalingEnabled,
isTableAlignmentEnabled: isTableAlignmentEnabled,
isFullWidthModeEnabled: isFullWidthModeEnabled,
isMaxWidthModeEnabled: isMaxWidthModeEnabled,
isCommentEditor: isCommentEditor,
isChromelessEditor: isChromelessEditor,
isTableResizingEnabled: isTableResizingEnabled,
isNestedTable: isNestedTable,
createTableProps: createTableProps
})(schema);
api === null || api === void 0 || (_api$contentInsertion = api.contentInsertion) === null || _api$contentInsertion === void 0 || (_api$contentInsertion = _api$contentInsertion.commands) === null || _api$contentInsertion === void 0 || _api$contentInsertion.insert({
node: node,
options: {
selectNodeInserted: false,
analyticsPayload: analyticsPayload ? _objectSpread(_objectSpread({}, analyticsPayload), {}, {
attributes: _objectSpread(_objectSpread({}, analyticsPayload.attributes), {}, {
localId: node.attrs.localId
})
}) : undefined,
insertAt: insertAt
}
})({
tr: tr
});
return tr;
};
};