UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

277 lines (272 loc) 14 kB
import { ACTION_SUBJECT, EVENT_TYPE, INPUT_METHOD, TABLE_ACTION, TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics'; import { tableCellMinWidth } from '@atlaskit/editor-common/styles'; import { TableMap } from '@atlaskit/editor-tables/table-map'; import { getSelectionRect } from '@atlaskit/editor-tables/utils'; import { insm } from '@atlaskit/insm'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { stopKeyboardColumnResizing } from '../commands/column-resize'; import { updateResizeHandleDecorations } from '../commands/misc'; import { getPluginState as getTablePluginState } from '../plugin-factory'; import { META_KEYS } from '../table-analytics'; import { updateColumnWidths } from '../transforms/column-width'; import { tablesHaveDifferentNoOfColumns } from '../utils/nodes'; import { getSelectedColumnIndexes } from '../utils/selection'; import { evenColumns, setDragging, stopResizing } from './commands'; import { getPluginState } from './plugin-factory'; import { TABLE_OFFSET_IN_COMMENT_EDITOR } from './utils/consts'; import { updateControls } from './utils/dom'; import { currentColWidth, getTableMaxWidth, pointsAtCell, getScalingPercentForTableWithoutWidth, getTableScalingPercent } from './utils/misc'; import { resizeColumn } from './utils/resize-column'; import { getResizeState } from './utils/resize-state'; export var handleMouseDown = function handleMouseDown(view, event, localResizeHandlePos, getEditorContainerWidth, getEditorFeatureFlags, isTableScalingEnabled, api, nodeViewPortalProviderAPI, editorAnalyticsAPI, isCommentEditor) { var _originalTable$attrs; var state = view.state, dispatch = view.dispatch; var editorDisabled = !view.editable; var domAtPos = view.domAtPos.bind(view); var _getEditorContainerWi = getEditorContainerWidth(), editorWidth = _getEditorContainerWi.width; if (editorDisabled || localResizeHandlePos === null || !pointsAtCell(state.doc.resolve(localResizeHandlePos))) { return false; } var _getTablePluginState = getTablePluginState(state), isKeyboardResize = _getTablePluginState.isKeyboardResize; event.preventDefault(); if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) { var _insm$session; (_insm$session = insm.session) === null || _insm$session === void 0 || _insm$session.startFeature('tableColumnResize'); } var tr = view.state.tr; tr.setMeta(META_KEYS.OVERFLOW_TRIGGER, { name: TABLE_OVERFLOW_CHANGE_TRIGGER.RESIZED_COLUMN }); dispatch(tr); var mouseDownTime = event.timeStamp; var cell = state.doc.nodeAt(localResizeHandlePos); var $cell = state.doc.resolve(localResizeHandlePos); var originalTable = $cell.node(-1); var start = $cell.start(-1); var tablePos = state.doc.resolve(start).start(-1); var tableDepth = state.doc.resolve(tablePos).depth; var dom = domAtPos(start).node; if (dom && dom.nodeName !== 'TABLE') { dom = dom.closest('table'); } var maxSize = 0; if (isTableScalingEnabled && isCommentEditor && !((_originalTable$attrs = originalTable.attrs) !== null && _originalTable$attrs !== void 0 && _originalTable$attrs.width)) { maxSize = editorWidth - TABLE_OFFSET_IN_COMMENT_EDITOR; } else { maxSize = getTableMaxWidth({ table: originalTable, tableStart: start, state: state, layout: originalTable.attrs.layout, getEditorContainerWidth: getEditorContainerWidth }); } var shouldScale = tableDepth === 0 && isTableScalingEnabled; var _getEditorFeatureFlag = getEditorFeatureFlags(), _getEditorFeatureFlag2 = _getEditorFeatureFlag.tableWithFixedColumnWidthsOption, tableWithFixedColumnWidthsOption = _getEditorFeatureFlag2 === void 0 ? false : _getEditorFeatureFlag2; var isTableScalingWithFixedColumnWidthsOptionEnabled = isTableScalingEnabled && tableWithFixedColumnWidthsOption; if (isTableScalingWithFixedColumnWidthsOptionEnabled) { shouldScale = shouldScale && originalTable.attrs.displayMode !== 'fixed'; } var shouldUseIncreasedScalingPercent = isTableScalingWithFixedColumnWidthsOptionEnabled; if (isTableScalingEnabled && isCommentEditor) { shouldScale = tableDepth === 0; shouldUseIncreasedScalingPercent = true; } var resizeState = getResizeState({ minWidth: tableCellMinWidth, maxSize: maxSize, table: originalTable, tableRef: dom, start: start, domAtPos: domAtPos, isTableScalingEnabled: shouldScale, shouldUseIncreasedScalingPercent: shouldUseIncreasedScalingPercent, isCommentEditor: isCommentEditor || false }); if (evenColumns({ resizeState: resizeState, table: originalTable, start: start, event: event, api: api })(state, dispatch)) { finish(event); return true; } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var width = currentColWidth(view, localResizeHandlePos, cell.attrs); setDragging({ startX: event.clientX, startWidth: width })(state, dispatch); // When we start resizing a column we need to ensure the underlying tooltip is removed from the decoration to avoid // unnecessary tooltips being displayed during drag. updateResizeHandleDecorations(nodeViewPortalProviderAPI, undefined, undefined, false)(state, dispatch); function finish(event) { // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners window.removeEventListener('mouseup', finish); // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners window.removeEventListener('mousemove', move); var clientX = event.clientX; var state = view.state, dispatch = view.dispatch; var _getPluginState = getPluginState(state), dragging = _getPluginState.dragging, resizeHandlePos = _getPluginState.resizeHandlePos; var _getTablePluginState2 = getTablePluginState(state), isTableHovered = _getTablePluginState2.isTableHovered; if (resizeHandlePos === null) { if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) { var _insm$session2; (_insm$session2 = insm.session) === null || _insm$session2 === void 0 || _insm$session2.endFeature('tableColumnResize'); } return stopResizing()(state, dispatch); } if (!pointsAtCell(state.doc.resolve(resizeHandlePos))) { if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) { var _insm$session3; (_insm$session3 = insm.session) === null || _insm$session3 === void 0 || _insm$session3.endFeature('tableColumnResize'); } return; } // resizeHandlePos could be remapped via a collab change. // Fetch a fresh reference of the table. var $cell = state.doc.resolve(resizeHandlePos); var start = $cell.start(-1); var table = $cell.node(-1); var tablePos = state.doc.resolve(start).start(-1); var tableDepth = state.doc.resolve(tablePos).depth; // If we let go in the same place we started, don't need to do anything. if (dragging && clientX === dragging.startX) { if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) { var _insm$session4; (_insm$session4 = insm.session) === null || _insm$session4 === void 0 || _insm$session4.endFeature('tableColumnResize'); } if (isKeyboardResize || !isTableHovered) { /** if column resize had started via keyboard but continued by mouse * or mouse pointer leaves the table but mouse button still pressed */ return stopKeyboardColumnResizing({})(state, dispatch, view); } else { return stopResizing()(state, dispatch); } } var tr = state.tr; if (dragging) { var startX = dragging.startX; // If the dimensions of the table have changed through a remote modification by another // person for example don't persist the new column widths as we couldn't reliably remap them // For example, if a table col is deleted // There may be a more elegant solution to this, to avoid a jarring experience. This used to // be an equality check but that caused issues when a nested table would change (eg. when it // dynamically updates its width on resize) if (!tablesHaveDifferentNoOfColumns(originalTable, table)) { var _table$attrs; var map = TableMap.get(table); var colIndex = map.colCount($cell.pos - start) + ($cell.nodeAfter ? $cell.nodeAfter.attrs.colspan : 1) - 1; var selectionRect = getSelectionRect(state.selection); var selectedColumns = selectionRect ? getSelectedColumnIndexes(selectionRect) : []; // only selected (or selected - 1) columns should be distributed var resizingSelectedColumns = selectedColumns.indexOf(colIndex) > -1 || selectedColumns.indexOf(colIndex + 1) > -1; var _shouldScale = tableDepth === 0 && isTableScalingEnabled; if (isTableScalingWithFixedColumnWidthsOptionEnabled) { _shouldScale = _shouldScale && originalTable.attrs.displayMode !== 'fixed'; } var resizedDelta = clientX - startX; var _shouldUseIncreasedScalingPercent = isTableScalingWithFixedColumnWidthsOptionEnabled || isTableScalingEnabled && !!isCommentEditor; var scalePercent = isTableScalingEnabled && isCommentEditor && !((_table$attrs = table.attrs) !== null && _table$attrs !== void 0 && _table$attrs.width) ? getScalingPercentForTableWithoutWidth(originalTable, dom) : getTableScalingPercent(originalTable, dom, _shouldUseIncreasedScalingPercent); var newResizeState = resizeColumn(resizeState, colIndex, resizedDelta, dom, originalTable, resizingSelectedColumns ? selectedColumns : undefined, _shouldScale, scalePercent); tr = updateColumnWidths(newResizeState, table, start, api)(tr); if (colIndex === map.width - 1) { var mouseUpTime = event.timeStamp; editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({ action: TABLE_ACTION.ATTEMPTED_TABLE_WIDTH_CHANGE, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { type: 'table-border', position: 'right', duration: mouseUpTime - mouseDownTime, delta: Math.abs(resizedDelta) }, eventType: EVENT_TYPE.UI })(tr); } editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 || editorAnalyticsAPI.attachAnalyticsEvent({ action: TABLE_ACTION.COLUMN_RESIZED, actionSubject: ACTION_SUBJECT.TABLE, eventType: EVENT_TYPE.TRACK, attributes: { colIndex: colIndex, resizedDelta: resizedDelta, isLastColumn: colIndex === map.width - 1, tableWidth: table.attrs.width, inputMethod: INPUT_METHOD.MOUSE, totalRowCount: map.height, totalColumnCount: map.width } })(tr); } if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) { var _insm$session5; (_insm$session5 = insm.session) === null || _insm$session5 === void 0 || _insm$session5.endFeature('tableColumnResize'); } if (isKeyboardResize || !isTableHovered) { /** if column resize had started via keyboard but continued by mouse * or mouse pointer leaves the table but mouse button still pressed */ return stopKeyboardColumnResizing({ originalTr: tr })(state, dispatch, view); } else { return stopResizing(tr)(state, dispatch); } } } function move(event) { var _table$attrs2; var clientX = event.clientX, which = event.which; var state = view.state; var _getPluginState2 = getPluginState(state), dragging = _getPluginState2.dragging, resizeHandlePos = _getPluginState2.resizeHandlePos; var _getTablePluginState3 = getTablePluginState(state), isTableHovered = _getTablePluginState3.isTableHovered; var tablePos = state.doc.resolve(start).start(-1); if (!which || !dragging || resizeHandlePos === null || !pointsAtCell(state.doc.resolve(resizeHandlePos)) || !isTableHovered) { return finish(event); } var $cell = state.doc.resolve(resizeHandlePos); var table = $cell.node(-1); var tableDepth = state.doc.resolve(tablePos).depth; var map = TableMap.get(table); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var colIndex = map.colCount($cell.pos - $cell.start(-1)) + $cell.nodeAfter.attrs.colspan - 1; var shouldScale = tableDepth === 0 && isTableScalingEnabled; var shouldUseIncreasedScalingPercent = isTableScalingWithFixedColumnWidthsOptionEnabled || isTableScalingEnabled && isCommentEditor; if (isTableScalingWithFixedColumnWidthsOptionEnabled) { shouldScale = shouldScale && originalTable.attrs.displayMode !== 'fixed'; } var resizedDelta = clientX - dragging.startX; var scalePercent = isTableScalingEnabled && isCommentEditor && !((_table$attrs2 = table.attrs) !== null && _table$attrs2 !== void 0 && _table$attrs2.width) ? getScalingPercentForTableWithoutWidth(table, dom) : getTableScalingPercent(originalTable, dom, shouldUseIncreasedScalingPercent); resizeColumn(resizeState, colIndex, resizedDelta, dom, table, undefined, shouldScale, scalePercent); updateControls()(state); } // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners window.addEventListener('mouseup', finish); // Ignored via go/ees005 // eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners window.addEventListener('mousemove', move); return true; };