@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
230 lines (228 loc) • 12.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireWildcard(require("react"));
var _react2 = require("@emotion/react");
var _reactIntl = require("react-intl");
var _enums = require("@atlaskit/editor-common/analytics/types/enums");
var _errorBoundary = require("@atlaskit/editor-common/error-boundary");
var _keymaps = require("@atlaskit/editor-common/keymaps");
var _table = require("@atlaskit/editor-common/messages/table");
var _Popup = _interopRequireDefault(require("@atlaskit/editor-common/Popup"));
var _ToolbarButton = _interopRequireDefault(require("@atlaskit/editor-common/ui-menu/ToolbarButton"));
var _useSharedPluginStateWithSelector = require("@atlaskit/editor-common/useSharedPluginStateWithSelector");
var _utils = require("@atlaskit/editor-prosemirror/utils");
var _constants = require("@atlaskit/editor-shared-styles/constants");
var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down"));
var _isExperimentEnabled = require("@atlaskit/platform-feature-experiments/is-experiment-enabled");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _commands = require("../../pm-plugins/commands");
var _pluginFactory = require("../../pm-plugins/plugin-factory");
var _stickyHeader = require("../../pm-plugins/utils/sticky-header");
var _types = require("../../types");
var _stickyHeaderZIndex = require("../sticky-header-z-index");
var _FixedButton = _interopRequireDefault(require("./FixedButton"));
var _styles = require("./styles");
var _useCellLayoutVersion = require("./useCellLayoutVersion");
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); }
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) { (0, _defineProperty2.default)(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; } /**
* @jsxRuntime classic
* @jsx jsx
*/ // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
// Ignored via go/ees005
// eslint-disable-next-line import/no-named-as-default
var BUTTON_OFFSET = 3;
var CONTEXTUAL_MENU_BUTTON_Z_INDEX = 2;
var anchorStyles = (0, _react2.css)({
position: 'absolute',
positionVisibility: 'anchors-visible',
zIndex: CONTEXTUAL_MENU_BUTTON_Z_INDEX
});
var FloatingContextualButtonInner = /*#__PURE__*/_react.default.memo(function (props) {
var api = props.api,
editorView = props.editorView,
isContextualMenuOpen = props.isContextualMenuOpen,
mountPoint = props.mountPoint,
scrollableElement = props.scrollableElement,
stickyHeader = props.stickyHeader,
tableWrapper = props.tableWrapper,
targetCellPosition = props.targetCellPosition,
isCellMenuOpenByKeyboard = props.isCellMenuOpenByKeyboard,
formatMessage = props.intl.formatMessage; // : Props & WrappedComponentProps
var _useSharedPluginState = (0, _useSharedPluginStateWithSelector.useSharedPluginStateWithSelector)(api, ['table'], function (states) {
var _states$tableState;
return {
activeTableMenu: (_states$tableState = states.tableState) === null || _states$tableState === void 0 ? void 0 : _states$tableState.activeTableMenu
};
}),
activeTableMenu = _useSharedPluginState.activeTableMenu;
var isCellMenuOpen = (0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true) ? (activeTableMenu === null || activeTableMenu === void 0 ? void 0 : activeTableMenu.type) === 'cell' : isContextualMenuOpen;
var handleClick = function handleClick() {
var state = editorView.state,
dispatch = editorView.dispatch;
if ((0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true)) {
if (!api) {
return;
}
var _getPluginState = (0, _pluginFactory.getPluginState)(state),
currentActiveTableMenu = _getPluginState.activeTableMenu;
api.core.actions.execute(function (_ref) {
var tr = _ref.tr;
(0, _commands.toggleActiveTableMenu)({
type: 'cell',
openedBy: 'mouse'
}, currentActiveTableMenu, api)({
tr: tr
});
return tr;
});
return;
}
// Clicking outside the dropdown handles toggling the menu closed
// (otherwise these two toggles combat each other).
// In the event a user clicks the chevron button again
// That will count as clicking outside the dropdown and
// will be toggled appropriately
if (!isContextualMenuOpen) {
(0, _commands.toggleContextualMenu)()(state, dispatch);
}
};
var domAtPos = editorView.domAtPos.bind(editorView);
var targetCellRef = (0, _utils.findDomRefAtPos)(targetCellPosition, domAtPos);
// Re-renders this component when the cell may have moved, so both FixedButton and Popup
// reposition: Popup recalculates its position whenever it receives new props.
var cellLayoutVersion = (0, _useCellLayoutVersion.useCellLayoutVersion)(targetCellRef);
(0, _react.useEffect)(function () {
if (isCellMenuOpenByKeyboard && !isCellMenuOpen) {
var state = editorView.state,
dispatch = editorView.dispatch;
// open the menu when the keyboard shortcut is pressed
if ((0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true)) {
if (!api) {
return;
}
var _getPluginState2 = (0, _pluginFactory.getPluginState)(state),
currentActiveTableMenu = _getPluginState2.activeTableMenu;
api.core.actions.execute(function (_ref2) {
var tr = _ref2.tr;
(0, _commands.toggleActiveTableMenu)({
type: 'cell',
openedBy: 'keyboard'
}, currentActiveTableMenu, api)({
tr: tr
});
return tr;
});
return;
}
(0, _commands.toggleContextualMenu)()(state, dispatch);
}
}, [isCellMenuOpenByKeyboard, isCellMenuOpen, editorView, api]);
if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
return null;
}
var labelCellOptions = formatMessage(_table.messages.cellOptions);
var button = (0, _react2.jsx)("div", {
css: [
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
(0, _styles.tableFloatingCellButtonStyles)(),
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766
isCellMenuOpen && (0, _styles.tableFloatingCellButtonSelectedStyles)()]
}, (0, _react2.jsx)(_ToolbarButton.default
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
, {
className: _types.TableCssClassName.CONTEXTUAL_MENU_BUTTON,
selected: isCellMenuOpen,
title: labelCellOptions,
keymap: _keymaps.focusToContextMenuTrigger,
onClick: handleClick,
iconBefore: (0, _react2.jsx)(_chevronDown.default, {
label: "",
color: "currentColor",
size: "small"
}),
"aria-label": labelCellOptions,
"aria-expanded": isCellMenuOpen
// Stable anchor used by the Post Office changeboarding spotlight
// (cc-editor-table-cell-menu-changes) to target the cell options button.
,
testId: (0, _expValEquals.expValEquals)('platform_editor_table_menu_updates', 'isEnabled', true) ? 'pm-table-contextual-menu-button' : undefined
}));
var parentSticky = targetCellRef.parentElement && targetCellRef.parentElement.className.indexOf('sticky') > -1;
var parentStickyNative = targetCellRef.parentElement && (tableWrapper === null || tableWrapper === void 0 ? void 0 : tableWrapper.classList.contains(_types.TableCssClassName.TABLE_NODE_WRAPPER_NO_OVERFLOW));
if (parentStickyNative && targetCellRef.nodeName === 'TH' && (0, _stickyHeader.isNativeStickySupported)()) {
var _targetCellRef$parent;
/* We need to default to checking the anchor style because there may be a conflict with the block controls
plugin not using the data attribute value and setting the `anchor-name` style property independently of the data attribute.
*/
var rowAnchorName = (_targetCellRef$parent = targetCellRef.parentElement) === null || _targetCellRef$parent === void 0 ? void 0 : _targetCellRef$parent.style.getPropertyValue('anchor-name');
var colAnchorName = targetCellRef.style.getPropertyValue('anchor-name');
if (rowAnchorName === '') {
var _targetCellRef$parent2;
rowAnchorName = (_targetCellRef$parent2 = targetCellRef.parentElement) === null || _targetCellRef$parent2 === void 0 ? void 0 : _targetCellRef$parent2.dataset.nodeAnchor;
}
if (colAnchorName === '') {
colAnchorName = targetCellRef === null || targetCellRef === void 0 ? void 0 : targetCellRef.dataset.nodeAnchor;
}
if (rowAnchorName && colAnchorName) {
return (0, _react2.jsx)("div", {
css: anchorStyles,
style: _objectSpread({
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
top: "calc(".concat(BUTTON_OFFSET, "px + anchor(").concat(rowAnchorName, " top))"),
right: "calc(".concat(BUTTON_OFFSET, "px + anchor(").concat(colAnchorName, " right))"),
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
positionAnchor: colAnchorName
}, (0, _isExperimentEnabled.isExperimentEnabled)('platform_editor_table_cell_menu_btn_zindex') && {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
zIndex: (0, _stickyHeaderZIndex.getTableZIndexes)().headerButton
}) // need to do this because CSSProperties doesn't have positionAnchor property even though it's a valid CSS property
,
"data-testid": "table-cell-options-anchor-wrapper"
}, button);
}
}
if (stickyHeader && parentSticky && tableWrapper) {
return (0, _react2.jsx)(_FixedButton.default, {
cellLayoutVersion: cellLayoutVersion,
offset: BUTTON_OFFSET,
stickyHeader: stickyHeader,
tableWrapper: tableWrapper,
targetCellPosition: targetCellPosition,
targetCellRef: targetCellRef,
mountTo: tableWrapper,
isContextualMenuOpen: isCellMenuOpen
}, button);
}
return (0, _react2.jsx)(_Popup.default, {
alignX: "right",
alignY: "start",
target: targetCellRef,
mountTo: tableWrapper || mountPoint,
boundariesElement: targetCellRef,
scrollableElement: scrollableElement
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
offset: [BUTTON_OFFSET, -BUTTON_OFFSET],
forcePlacement: true,
allowOutOfBounds: true,
zIndex: _constants.akEditorSmallZIndex
}, button);
});
var FloatingContextualButton = (0, _reactIntl.injectIntl)(FloatingContextualButtonInner);
function _default(props) {
return (0, _react2.jsx)(_errorBoundary.ErrorBoundary, {
component: _enums.ACTION_SUBJECT.FLOATING_CONTEXTUAL_BUTTON,
dispatchAnalyticsEvent: props.dispatchAnalyticsEvent,
fallbackComponent: null
}, (0, _react2.jsx)(FloatingContextualButton
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, props));
}