@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
176 lines (174 loc) • 8.79 kB
JavaScript
/**
* @jsxRuntime classic
* @jsx jsx
*/
import React, { useEffect } from 'react';
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled -- Ignored via go/DSP-18766
import { css, jsx } from '@emotion/react';
import { injectIntl } from 'react-intl-next';
import { ACTION_SUBJECT } from '@atlaskit/editor-common/analytics';
import { ErrorBoundary } from '@atlaskit/editor-common/error-boundary';
import { focusToContextMenuTrigger } from '@atlaskit/editor-common/keymaps';
import { tableMessages as messages } from '@atlaskit/editor-common/messages';
import { Popup } from '@atlaskit/editor-common/ui';
import { ToolbarButton } from '@atlaskit/editor-common/ui-menu';
import { findDomRefAtPos } from '@atlaskit/editor-prosemirror/utils';
import { akEditorSmallZIndex } from '@atlaskit/editor-shared-styles';
import ExpandIcon from '@atlaskit/icon/core/chevron-down';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { toggleContextualMenu } from '../../pm-plugins/commands';
import { isNativeStickySupported } from '../../pm-plugins/utils/sticky-header';
import { TableCssClassName as ClassName } from '../../types';
// Ignored via go/ees005
// eslint-disable-next-line import/no-named-as-default
import FixedButton from './FixedButton';
import { tableFloatingCellButtonSelectedStyles, tableFloatingCellButtonStyles } from './styles';
var BUTTON_OFFSET = 3;
var CONTEXTUAL_MENU_BUTTON_Z_INDEX = 2;
var anchorStyles = css({
position: 'absolute',
positionVisibility: 'anchors-visible',
zIndex: CONTEXTUAL_MENU_BUTTON_Z_INDEX
});
var FloatingContextualButtonInner = /*#__PURE__*/React.memo(function (props) {
var editorView = props.editorView,
isContextualMenuOpen = props.isContextualMenuOpen,
mountPoint = props.mountPoint,
scrollableElement = props.scrollableElement,
stickyHeader = props.stickyHeader,
tableWrapper = props.tableWrapper,
targetCellPosition = props.targetCellPosition,
isCellMenuOpenByKeyboard = props.isCellMenuOpenByKeyboard,
isDragAndDropEnabled = props.isDragAndDropEnabled,
formatMessage = props.intl.formatMessage; // : Props & WrappedComponentProps
var handleClick = function handleClick() {
var state = editorView.state,
dispatch = editorView.dispatch;
// 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) {
toggleContextualMenu()(state, dispatch);
}
};
var domAtPos = editorView.domAtPos.bind(editorView);
var targetCellRef = findDomRefAtPos(targetCellPosition, domAtPos);
useEffect(function () {
if (isCellMenuOpenByKeyboard && !isContextualMenuOpen) {
var state = editorView.state,
dispatch = editorView.dispatch;
// open the menu when the keyboard shortcut is pressed
toggleContextualMenu()(state, dispatch);
}
}, [isCellMenuOpenByKeyboard, isContextualMenuOpen, editorView]);
if (!targetCellRef || !(targetCellRef instanceof HTMLElement)) {
return null;
}
var labelCellOptions = formatMessage(messages.cellOptions);
var button = 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
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
isContextualMenuOpen && tableFloatingCellButtonSelectedStyles()]
}, jsx(ToolbarButton
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766
, {
className: ClassName.CONTEXTUAL_MENU_BUTTON,
selected: isContextualMenuOpen,
title: labelCellOptions,
keymap: focusToContextMenuTrigger,
onClick: handleClick,
iconBefore: jsx(ExpandIcon, {
label: "",
color: "currentColor",
size: "small"
}),
"aria-label": labelCellOptions,
"aria-expanded": isContextualMenuOpen
}));
var parentSticky = targetCellRef.parentElement && targetCellRef.parentElement.className.indexOf('sticky') > -1;
var parentStickyNative = targetCellRef.parentElement && (fg('platform_editor_table_sticky_header_patch_4') ? tableWrapper === null || tableWrapper === void 0 ? void 0 : tableWrapper.classList.contains(ClassName.TABLE_NODE_WRAPPER_NO_OVERFLOW) : targetCellRef.parentElement.classList.contains(ClassName.NATIVE_STICKY));
if (parentStickyNative && targetCellRef.nodeName === 'TH' && isNativeStickySupported(isDragAndDropEnabled !== null && isDragAndDropEnabled !== void 0 ? isDragAndDropEnabled : false) && expValEquals('platform_editor_table_sticky_header_improvements', 'cohort', 'test_with_overflow')) {
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 (!expValEquals('platform_editor_table_sticky_header_patch_9', 'isEnabled', true)) {
return jsx("div", {
css: anchorStyles,
style: {
// 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
} // 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 (rowAnchorName && colAnchorName) {
return jsx("div", {
css: anchorStyles,
style: {
// 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
} // 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 jsx(FixedButton, {
offset: BUTTON_OFFSET,
stickyHeader: stickyHeader,
tableWrapper: tableWrapper,
targetCellPosition: targetCellPosition,
targetCellRef: targetCellRef,
mountTo: tableWrapper,
isContextualMenuOpen: isContextualMenuOpen
}, button);
}
return jsx(Popup, {
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: akEditorSmallZIndex
}, button);
});
var FloatingContextualButton = injectIntl(FloatingContextualButtonInner);
export default function (props) {
return jsx(ErrorBoundary, {
component: ACTION_SUBJECT.FLOATING_CONTEXTUAL_BUTTON,
dispatchAnalyticsEvent: props.dispatchAnalyticsEvent,
fallbackComponent: null
}, jsx(FloatingContextualButton
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, props));
}