UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

913 lines (897 loc) 47.6 kB
import _toArray from "@babel/runtime/helpers/toArray"; import _extends from "@babel/runtime/helpers/extends"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; 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) { _defineProperty(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 import { jsx } from '@emotion/react'; import isEqual from 'lodash/isEqual'; import memoizeOne from 'memoize-one'; import { TableSortOrder as SortOrder } from '@atlaskit/custom-steps'; import { CHANGE_ALIGNMENT_REASON, INPUT_METHOD } from '@atlaskit/editor-common/analytics'; import { DropdownMenuExtensionItems } from '@atlaskit/editor-common/floating-toolbar'; import { addColumnAfter, addRowAfter, backspace, tooltip } from '@atlaskit/editor-common/keymaps'; import commonMessages, { tableMessages as messages } from '@atlaskit/editor-common/messages'; import { isNestedTablesSupported, isSelectionTableNestedInTable } from '@atlaskit/editor-common/nesting'; import { getTableContainerWidth } from '@atlaskit/editor-common/node-width'; import { areToolbarFlagsEnabled } from '@atlaskit/editor-common/toolbar-flag-check'; import { DEFAULT_BORDER_COLOR, cellBackgroundColorPalette } from '@atlaskit/editor-common/ui-color'; import { closestElement, getChildrenInfo as _getChildrenInfo, getNodeName, isReferencedSource } from '@atlaskit/editor-common/utils'; import { findParentDomRefOfType } from '@atlaskit/editor-prosemirror/utils'; import { akEditorFloatingPanelZIndex } from '@atlaskit/editor-shared-styles'; import { shortcutStyle } from '@atlaskit/editor-shared-styles/shortcut'; import { Rect, TableMap } from '@atlaskit/editor-tables/table-map'; import { findCellRectClosestToPos, findTable, getSelectionRect, isSelectionType, splitCell } from '@atlaskit/editor-tables/utils'; import AlignImageCenterIcon from '@atlaskit/icon/core/align-image-center'; import AlignImageLeftIcon from '@atlaskit/icon/core/align-image-left'; import CopyIcon from '@atlaskit/icon/core/copy'; import CustomizeIcon from '@atlaskit/icon/core/customize'; import DeleteIcon from '@atlaskit/icon/core/delete'; import TableColumnsDistributeIcon from '@atlaskit/icon/core/table-columns-distribute'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { clearHoverSelection, hoverColumns, hoverMergedCells, hoverRows, hoverTable, removeDescendantNodes } from '../pm-plugins/commands'; import { deleteColumnsWithAnalytics, deleteRowsWithAnalytics, deleteTableWithAnalytics, distributeColumnsWidthsWithAnalytics, emptyMultipleCellsWithAnalytics, insertColumnWithAnalytics, insertRowWithAnalytics, mergeCellsWithAnalytics, setColorWithAnalytics, setTableAlignmentWithAnalytics, sortColumnWithAnalytics, splitCellWithAnalytics, toggleFixedColumnWidthsOptionAnalytics, toggleHeaderColumnWithAnalytics, toggleHeaderRowWithAnalytics, toggleNumberColumnWithAnalytics, wrapTableInExpandWithAnalytics } from '../pm-plugins/commands/commands-with-analytics'; import { getPluginState as getDragDropPluginState } from '../pm-plugins/drag-and-drop/plugin-factory'; import { getPluginState } from '../pm-plugins/plugin-factory'; import { pluginKey as tableResizingPluginKey } from '../pm-plugins/table-resizing/plugin-key'; import { getStaticTableScalingPercent } from '../pm-plugins/table-resizing/utils/misc'; import { getNewResizeStateFromSelectedColumns } from '../pm-plugins/table-resizing/utils/resize-state'; import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width'; import { canMergeCells } from '../pm-plugins/transforms/merge'; import { normaliseAlignment } from '../pm-plugins/utils/alignment'; import { isTableNested } from '../pm-plugins/utils/nodes'; import { getSelectedColumnIndexes, getSelectedRowIndexes } from '../pm-plugins/utils/selection'; import { getMergedCellsPositions } from '../pm-plugins/utils/table'; import { TableCssClassName } from '../types'; import { FloatingAlignmentButtons } from './FloatingAlignmentButtons/FloatingAlignmentButtons'; export var getToolbarMenuConfig = function getToolbarMenuConfig(config, state, _ref, editorAnalyticsAPI) { var formatMessage = _ref.formatMessage; var isTableScalingWithFixedColumnWidthsOptionShown = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; var areTableColumnWidthsFixed = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; var optionItem = 'item-checkbox'; var options = [{ id: 'editor.table.lockColumnWidths', title: formatMessage(messages.lockColumnWidths), onClick: toggleFixedColumnWidthsOptionAnalytics(editorAnalyticsAPI, INPUT_METHOD.FLOATING_TB), selected: areTableColumnWidthsFixed, hidden: !isTableScalingWithFixedColumnWidthsOptionShown, domItemOptions: { type: optionItem } }, { id: 'editor.table.headerRow', title: formatMessage(messages.headerRow), onClick: toggleHeaderRowWithAnalytics(editorAnalyticsAPI), selected: state.isHeaderRowEnabled, hidden: !config.allowHeaderRow, domItemOptions: { type: optionItem } }, { id: 'editor.table.headerColumn', title: formatMessage(messages.headerColumn), onClick: toggleHeaderColumnWithAnalytics(editorAnalyticsAPI), selected: state.isHeaderColumnEnabled, hidden: !config.allowHeaderColumn, domItemOptions: { type: optionItem } }, { id: 'editor.table.numberedColumn', title: formatMessage(messages.numberedRows), onClick: toggleNumberColumnWithAnalytics(editorAnalyticsAPI), selected: state.isNumberColumnEnabled, hidden: !config.allowNumberColumn, domItemOptions: { type: optionItem } }, { id: 'editor.table.collapseTable', title: formatMessage(messages.collapseTable), onClick: wrapTableInExpandWithAnalytics(editorAnalyticsAPI), selected: !!state.isTableCollapsed, disabled: !state.canCollapseTable, hidden: !config.allowCollapse, domItemOptions: { type: optionItem } }]; var tableOptionsDropdownWidth = isTableScalingWithFixedColumnWidthsOptionShown ? 192 : undefined; if (state.isDragAndDropEnabled) { return { id: 'editor.table.tableOptions', type: 'dropdown', testId: 'table_options', iconBefore: CustomizeIcon, title: formatMessage(messages.tableOptions), hidden: options.every(function (option) { return option.hidden; }), options: options, dropdownWidth: tableOptionsDropdownWidth }; } else { return { id: 'editor.table.tableOptions', type: 'dropdown', testId: 'table_options', title: formatMessage(messages.tableOptions), hidden: options.every(function (option) { return option.hidden; }), options: options, dropdownWidth: tableOptionsDropdownWidth }; } }; // Added these options for mobile. Mobile bridge translates this menu and // relay it to the native mobile. Native mobile displays the menu // with native widgets. It's enabled via a plugin config. export var getToolbarCellOptionsConfig = function getToolbarCellOptionsConfig(editorState, editorView, initialSelectionRect, _ref2, getEditorContainerWidth, api, editorAnalyticsAPI) { var _pluginState$pluginCo, _pluginState$pluginCo2; var formatMessage = _ref2.formatMessage; var isTableScalingEnabled = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; var isTableFixedColumnWidthsOptionEnabled = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false; var shouldUseIncreasedScalingPercent = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false; var isCommentEditor = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : false; var isLimitedModeEnabled = arguments.length > 11 && arguments[11] !== undefined ? arguments[11] : false; var top = initialSelectionRect.top, bottom = initialSelectionRect.bottom, right = initialSelectionRect.right, left = initialSelectionRect.left; var numberOfColumns = right - left; var numberOfRows = bottom - top; var pluginState = getPluginState(editorState); var options = [{ id: 'editor.table.insertColumn', title: formatMessage(messages.insertColumn), onClick: function onClick(state, dispatch, view) { var selectionRect = getClosestSelectionRect(state); var index = selectionRect === null || selectionRect === void 0 ? void 0 : selectionRect.right; if (index) { insertColumnWithAnalytics(api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(INPUT_METHOD.FLOATING_TB, index)(state, dispatch, view); } return true; }, selected: false, disabled: false, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 elemAfter: jsx("div", { css: shortcutStyle }, tooltip(addColumnAfter)) }, { id: 'editor.table.insertRow', title: formatMessage(messages.insertRow), onClick: function onClick(state, dispatch) { var selectionRect = getClosestSelectionRect(state); var index = selectionRect === null || selectionRect === void 0 ? void 0 : selectionRect.bottom; if (index) { insertRowWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, { index: index, moveCursorToInsertedRow: true })(state, dispatch); } return true; }, selected: false, disabled: false, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 elemAfter: jsx("div", { css: shortcutStyle }, tooltip(addRowAfter)) }, { id: 'editor.table.removeColumns', title: formatMessage(messages.removeColumns, { 0: numberOfColumns }), onClick: function onClick(state, dispatch, view) { var selectionRect = getClosestSelectionRect(state); if (selectionRect) { deleteColumnsWithAnalytics(editorAnalyticsAPI, api, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor)(INPUT_METHOD.FLOATING_TB, selectionRect)(state, dispatch, view); } return true; }, onFocus: highlightColumnsHandler, onBlur: clearHoverSelection(), onMouseOver: highlightColumnsHandler, onMouseLeave: clearHoverSelection(), selected: false, disabled: false }, { id: 'editor.table.removeRows', title: formatMessage(messages.removeRows, { 0: numberOfRows }), onClick: function onClick(state, dispatch) { var selectionRect = getClosestSelectionRect(state); if (selectionRect) { deleteRowsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, selectionRect, false)(state, dispatch); } return true; }, onFocus: highlightRowsHandler, onBlur: clearHoverSelection(), onMouseOver: highlightRowsHandler, onMouseLeave: clearHoverSelection(), selected: false, disabled: false }]; if (pluginState.pluginConfig.allowMergeCells) { options.push({ id: 'editor.table.mergeCells', title: formatMessage(messages.mergeCells), onClick: mergeCellsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB), selected: false, disabled: !canMergeCells(editorState.tr) }, { id: 'editor.table.splitCell', title: formatMessage(messages.splitCell), onClick: splitCellWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB), selected: false, disabled: !splitCell(editorState) }); } if (pluginState !== null && pluginState !== void 0 && (_pluginState$pluginCo = pluginState.pluginConfig) !== null && _pluginState$pluginCo !== void 0 && _pluginState$pluginCo.allowDistributeColumns) { var wouldChange = true; // Default to enabled - show the button. var newResizeStateWithAnalytics; // Performance optimization: Skip expensive getTableScalingPercent() DOM query when limited mode is enabled. // This avoids layout reflows on every transaction. Instead, button stays enabled and calculates on-demand when clicked. if (!isLimitedModeEnabled && !expValEquals('platform_editor_table_toolbar_perf_fix', 'isEnabled', true)) { var _newResizeStateWithAn, _newResizeStateWithAn2; newResizeStateWithAnalytics = editorView ? getNewResizeStateFromSelectedColumns(initialSelectionRect, editorState, editorView.domAtPos.bind(editorView), getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor) : undefined; wouldChange = (_newResizeStateWithAn = (_newResizeStateWithAn2 = newResizeStateWithAnalytics) === null || _newResizeStateWithAn2 === void 0 ? void 0 : _newResizeStateWithAn2.changed) !== null && _newResizeStateWithAn !== void 0 ? _newResizeStateWithAn : false; } var distributeColumnWidths = function distributeColumnWidths(state, dispatch, view) { // When optimization is enabled, calculate on-demand when clicked if (isLimitedModeEnabled || expValEquals('platform_editor_table_toolbar_perf_fix', 'isEnabled', true)) { if (view) { var resizeState = getNewResizeStateFromSelectedColumns(initialSelectionRect, state, view.domAtPos.bind(view), getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor); if (resizeState) { distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI, api)(INPUT_METHOD.FLOATING_TB, resizeState)(state, dispatch); return true; } } return false; } else { // Original behavior: use pre-calculated state if (newResizeStateWithAnalytics) { distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI, api)(INPUT_METHOD.FLOATING_TB, newResizeStateWithAnalytics)(state, dispatch); return true; } return false; } }; options.push({ id: 'editor.table.distributeColumns', title: formatMessage(messages.distributeColumns), onClick: distributeColumnWidths, selected: false, disabled: !wouldChange }); } if (pluginState !== null && pluginState !== void 0 && (_pluginState$pluginCo2 = pluginState.pluginConfig) !== null && _pluginState$pluginCo2 !== void 0 && _pluginState$pluginCo2.allowColumnSorting) { var hasMergedCellsInTable = getMergedCellsPositions(editorState.tr).length > 0; var warning = hasMergedCellsInTable ? formatMessage(messages.canNotSortTable) : undefined; options.push({ id: 'editor.table.sortColumnAsc', title: formatMessage(messages.sortColumnASC), onMouseOver: function onMouseOver(state, dispatch) { if (getMergedCellsPositions(state.tr).length !== 0) { hoverMergedCells()(state, dispatch); return true; } return false; }, onMouseOut: function onMouseOut(state, dispatch) { clearHoverSelection()(state, dispatch); return true; }, onClick: function onClick(state, dispatch) { sortColumnWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, initialSelectionRect.left, SortOrder.ASC)(state, dispatch); return true; }, selected: false, disabled: hasMergedCellsInTable, tooltip: warning }); options.push({ id: 'editor.table.sortColumnDesc', title: formatMessage(messages.sortColumnDESC), onMouseOver: function onMouseOver(state, dispatch) { if (getMergedCellsPositions(state.tr).length !== 0) { hoverMergedCells()(state, dispatch); return true; } return false; }, onMouseOut: function onMouseOut(state, dispatch) { clearHoverSelection()(state, dispatch); return true; }, onClick: function onClick(state, dispatch) { sortColumnWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, initialSelectionRect.left, SortOrder.DESC)(state, dispatch); return true; }, selected: false, disabled: hasMergedCellsInTable, tooltip: warning }); } options.push({ id: 'editor.table.clearCells', title: formatMessage(messages.clearCells, { 0: Math.max(numberOfColumns, numberOfRows) }), onClick: function onClick(state, dispatch) { var _getPluginState = getPluginState(state), targetCellPosition = _getPluginState.targetCellPosition; emptyMultipleCellsWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, targetCellPosition)(state, dispatch); return true; }, selected: false, disabled: false, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/design-system/consistent-css-prop-usage -- Ignored via go/DSP-18766 elemAfter: jsx("div", { css: shortcutStyle }, tooltip(backspace)) }); return { id: 'editor.table.cellOptions', testId: 'cell_options', type: 'dropdown', title: formatMessage(messages.cellOptions), options: options, // Increased dropdown item width to prevent labels from being truncated dropdownWidth: 230, showSelected: false }; }; export var getClosestSelectionRect = function getClosestSelectionRect(state) { var selection = state.selection; return isSelectionType(selection, 'cell') ? // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion getSelectionRect(selection) : findCellRectClosestToPos(selection.$from); }; var getClosestSelectionOrTableRect = function getClosestSelectionOrTableRect(state) { var selection = state.selection; var tableObject = findTable(state.selection); if (!tableObject) { return; } var map = TableMap.get(tableObject.node); var tableRect = new Rect(0, 0, map.width, map.height); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return isSelectionType(selection, 'cell') ? getSelectionRect(selection) : tableRect; }; // Memoize the expensive DOM queries (querySelector, closestElement) separately // Cache key is the parent DOM node reference - stays same when typing in same cell var getTableWrapperFromParentImpl = function getTableWrapperFromParentImpl(parent) { if (!parent) { return undefined; } // These are the expensive DOM operations var tableRef = // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting parent.querySelector('table') || undefined; if (!tableRef) { return undefined; } return closestElement(tableRef, ".".concat(TableCssClassName.TABLE_NODE_WRAPPER)) || undefined; }; // Create memoized version ONCE - reused across all calls var getMemoizedTableWrapperFromParent = memoizeOne(getTableWrapperFromParentImpl); export var getToolbarConfig = function getToolbarConfig(getEditorContainerWidth, api, editorAnalyticsAPI, getEditorView, options) { var isTableFixedColumnWidthsOptionEnabled = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; var shouldUseIncreasedScalingPercent = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false; return function (config) { return function (state, intl) { var tableObject = findTable(state.selection); var pluginState = getPluginState(state); var resizeState = tableResizingPluginKey.getState(state); var tableWidthState = tableWidthPluginKey.getState(state); var isTableScalingEnabled = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) || false; var nodeType = state.schema.nodes.table; var toolbarTitle = 'Table floating controls'; var areAnyNewToolbarFlagsEnabled = areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar)); if (editorExperiment('platform_editor_controls', 'variant1')) { var _api$editorViewMode; var isDragHandleMenuOpened = false; var isTableRowOrColumnDragged = false; if (options !== null && options !== void 0 && options.dragAndDropEnabled) { var _getDragDropPluginSta = getDragDropPluginState(state), _getDragDropPluginSta2 = _getDragDropPluginSta.isDragMenuOpen, isDragMenuOpen = _getDragDropPluginSta2 === void 0 ? false : _getDragDropPluginSta2, _getDragDropPluginSta3 = _getDragDropPluginSta.isDragging, isDragging = _getDragDropPluginSta3 === void 0 ? false : _getDragDropPluginSta3; isDragHandleMenuOpened = isDragMenuOpen; isTableRowOrColumnDragged = isDragging; } var isTableOrColumnResizing = !!(resizeState !== null && resizeState !== void 0 && resizeState.dragging || tableWidthState !== null && tableWidthState !== void 0 && tableWidthState.resizing); var isTableMenuOpened = pluginState.isContextualMenuOpen || isDragHandleMenuOpened; var isTableState = isTableRowOrColumnDragged || isTableOrColumnResizing || isTableMenuOpened; var isViewMode = (api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode) === 'view'; // Note: when focus is in codeblocks, pluginState.editorHasFocus is false, so the codeblocks toolbar // won't be suppressed. var shouldSuppressAllToolbars = isTableState && pluginState.editorHasFocus && !isViewMode; if (shouldSuppressAllToolbars) { return { title: toolbarTitle, items: [], nodeType: nodeType }; } } // We don't want to show floating toolbar while resizing the table var isWidthResizing = tableWidthState === null || tableWidthState === void 0 ? void 0 : tableWidthState.resizing; if (tableObject && pluginState.editorHasFocus && !isWidthResizing) { var _api$limitedMode$shar, _api$limitedMode, _api$extension, _api$extension2; var isNested = pluginState.tablePos && isTableNested(state, pluginState.tablePos); var isTableScalingWithFixedColumnWidthsOptionShown = isTableScalingEnabled && isTableFixedColumnWidthsOptionEnabled && !isNested; var areTableColumWidthsFixed = tableObject.node.attrs.displayMode === 'fixed'; var editorView = getEditorView(); var getDomRef = expValEquals('platform_editor_table_toolbar_perf_fix', 'isEnabled', true) ? function (editorView) { var domAtPos = editorView.domAtPos.bind(editorView); var parent = findParentDomRefOfType(nodeType, domAtPos)(state.selection); return getMemoizedTableWrapperFromParent(parent); } : function (editorView) { var element; var domAtPos = editorView.domAtPos.bind(editorView); var parent = findParentDomRefOfType(nodeType, domAtPos)(state.selection); if (parent) { var tableRef = // Ignored via go/ees005 // eslint-disable-next-line @atlaskit/editor/no-as-casting parent.querySelector('table') || undefined; if (tableRef) { element = closestElement(tableRef, ".".concat(TableCssClassName.TABLE_NODE_WRAPPER)) || undefined; } } return element; }; var menu = getToolbarMenuConfig(config, pluginState, intl, editorAnalyticsAPI, isTableScalingWithFixedColumnWidthsOptionShown, areTableColumWidthsFixed); var alignmentMenu = config.allowTableAlignment && !isNested ? getAlignmentOptionsConfig(state, intl, editorAnalyticsAPI, getEditorContainerWidth, editorView, shouldUseIncreasedScalingPercent, areAnyNewToolbarFlagsEnabled, options === null || options === void 0 ? void 0 : options.fullWidthEnabled, options === null || options === void 0 ? void 0 : options.isCommentEditor) : []; var isLimitedModeEnabled = (_api$limitedMode$shar = api === null || api === void 0 || (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode === void 0 ? void 0 : _api$limitedMode.enabled) !== null && _api$limitedMode$shar !== void 0 ? _api$limitedMode$shar : false; var cellItems = pluginState.isDragAndDropEnabled ? [] : getCellItems(state, editorView, intl, getEditorContainerWidth, api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, options === null || options === void 0 ? void 0 : options.isCommentEditor, isLimitedModeEnabled); var columnSettingsItems = pluginState.isDragAndDropEnabled ? getColumnSettingItems(state, editorView, intl, getEditorContainerWidth, api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, options === null || options === void 0 ? void 0 : options.isCommentEditor, isLimitedModeEnabled) : []; var colorPicker = !areAnyNewToolbarFlagsEnabled ? getColorPicker(state, menu, intl, editorAnalyticsAPI, getEditorView) : []; // Check if we need to show confirm dialog for delete button var confirmDialog; if (isReferencedSource(state, tableObject.node)) { var localSourceName = intl.formatMessage(messages.unnamedSource); confirmDialog = function confirmDialog() { return { title: intl.formatMessage(messages.deleteElementTitle), okButtonLabel: intl.formatMessage(messages.confirmDeleteLinkedModalOKButton), message: intl.formatMessage(messages.confirmDeleteLinkedModalMessage, { nodeName: getNodeName(state, tableObject.node) || localSourceName }), messagePrefix: intl.formatMessage(messages.confirmDeleteLinkedModalMessagePrefix), isReferentialityDialog: true, getChildrenInfo: function getChildrenInfo() { return _getChildrenInfo(state, tableObject.node); }, checkboxLabel: intl.formatMessage(messages.confirmModalCheckboxLabel), onConfirm: function onConfirm() { var isChecked = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; return clickWithCheckboxHandler(isChecked, tableObject.node); } }; }; } var deleteButton = { id: 'editor.table.delete', type: 'button', appearance: 'danger', icon: DeleteIcon, onClick: deleteTableWithAnalytics(editorAnalyticsAPI), disabled: !!resizeState && !!resizeState.dragging, onMouseEnter: hoverTable(true), onFocus: hoverTable(true), onBlur: clearHoverSelection(), onMouseLeave: clearHoverSelection(), title: intl.formatMessage(commonMessages.remove), focusEditoronEnter: true, confirmDialog: confirmDialog }; var copyButton = { type: 'copy-button', supportsViewMode: true, items: [{ state: state, formatMessage: intl.formatMessage, nodeType: nodeType, onMouseEnter: hoverTable(false, true), onMouseLeave: clearHoverSelection(), onFocus: hoverTable(false, true), onBlur: clearHoverSelection() }] }; var isNestedTable = isNestedTablesSupported(state.schema) && isSelectionTableNestedInTable(state); var hoverTableProps = function hoverTableProps(isInDanger, isSelected) { return { onMouseEnter: hoverTable(isInDanger, isSelected), onMouseLeave: clearHoverSelection(), onFocus: hoverTable(isInDanger, isSelected), onBlur: clearHoverSelection() }; }; // testId is required to show focus on trigger button on ESC key press // see hideOnEsc in platform/packages/editor/editor-plugin-floating-toolbar/src/ui/Dropdown.tsx var overflowDropdownTestId = 'table-overflow-dropdown-trigger'; var extensionState = api === null || api === void 0 || (_api$extension = api.extension) === null || _api$extension === void 0 || (_api$extension = _api$extension.sharedState) === null || _api$extension === void 0 ? void 0 : _api$extension.currentState(); var extensionApi = api === null || api === void 0 || (_api$extension2 = api.extension) === null || _api$extension2 === void 0 ? void 0 : _api$extension2.actions.api(); return { title: toolbarTitle, getDomRef: getDomRef, nodeType: nodeType, offset: [0, 18], absoluteOffset: { top: -6 }, zIndex: akEditorFloatingPanelZIndex + 1, // Place the context menu slightly above the others items: [menu].concat(_toConsumableArray(!areAnyNewToolbarFlagsEnabled ? [separator(menu.hidden)] : []), _toConsumableArray(alignmentMenu), _toConsumableArray(!areAnyNewToolbarFlagsEnabled ? [separator(alignmentMenu.length === 0)] : []), _toConsumableArray(cellItems), _toConsumableArray(columnSettingsItems), _toConsumableArray(colorPicker), _toConsumableArray(!areAnyNewToolbarFlagsEnabled ? [{ type: 'extensions-placeholder', separator: 'end' }, copyButton, { type: 'separator' }, deleteButton] : [areAnyNewToolbarFlagsEnabled && { type: 'separator', fullHeight: true }, { type: 'overflow-dropdown', testId: overflowDropdownTestId, dropdownWidth: 220, options: [{ type: 'custom', fallback: [], render: function render(editorView, dropdownOptions) { if (!editorView) { return null; } if (!extensionApi || !(extensionState !== null && extensionState !== void 0 && extensionState.extensionProvider)) { return null; } return jsx(DropdownMenuExtensionItems, { node: tableObject.node, editorView: editorView // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , extension: { extensionProvider: extensionState !== null && extensionState !== void 0 && extensionState.extensionProvider ? Promise.resolve(extensionState.extensionProvider) : undefined, extensionApi: extensionApi }, dropdownOptions: dropdownOptions // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , disabled: function disabled(key) { return isNestedTable && ['referentiality:connections', 'chart:insert-chart'].includes(key); }, areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled }); } }].concat(_toConsumableArray(extensionApi && extensionState !== null && extensionState !== void 0 && extensionState.extensionProvider && !areAnyNewToolbarFlagsEnabled ? [{ type: 'separator' }] : []), [_objectSpread({ title: intl.formatMessage(commonMessages.copyToClipboard), onClick: function onClick() { var _api$core, _api$floatingToolbar; api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute( // @ts-ignore api === null || api === void 0 || (_api$floatingToolbar = api.floatingToolbar) === null || _api$floatingToolbar === void 0 ? void 0 : _api$floatingToolbar.commands.copyNode(nodeType, INPUT_METHOD.FLOATING_TB)); return true; }, icon: jsx(CopyIcon, { label: intl.formatMessage(commonMessages.copyToClipboard) }) }, hoverTableProps(false, true)), _objectSpread(_objectSpread({ title: intl.formatMessage(commonMessages.delete), onClick: deleteTableWithAnalytics(editorAnalyticsAPI), icon: jsx(DeleteIcon, { label: intl.formatMessage(commonMessages.delete) }) }, hoverTableProps(true)), {}, { confirmDialog: confirmDialog })]) }])), scrollable: true }; } return; }; }; }; var separator = function separator(hidden) { return { type: 'separator', hidden: hidden }; }; var getCellItems = function getCellItems(state, view, _ref3, getEditorContainerWidth, api, editorAnalyticsAPI) { var formatMessage = _ref3.formatMessage; var isTableScalingEnabled = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false; var isTableFixedColumnWidthsOptionEnabled = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; var shouldUseIncreasedScalingPercent = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false; var isCommentEditor = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false; var isLimitedModeEnabled = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : false; var initialSelectionRect = getClosestSelectionRect(state); if (initialSelectionRect) { var cellOptions = getToolbarCellOptionsConfig(state, view, initialSelectionRect, { formatMessage: formatMessage }, getEditorContainerWidth, api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor, isLimitedModeEnabled); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return [cellOptions, separator(cellOptions.hidden)]; } return []; }; var getDistributeConfig = function getDistributeConfig(getEditorContainerWidth, api, editorAnalyticsAPI) { var isTableScalingEnabled = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; var isTableFixedColumnWidthsOptionEnabled = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; var isCommentEditor = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : false; return function (state, dispatch, editorView) { var selectionOrTableRect = getClosestSelectionOrTableRect(state); if (!editorView || !selectionOrTableRect) { return false; } var newResizeStateWithAnalytics = getNewResizeStateFromSelectedColumns(selectionOrTableRect, state, editorView.domAtPos.bind(editorView), getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor); if (newResizeStateWithAnalytics) { distributeColumnsWidthsWithAnalytics(editorAnalyticsAPI, api)(INPUT_METHOD.FLOATING_TB, newResizeStateWithAnalytics)(state, dispatch); return true; } return false; }; }; // this create the button group for distribute column and also fixed column width // fixed column button should be in this function call in the future var getColumnSettingItems = function getColumnSettingItems(editorState, editorView, _ref4, getEditorContainerWidth, api, editorAnalyticsAPI) { var _pluginState$pluginCo3; var formatMessage = _ref4.formatMessage; var isTableScalingEnabled = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : false; var isTableFixedColumnWidthsOptionEnabled = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false; var isCommentEditor = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false; var isLimitedModeEnabled = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : false; var pluginState = getPluginState(editorState); var items = []; var wouldChange = true; // Default to enabled - show the button. var newResizeStateWithAnalytics; if (expValEquals('platform_editor_table_toolbar_perf_fix', 'isEnabled', true)) { if (!editorView) { return []; } } else { var selectionOrTableRect = getClosestSelectionOrTableRect(editorState); if (!selectionOrTableRect || !editorView) { return []; } // Performance optimization: Skip expensive getTableScalingPercent() DOM query when limited mode is enabled. // This avoids layout reflows on every transaction. Instead, button stays enabled and calculates on-demand when clicked. if (!isLimitedModeEnabled) { var _newResizeStateWithAn3, _newResizeStateWithAn4; newResizeStateWithAnalytics = getNewResizeStateFromSelectedColumns(selectionOrTableRect, editorState, editorView.domAtPos.bind(editorView), getEditorContainerWidth, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor); wouldChange = (_newResizeStateWithAn3 = (_newResizeStateWithAn4 = newResizeStateWithAnalytics) === null || _newResizeStateWithAn4 === void 0 ? void 0 : _newResizeStateWithAn4.changed) !== null && _newResizeStateWithAn3 !== void 0 ? _newResizeStateWithAn3 : false; } } if (pluginState !== null && pluginState !== void 0 && (_pluginState$pluginCo3 = pluginState.pluginConfig) !== null && _pluginState$pluginCo3 !== void 0 && _pluginState$pluginCo3.allowDistributeColumns && pluginState.isDragAndDropEnabled) { items.push({ id: 'editor.table.distributeColumns', type: 'button', title: formatMessage(messages.distributeColumns), icon: function icon() { return jsx(TableColumnsDistributeIcon, { spacing: 'spacious', label: '' }); }, onClick: function onClick(state, dispatch, view) { return getDistributeConfig(getEditorContainerWidth, api, editorAnalyticsAPI, isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, isCommentEditor)(state, dispatch, view); }, disabled: !wouldChange }); } if (items.length !== 0 && !areToolbarFlagsEnabled(Boolean(api === null || api === void 0 ? void 0 : api.toolbar))) { items.push({ type: 'separator' }); } return items; }; var getColorPicker = function getColorPicker(state, menu, _ref5, editorAnalyticsAPI, getEditorView) { var _node$attrs; var formatMessage = _ref5.formatMessage; var _getPluginState2 = getPluginState(state), targetCellPosition = _getPluginState2.targetCellPosition, pluginConfig = _getPluginState2.pluginConfig; if (!pluginConfig.allowBackgroundColor) { return []; } var node = targetCellPosition ? state.doc.nodeAt(targetCellPosition) : undefined; var currentBackground = (node === null || node === void 0 || (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.background) || '#ffffff'; var defaultPalette = cellBackgroundColorPalette.find(function (item) { return item.value === currentBackground; }) || { // eslint-disable-next-line @atlassian/i18n/no-literal-string-in-object label: 'Custom', value: currentBackground, border: DEFAULT_BORDER_COLOR }; return [{ id: 'editor.table.colorPicker', title: formatMessage(messages.cellBackground), type: 'select', isAriaExpanded: true, selectType: 'color', defaultValue: defaultPalette, options: cellBackgroundColorPalette, returnEscToButton: true, // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any onChange: function onChange(option) { return setColorWithAnalytics(editorAnalyticsAPI)(INPUT_METHOD.FLOATING_TB, option.value, getEditorView()); } }, separator(menu.hidden)]; }; var clickWithCheckboxHandler = function clickWithCheckboxHandler(isChecked, node, editorAnalyticsAPI) { return function (state, dispatch) { if (!node) { return false; } if (!isChecked) { return deleteTableWithAnalytics(editorAnalyticsAPI)(state, dispatch); } else { removeDescendantNodes(node)(state, dispatch); } return true; }; }; var highlightRowsHandler = function highlightRowsHandler(state, dispatch) { var selectionRect = getClosestSelectionRect(state); if (selectionRect) { hoverRows(getSelectedRowIndexes(selectionRect), true)(state, dispatch); return true; } return false; }; var highlightColumnsHandler = function highlightColumnsHandler(state, dispatch) { var selectionRect = getClosestSelectionRect(state); if (selectionRect) { hoverColumns(getSelectedColumnIndexes(selectionRect), true)(state, dispatch); return true; } return false; }; var getAlignmentOptionsConfig = function getAlignmentOptionsConfig(editorState, _ref6, editorAnalyticsAPI, getEditorContainerWidth, editorView, shouldUseIncreasedScalingPercent, areAnyNewToolbarFlagsEnabled, isFullWidthEditor, isCommentEditor) { var formatMessage = _ref6.formatMessage; var tableObject = findTable(editorState.selection); if (!tableObject) { return []; } var alignmentIcons = [{ id: 'editor.table.alignLeft', value: 'align-start', icon: function icon() { return jsx(AlignImageLeftIcon, { color: "currentColor", spacing: "spacious", label: "table-align-start-icon" }); } }, { id: 'editor.table.alignCenter', value: 'center', icon: function icon() { return jsx(AlignImageCenterIcon, { color: "currentColor", spacing: "spacious", label: "table-align-center-icon" }); } }]; // eslint-disable-next-line @typescript-eslint/no-explicit-any var layoutToMessages = { center: messages.alignTableCenter, 'align-start': messages.alignTableLeft }; var alignmentButtons = alignmentIcons.map(function (alignmentIcon) { var id = alignmentIcon.id, value = alignmentIcon.value, icon = alignmentIcon.icon; var currentLayout = tableObject.node.attrs.layout; var shouldDisableLayoutOption = expValEquals('platform_editor_table_toolbar_perf_fix', 'isEnabled', true) ? getMemoizedIsLayoutOptionDisabled(tableObject.node, getEditorContainerWidth, editorView !== null, shouldUseIncreasedScalingPercent, isFullWidthEditor) : isLayoutOptionDisabled(tableObject.node, getEditorContainerWidth, editorView, shouldUseIncreasedScalingPercent, isFullWidthEditor); return _objectSpread({ id: id, type: 'button', icon: icon, title: formatMessage(layoutToMessages[value]), selected: normaliseAlignment(currentLayout) === value, onClick: setTableAlignmentWithAnalytics(editorAnalyticsAPI, isCommentEditor || false)(value, currentLayout, INPUT_METHOD.FLOATING_TB, CHANGE_ALIGNMENT_REASON.TOOLBAR_OPTION_CHANGED) }, shouldDisableLayoutOption && { disabled: value !== 'center' }); }); var alignmentItemOptions = { render: function render(props) { return jsx(FloatingAlignmentButtons, _extends({ alignmentButtons: alignmentButtons // Ignored via go/ees005 // eslint-disable-next-line react/jsx-props-no-spreading }, props, { areAnyNewToolbarFlagsEnabled: areAnyNewToolbarFlagsEnabled })); }, width: 74, height: 32 }; var selectedAlignmentIcon = getSelectedAlignmentIcon(alignmentIcons, tableObject.node); var alignmentToolbarItem = [{ id: 'table-layout', testId: 'table-layout-dropdown', type: 'dropdown', options: alignmentItemOptions, title: formatMessage(messages.tableAlignmentOptions), icon: selectedAlignmentIcon === null || selectedAlignmentIcon === void 0 ? void 0 : selectedAlignmentIcon.icon }]; return alignmentToolbarItem; }; var getSelectedAlignmentIcon = function getSelectedAlignmentIcon(alignmentIcons, selectedNode) { var selectedAlignment = selectedNode.attrs.layout; return alignmentIcons.find(function (icon) { return icon.value === normaliseAlignment(selectedAlignment); }); }; var isLayoutOptionDisabledImpl = function isLayoutOptionDisabledImpl(selectedNode, getEditorContainerWidth, hasEditorView, shouldUseIncreasedScalingPercent, isFullWidthEditor) { var _getEditorContainerWi = getEditorContainerWidth(), lineLength = _getEditorContainerWi.lineLength; var tableContainerWidth = getTableContainerWidth(selectedNode); // table may be scaled, use the scale percent to calculate the table width if (hasEditorView) { var tableWrapperWidth = tableContainerWidth; var scalePercent = getStaticTableScalingPercent(selectedNode, tableWrapperWidth, shouldUseIncreasedScalingPercent); tableContainerWidth = tableContainerWidth * scalePercent; } // If fixed-width editor, we disable 'left-alignment' when table width is 760px. // tableContainerWidth +1 here because tableContainerWidth is 759 in fixed-width editor if (selectedNode && !isFullWidthEditor && lineLength && tableContainerWidth + 1 >= lineLength) { return true; } return false; }; var getMemoizedIsLayoutOptionDisabled = memoizeOne(isLayoutOptionDisabledImpl, function (_ref7, _ref8) { var _ref9 = _toArray(_ref7), prevNode = _ref9[0], prevRest = _ref9.slice(1); var _ref0 = _toArray(_ref8), nextNode = _ref0[0], nextRest = _ref0.slice(1); // Only node needs special comparison (attrs only), rest use reference equality var nodeEqual = isEqual(prevNode.attrs, nextNode.attrs); var restEqual = prevRest.every(function (val, idx) { return val === nextRest[idx]; }); return nodeEqual && restEqual; }); var isLayoutOptionDisabled = function isLayoutOptionDisabled(selectedNode, getEditorContainerWidth, editorView, shouldUseIncreasedScalingPercent, isFullWidthEditor) { var _getEditorContainerWi2 = getEditorContainerWidth(), lineLength = _getEditorContainerWi2.lineLength; var tableContainerWidth = getTableContainerWidth(selectedNode); // table may be scaled, use the scale percent to calculate the table width if (editorView) { var tableWrapperWidth = tableContainerWidth; var scalePercent = getStaticTableScalingPercent(selectedNode, tableWrapperWidth, shouldUseIncreasedScalingPercent); tableContainerWidth = tableContainerWidth * scalePercent; } // If fixed-width editor, we disable 'left-alignment' when table width is 760px. // tableContainerWidth +1 here because tableContainerWidth is 759 in fixed-width editor if (selectedNode && !isFullWidthEditor && lineLength && tableContainerWidth + 1 >= lineLength) { return true; } return false; };