UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

377 lines (370 loc) 19.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.DragControlsWithSelection = exports.DragControls = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _react = _interopRequireWildcard(require("react")); var _analytics = require("@atlaskit/editor-common/analytics"); var _hooks = require("@atlaskit/editor-common/hooks"); var _editorTables = require("@atlaskit/editor-tables"); var _utils = require("@atlaskit/editor-tables/utils"); var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter"); var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals"); var _commands = require("../../../pm-plugins/commands"); var _commandsWithAnalytics = require("../../../pm-plugins/drag-and-drop/commands-with-analytics"); var _pluginFactory = require("../../../pm-plugins/plugin-factory"); var _rowControls = require("../../../pm-plugins/utils/row-controls"); var _selection = require("../../../pm-plugins/utils/selection"); var _types = require("../../../types"); var _consts = require("../../consts"); var _DragHandle = require("../../DragHandle"); var _RowDropTarget = _interopRequireDefault(require("../RowDropTarget")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } /* eslint-disable @atlaskit/design-system/prefer-primitives */ var getSelectedRows = function getSelectedRows(selection) { if (!(selection instanceof _editorTables.CellSelection)) { return []; } if ((0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true)) { // New behaviour: also treat a row selection that sits to the right of a merged first-column // cell as a full row selection. if (!selection.isRowSelection() && !(0, _selection.isRowSelectionWithMergedFirstColumn)(selection)) { return []; } var rect = (0, _utils.getSelectionRect)(selection); return rect ? (0, _selection.getSelectedRowIndexes)(rect) : []; } // Old behaviour: only standard row selections are recognised. if (selection.isRowSelection()) { var _rect = (0, _utils.getSelectionRect)(selection); if (!_rect) { return []; } return (0, _selection.getSelectedRowIndexes)(_rect); } return []; }; var DragControls = exports.DragControls = function DragControls(_ref) { var _tableNode$attrs$loca, _tableNode$attrs; var tableRef = _ref.tableRef, tableNode = _ref.tableNode, tableWidth = _ref.tableWidth, hoveredCell = _ref.hoveredCell, tableActive = _ref.tableActive, editorView = _ref.editorView, isInDanger = _ref.isInDanger, isResizing = _ref.isResizing, isTableHovered = _ref.isTableHovered, hoverRows = _ref.hoverRows, selectRow = _ref.selectRow, selectRows = _ref.selectRows, updateCellHoverLocation = _ref.updateCellHoverLocation, api = _ref.api, selection = _ref.selection; var _useState = (0, _react.useState)(false), _useState2 = (0, _slicedToArray2.default)(_useState, 2), isDragging = _useState2[0], setIsDragging = _useState2[1]; var rowHeights = (0, _rowControls.getRowHeights)(tableRef); var rowsParams = (0, _rowControls.getRowsParams)(rowHeights); var heights = rowHeights.map(function (height) { return "".concat(height - 1, "px"); }).join(' '); var selectedRowIndexes = getSelectedRows(selection !== null && selection !== void 0 ? selection : editorView.state.selection); var currentNodeLocalId = (_tableNode$attrs$loca = tableNode === null || tableNode === void 0 || (_tableNode$attrs = tableNode.attrs) === null || _tableNode$attrs === void 0 ? void 0 : _tableNode$attrs.localId) !== null && _tableNode$attrs$loca !== void 0 ? _tableNode$attrs$loca : ''; (0, _react.useEffect)(function () { return (0, _adapter.monitorForElements)({ canMonitor: function canMonitor(_ref2) { var source = _ref2.source; var _ref3 = source.data, type = _ref3.type, localId = _ref3.localId, indexes = _ref3.indexes; if (!indexes || !localId || type !== 'table-row') { return false; } var _getTablePluginState = (0, _pluginFactory.getPluginState)(editorView.state), tableNode = _getTablePluginState.tableNode; // If the draggable localId is the same as the current selected table localId then we will allow the monitor // watch for changes return localId === (tableNode === null || tableNode === void 0 ? void 0 : tableNode.attrs.localId); }, onDragStart: function onDragStart() { setIsDragging(true); }, onDrop: function onDrop() { setIsDragging(false); } }); }, [editorView]); var toggleDragMenuHandler = (0, _react.useCallback)(function (trigger, event, handleIndex) { var _api$analytics2; if (event !== null && event !== void 0 && event.shiftKey) { return; } // Use the clicked handle index because `hoveredCell` can point at a merged cell's first row. var rowIndex = handleIndex !== null && handleIndex !== void 0 ? handleIndex : hoveredCell === null || hoveredCell === void 0 ? void 0 : hoveredCell.rowIndex; if ((0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true)) { if (rowIndex !== undefined && api) { var _getTablePluginState2 = (0, _pluginFactory.getPluginState)(editorView.state), currentActiveTableMenu = _getTablePluginState2.activeTableMenu; var isSameActiveMenu = (currentActiveTableMenu === null || currentActiveTableMenu === void 0 ? void 0 : currentActiveTableMenu.type) === 'row' && currentActiveTableMenu.index === rowIndex; api.core.actions.execute(function (_ref4) { var tr = _ref4.tr; if (!isSameActiveMenu) { var _api$analytics; (_api$analytics = api.analytics) === null || _api$analytics === void 0 || (_api$analytics = _api$analytics.actions) === null || _api$analytics === void 0 || _api$analytics.attachAnalyticsEvent({ action: _analytics.TABLE_ACTION.DRAG_MENU_OPENED, actionSubject: _analytics.ACTION_SUBJECT.TABLE, actionSubjectId: null, eventType: _analytics.EVENT_TYPE.TRACK, attributes: { inputMethod: trigger === 'keyboard' ? _analytics.INPUT_METHOD.KEYBOARD : _analytics.INPUT_METHOD.MOUSE, direction: 'row' } })(tr); } (0, _commands.toggleActiveTableMenu)({ type: 'row', index: rowIndex, openedBy: trigger }, currentActiveTableMenu, api)({ tr: tr }); return tr; }); } return; } (0, _commandsWithAnalytics.toggleDragMenuWithAnalytics)(api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions)(undefined, 'row', rowIndex, trigger)(editorView.state, editorView.dispatch); }, [editorView, hoveredCell === null || hoveredCell === void 0 ? void 0 : hoveredCell.rowIndex, api]); var rowIndex = hoveredCell === null || hoveredCell === void 0 ? void 0 : hoveredCell.rowIndex; var handleMouseOut = (0, _react.useCallback)(function () { if (tableActive) { var state = editorView.state, dispatch = editorView.dispatch; (0, _commands.clearHoverSelection)()(state, dispatch); } }, [editorView, tableActive]); var handleMouseMove = (0, _react.useCallback)(function (e) { var target = e.nativeEvent.target instanceof Element ? e.nativeEvent.target : null; var isParentDragControls = target === null || target === void 0 ? void 0 : target.closest(".".concat(_types.TableCssClassName.DRAG_ROW_CONTROLS)); var rowIndex = target === null || target === void 0 ? void 0 : target.getAttribute('data-start-index'); // avoid updating if event target is not related if (!isParentDragControls || !rowIndex) { return; } updateCellHoverLocation(Number(rowIndex)); }, [updateCellHoverLocation]); var rowIndexes = (0, _react.useMemo)(function () { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return [rowIndex]; }, [rowIndex]); var handleMouseOver = (0, _react.useCallback)(function () { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion hoverRows([rowIndex]); }, [hoverRows, rowIndex]); var handleClick = (0, _react.useCallback)(function (e) { var isClickOutsideSelectedRows = // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion selectedRowIndexes.length >= 1 && !selectedRowIndexes.includes(rowIndex); if (!selectedRowIndexes || selectedRowIndexes.length === 0 || isClickOutsideSelectedRows) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion selectRow(rowIndex, e.shiftKey); } // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (selectedRowIndexes.length > 1 && selectedRowIndexes.includes(rowIndex) && !e.shiftKey) { selectRows(selectedRowIndexes); } }, [rowIndex, selectRow, selectRows, selectedRowIndexes]); var generateHandleByType = function generateHandleByType(type, appearance, gridRow, indexes) { var isHover = type === 'hover'; var previewHeight = rowHeights.reduce(function (sum, v, i) { return sum + v * (indexes.includes(i) ? 1 : 0); }, 0); return /*#__PURE__*/_react.default.createElement("div", { key: type, style: { gridRow: gridRow, // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 gridColumn: '2', // DragHandle uses `transform: rotate(90)`, which doesn't affect its parent (this div) causing the width of this element to be the true height of the drag handle // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 display: 'flex', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 width: '9px', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 height: '100%', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 position: 'relative', // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview, @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 right: '-0.5px', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop pointerEvents: 'none' } // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop , className: (0, _expValEquals.expValEquals)('platform_editor_table_sticky_header_improvements', 'cohort', 'test_with_overflow') ? _types.TableCssClassName.DRAG_ROW_FLOATING_DRAG_HANDLE : undefined, "data-testid": "table-floating-row-".concat(isHover ? rowIndex : selectedRowIndexes[0], "-drag-handle"), "data-row-index": rowIndex, "data-selected-row-index": selectedRowIndexes[0], "data-handle-appearance": appearance }, /*#__PURE__*/_react.default.createElement(_DragHandle.DragHandle, { api: api, isDragMenuTarget: !isHover, direction: "row", tableLocalId: currentNodeLocalId, indexes: indexes, forceDefaultHandle: !isHover, previewWidth: tableWidth, previewHeight: previewHeight, appearance: appearance, hoveredCell: hoveredCell, onClick: handleClick, onMouseOver: handleMouseOver, onMouseOut: handleMouseOut, onBlur: (0, _expValEquals.expValEquals)('platform_editor_table_a11y_eslint_fix', 'isEnabled', true) ? handleMouseOut : undefined, onFocus: (0, _expValEquals.expValEquals)('platform_editor_table_a11y_eslint_fix', 'isEnabled', true) ? handleMouseOver : undefined, toggleDragMenu: toggleDragMenuHandler, editorView: editorView })); }; var rowHandles = function rowHandles() { var handles = []; var isRowSelected = selectedRowIndexes.length > 0; var isEntireTableSelected = rowHeights.length > selectedRowIndexes.length; if (!tableActive) { return null; } var selectedAppearance = isRowSelected && isEntireTableSelected ? isInDanger ? 'danger' : 'selected' : 'placeholder'; // placeholder / selected need to always render at least one handle // so it can be focused via keyboard shortcuts var selectedGridRow = (0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true) ? // New behaviour: always position the placeholder in the first row to avoid an invalid // `NaN / span 0` grid placement (which makes the handle disappear) when no rows are selected. selectedAppearance === 'placeholder' ? '1 / span 1' : "".concat(selectedRowIndexes[0] + 1, " / span ").concat(selectedRowIndexes.length) : // Old behaviour. "".concat(selectedRowIndexes[0] + 1, " / span ").concat(selectedRowIndexes.length); handles.push(generateHandleByType('selected', selectedAppearance, selectedGridRow, selectedRowIndexes)); if (hoveredCell && isTableHovered && rowIndex !== undefined && !selectedRowIndexes.includes(rowIndex) && rowIndex < rowHeights.length) { handles.push(generateHandleByType('hover', 'default', "".concat(rowIndex + 1, " / span 1"), rowIndexes)); } return handles; }; if (isResizing) { return null; } return /*#__PURE__*/_react.default.createElement("div", { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 className: _types.TableCssClassName.DRAG_ROW_CONTROLS, style: { gridTemplateRows: heights, gridTemplateColumns: isDragging ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 "".concat(_consts.dropTargetExtendedWidth, "px ").concat(_consts.dragRowControlsWidth, "px ").concat(tableWidth, "px") : // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values "0px ".concat(_consts.dragRowControlsWidth, "px 0px"), // eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview left: isDragging ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766 "-".concat(_consts.dropTargetExtendedWidth + 2, "px") : "var(--ds-space-negative-025, -2px)" }, onMouseMove: handleMouseMove, contentEditable: false }, rowsParams.map(function (_ref5, index) { var startIndex = _ref5.startIndex, endIndex = _ref5.endIndex; return ( /*#__PURE__*/ // Ignored via go/ees005 // eslint-disable-next-line react/no-array-index-key _react.default.createElement(_react.Fragment, { key: index }, /*#__PURE__*/_react.default.createElement("div", { style: { gridRow: "".concat(index + 1, " / span 1"), // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 gridColumn: '2' }, "data-start-index": startIndex, "data-end-index": endIndex // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 , className: _types.TableCssClassName.DRAG_ROW_FLOATING_INSERT_DOT_WRAPPER, contentEditable: false // Ignored via go/ees005 // eslint-disable-next-line react/no-array-index-key , key: "insert-dot-".concat(index) }, /*#__PURE__*/_react.default.createElement("div", { className: _types.TableCssClassName.DRAG_ROW_FLOATING_INSERT_DOT })), isDragging && /*#__PURE__*/_react.default.createElement(_RowDropTarget.default // Ignored via go/ees005 // eslint-disable-next-line react/no-array-index-key , { key: "drop-target-".concat(index), index: index, localId: currentNodeLocalId // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , style: { // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 gridColumn: '1 / span 3', gridRow: "".concat(index + 1, " / span 1"), // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 height: '100%', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 pointerEvents: 'auto', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 position: 'relative', // eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 left: "var(--ds-space-negative-100, -8px)" } })) ); }), rowHandles()); }; var DragControlsWithSelection = exports.DragControlsWithSelection = function DragControlsWithSelection(_ref6) { var editorView = _ref6.editorView, tableRef = _ref6.tableRef, tableNode = _ref6.tableNode, tableWidth = _ref6.tableWidth, tableActive = _ref6.tableActive, hoveredCell = _ref6.hoveredCell, isInDanger = _ref6.isInDanger, isTableHovered = _ref6.isTableHovered, isResizing = _ref6.isResizing, hoverRows = _ref6.hoverRows, selectRow = _ref6.selectRow, selectRows = _ref6.selectRows, updateCellHoverLocation = _ref6.updateCellHoverLocation, api = _ref6.api; var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['selection'], function (states) { var _states$selectionStat; return { selection: (_states$selectionStat = states.selectionState) === null || _states$selectionStat === void 0 ? void 0 : _states$selectionStat.selection }; }), selection = _useSharedPluginState.selection; return /*#__PURE__*/_react.default.createElement(DragControls, { editorView: editorView, tableRef: tableRef, tableNode: tableNode, tableWidth: tableWidth, tableActive: tableActive, hoveredCell: hoveredCell, isInDanger: isInDanger, isTableHovered: isTableHovered, isResizing: isResizing, hoverRows: hoverRows, selectRow: selectRow, selectRows: selectRows, updateCellHoverLocation: updateCellHoverLocation, api: api, selection: selection }); };