@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
257 lines (254 loc) • 13.7 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DragHandle = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = _interopRequireWildcard(require("react"));
var _classnames2 = _interopRequireDefault(require("classnames"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _reactIntl = require("react-intl");
var _browser = require("@atlaskit/editor-common/browser");
var _messages = require("@atlaskit/editor-common/messages");
var _state = require("@atlaskit/editor-prosemirror/state");
var _editorTables = require("@atlaskit/editor-tables");
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
var _setCustomNativeDragPreview = require("@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _pluginFactory = require("../../pm-plugins/drag-and-drop/plugin-factory");
var _mergedCells = require("../../pm-plugins/utils/merged-cells");
var _types = require("../../types");
var _consts = require("../consts");
var _DragPreview = require("../DragPreview");
var _HandleIconComponent = require("./HandleIconComponent");
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/no-html-button */
var DragHandleComponent = function DragHandleComponent(_ref) {
var isDragMenuTarget = _ref.isDragMenuTarget,
tableLocalId = _ref.tableLocalId,
_ref$direction = _ref.direction,
direction = _ref$direction === void 0 ? 'row' : _ref$direction,
_ref$appearance = _ref.appearance,
appearance = _ref$appearance === void 0 ? 'default' : _ref$appearance,
indexes = _ref.indexes,
_ref$forceDefaultHand = _ref.forceDefaultHandle,
forceDefaultHandle = _ref$forceDefaultHand === void 0 ? false : _ref$forceDefaultHand,
previewWidth = _ref.previewWidth,
previewHeight = _ref.previewHeight,
_onMouseOver = _ref.onMouseOver,
_onMouseOut = _ref.onMouseOut,
onFocus = _ref.onFocus,
onBlur = _ref.onBlur,
toggleDragMenu = _ref.toggleDragMenu,
hoveredCell = _ref.hoveredCell,
onClick = _ref.onClick,
editorView = _ref.editorView,
formatMessage = _ref.intl.formatMessage;
var dragHandleDivRef = (0, _react.useRef)(null);
var _useState = (0, _react.useState)(null),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
previewContainer = _useState2[0],
setPreviewContainer = _useState2[1];
var state = editorView.state,
selection = editorView.state.selection;
var _getDnDPluginState = (0, _pluginFactory.getPluginState)(state),
_getDnDPluginState$is = _getDnDPluginState.isDragMenuOpen,
isDragMenuOpen = _getDnDPluginState$is === void 0 ? false : _getDnDPluginState$is;
var _useState3 = (0, _react.useState)(false),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
isHovered = _useState4[0],
setIsHovered = _useState4[1];
var isRow = direction === 'row';
var isColumn = direction === 'column';
var hasMergedCells = (0, _react.useMemo)(function () {
var table = (0, _editorTables.findTable)(selection);
if (!table) {
return false;
}
var map = _editorTables.TableMap.get(table === null || table === void 0 ? void 0 : table.node);
if (!map.hasMergedCells() || indexes.length < 1) {
return false;
}
var mapByColumn = map.mapByColumn,
mapByRow = map.mapByRow;
// this handle when hover to first column or row which has merged cells.
if (hoveredCell && hoveredCell.rowIndex !== undefined && hoveredCell.colIndex !== undefined && selection instanceof _state.TextSelection) {
var rowIndex = hoveredCell.rowIndex,
colIndex = hoveredCell.colIndex;
var mergedPositionInRow = (0, _mergedCells.findDuplicatePosition)(mapByRow[rowIndex]);
var mergedPositionInCol = (0, _mergedCells.findDuplicatePosition)(mapByColumn[colIndex]);
var hasMergedCellsInFirstRowOrColumn = direction === 'column' ? mergedPositionInRow.includes(mapByRow[0][colIndex]) : mergedPositionInCol.includes(mapByColumn[0][rowIndex]);
var isHoveredOnFirstRowOrColumn = direction === 'column' ? hoveredCell.rowIndex === 0 && hasMergedCellsInFirstRowOrColumn : hoveredCell.colIndex === 0 && hasMergedCellsInFirstRowOrColumn;
if (isHoveredOnFirstRowOrColumn) {
var mergedSizes = direction === 'column' ? mapByRow[0].filter(function (el) {
return el === mapByRow[0][colIndex];
}).length : mapByColumn[0].filter(function (el) {
return el === mapByColumn[0][rowIndex];
}).length;
var mergedSelection = (0, _mergedCells.hasMergedCellsInSelection)(direction === 'column' ? [colIndex, colIndex + mergedSizes - 1] : [rowIndex, rowIndex + mergedSizes - 1], direction)(selection);
return mergedSelection;
}
}
return (0, _mergedCells.hasMergedCellsInSelection)(indexes, direction)(selection);
}, [indexes, selection, direction, hoveredCell]);
var handleIconProps = {
forceDefaultHandle: forceDefaultHandle,
isHandleHovered: isHovered,
hasMergedCells: hasMergedCells
};
(0, _react.useEffect)(function () {
var dragHandleDivRefCurrent = dragHandleDivRef.current;
var browser = (0, _browser.getBrowserInfo)();
if (dragHandleDivRefCurrent) {
return (0, _adapter.draggable)({
element: dragHandleDivRefCurrent,
canDrag: function canDrag() {
return !hasMergedCells;
},
getInitialData: function getInitialData() {
return {
localId: tableLocalId,
type: "table-".concat(direction),
indexes: indexes
};
},
onGenerateDragPreview: function onGenerateDragPreview(_ref2) {
var nativeSetDragImage = _ref2.nativeSetDragImage;
(0, _setCustomNativeDragPreview.setCustomNativeDragPreview)({
getOffset: function getOffset(_ref3) {
var container = _ref3.container;
var rect = container.getBoundingClientRect();
if (browser.safari) {
// See: https://product-fabric.atlassian.net/browse/ED-21442
// We need to ensure that the preview is not overlaying screen content when the snapshot is taken, otherwise
// safari will composite the screen text elements into the bitmap snapshot. The container is a wrapper which is already
// positioned fixed at top/left 0.
// IMPORTANT: we must not exceed more then the width of the container off-screen otherwise not preview will
// be generated.
container.style.left = "-".concat(rect.width - 0.0001, "px");
}
if (isRow) {
return {
x: 12,
y: rect.height / 2
};
} else {
return {
x: rect.width / 2 + 4,
y: 12
};
}
},
render: function render(_ref4) {
var container = _ref4.container;
setPreviewContainer(container);
return function () {
return setPreviewContainer(null);
};
},
nativeSetDragImage: nativeSetDragImage
});
}
});
}
}, [tableLocalId, direction, indexes, isRow, editorView.state.selection, hasMergedCells]);
var showDragMenuAnchorId = isRow ? 'drag-handle-button-row' : 'drag-handle-button-column';
var browser = (0, _browser.getBrowserInfo)();
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("button", {
type: "button"
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: _types.TableCssClassName.DRAG_HANDLE_BUTTON_CLICKABLE_ZONE,
"data-testid": "table-drag-handle-clickable-zone-button",
style: {
height: isRow ? // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
"calc(100% - ".concat(_consts.dragTableInsertColumnButtonSize, "px)") : "var(--ds-space-200, 16px)",
// 16px here because it's the size of drag handle button's large side
width: isRow ? "var(--ds-space-200, 16px)" // 16px here because it's the size of drag handle button's large side
: // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
"calc(100% - ".concat(_consts.dragTableInsertColumnButtonSize, "px)"),
left: isRow ? "var(--ds-space-050, 4px)" : undefined,
bottom: isColumn ? "var(--ds-space-0, 0px)" : undefined,
alignSelf: isColumn ? 'none' : 'center',
zIndex: isColumn ? '-1' : 'auto',
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
pointerEvents: 'auto'
},
onMouseUp: function onMouseUp(e) {
// should toggle menu if current drag menu open.
// return focus to editor so copying table selections whilst still works, i cannot call e.preventDefault in a mousemove event as this stops dragstart events from firing
// -> this is bad for a11y but is the current standard new copy/paste keyboard shortcuts should be introduced instead
editorView.focus();
if (isDragMenuOpen) {
toggleDragMenu && toggleDragMenu('mouse', e);
}
},
onClick: onClick,
"aria-label": formatMessage(_messages.tableMessages.dragHandleZone)
}), /*#__PURE__*/_react.default.createElement("button", {
type: "button",
id: isDragMenuTarget ? showDragMenuAnchorId : undefined
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
,
className: (0, _classnames2.default)(_types.TableCssClassName.DRAG_HANDLE_BUTTON_CONTAINER, appearance, (0, _defineProperty2.default)({}, _types.TableCssClassName.DRAG_HANDLE_DISABLED, hasMergedCells)),
ref: dragHandleDivRef,
style: {
transform: isColumn ? 'none' : 'rotate(90deg)',
alignSelf: isColumn ? 'none' : 'center'
},
"data-testid": "table-drag-handle-button",
"aria-label": formatMessage(isRow ? _messages.tableMessages.rowDragHandle : _messages.tableMessages.columnDragHandle),
"aria-expanded": isDragMenuOpen && isDragMenuTarget ? 'true' : 'false',
"aria-haspopup": "menu",
onMouseOver: function onMouseOver(e) {
setIsHovered(true);
_onMouseOver && _onMouseOver(e);
},
onMouseOut: function onMouseOut(e) {
setIsHovered(false);
_onMouseOut && _onMouseOut(e);
},
onFocus: (0, _expValEquals.expValEquals)('platform_editor_table_a11y_eslint_fix', 'isEnabled', true) ? function (e) {
onFocus && onFocus(e);
} : undefined,
onBlur: (0, _expValEquals.expValEquals)('platform_editor_table_a11y_eslint_fix', 'isEnabled', true) ? function (e) {
onBlur && onBlur(e);
} : undefined,
onMouseUp: function onMouseUp(e) {
// return focus to editor so copying table selections whilst still works, i cannot call e.preventDefault in a mousemove event as this stops dragstart events from firing
// -> this is bad for a11y but is the current standard new copy/paste keyboard shortcuts should be introduced instead
editorView.focus();
toggleDragMenu && toggleDragMenu('mouse', e);
},
onClick: onClick,
onKeyDown: function onKeyDown(e) {
if (e.key === 'Enter' || e.key === ' ') {
toggleDragMenu && toggleDragMenu('keyboard');
}
}
}, appearance !== 'placeholder' ?
// cannot block pointer events in Firefox as it breaks Dragging functionality
browser.gecko ?
/*#__PURE__*/
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
_react.default.createElement(_HandleIconComponent.HandleIconComponent, handleIconProps) :
/*#__PURE__*/
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766
_react.default.createElement("span", {
style: {
pointerEvents: 'none'
}
}, /*#__PURE__*/_react.default.createElement(_HandleIconComponent.HandleIconComponent
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, handleIconProps)) : null), previewContainer && previewWidth !== undefined && previewHeight !== undefined && /*#__PURE__*/_reactDom.default.createPortal( /*#__PURE__*/_react.default.createElement(_DragPreview.DragPreview, {
direction: direction,
width: previewWidth,
height: previewHeight
}), previewContainer));
};
var DragHandle = exports.DragHandle = (0, _reactIntl.injectIntl)(DragHandleComponent);