UNPKG

@atlaskit/editor-plugin-table

Version:

Table plugin for the @atlaskit/editor

618 lines (612 loc) 37.3 kB
import React, { useEffect } from 'react'; import { tableCell, tableCellWithNestedTable, tableHeader, tableHeaderWithLocalId, tableHeaderWithNestedTable, tableRow, tableRowWithNestedTable, tableRowWithLocalId, tableCellWithLocalId, tableCellWithNestedTableWithLocalId, tableRowWithNestedTableWithLocalId, tableHeaderWithNestedTableWithLocalId } from '@atlaskit/adf-schema'; import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD, TABLE_ACTION } from '@atlaskit/editor-common/analytics'; import { browser as browserLegacy, getBrowserInfo } from '@atlaskit/editor-common/browser'; import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks'; import { IconTable } from '@atlaskit/editor-common/icons'; import { toggleTable, tooltip } from '@atlaskit/editor-common/keymaps'; import { toolbarInsertBlockMessages as messages } from '@atlaskit/editor-common/messages'; import { getParentOfTypeCount, getPositionAfterTopParentNodeOfType } from '@atlaskit/editor-common/nesting'; import { editorCommandToPMCommand } from '@atlaskit/editor-common/preset'; import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { hasParentNodeOfType, safeInsert } from '@atlaskit/editor-prosemirror/utils'; import { tableEditing } from '@atlaskit/editor-tables/pm-plugins'; import { fg } from '@atlaskit/platform-feature-flags'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments'; import { tableNodeSpecWithFixedToDOM } from './nodeviews/toDOM'; import { createPlugin as createTableAnalyticsPlugin } from './pm-plugins/analytics/plugin'; import { insertTableWithNestingSupport } from './pm-plugins/commands/insert'; import { pluginConfig } from './pm-plugins/create-plugin-config'; import { createPlugin as createDecorationsPlugin } from './pm-plugins/decorations/plugin'; import { createPlugin as createDragAndDropPlugin } from './pm-plugins/drag-and-drop/plugin'; import { pluginKey as dragAndDropPluginKey } from './pm-plugins/drag-and-drop/plugin-key'; import { createPlugin as createContentAreaHeightPlugin, pluginKey as editorContentAreaHeightPluginKey } from './pm-plugins/editor-content-area-height'; import { keymapPlugin } from './pm-plugins/keymap'; import { createPlugin } from './pm-plugins/main'; import { pluginKey } from './pm-plugins/plugin-key'; import { createPlugin as createTableSafariDeleteCompositionTextIssueWorkaroundPlugin } from './pm-plugins/safari-delete-composition-text-issue-workaround'; import { createPlugin as createStickyHeadersPlugin } from './pm-plugins/sticky-headers/plugin'; import { pluginKey as stickyHeadersPluginKey } from './pm-plugins/sticky-headers/plugin-key'; import { findStickyHeaderForTable } from './pm-plugins/sticky-headers/util'; import { createPlugin as createTableOverflowAnalyticsPlugin } from './pm-plugins/table-analytics'; import { createPlugin as createTableAnchorNamesPlugin } from './pm-plugins/table-anchor-names/plugin'; import { createPlugin as createTableLocalIdPlugin } from './pm-plugins/table-local-id'; import { createPlugin as createFlexiResizingPlugin } from './pm-plugins/table-resizing/plugin'; import { getPluginState as getFlexiResizingPlugin } from './pm-plugins/table-resizing/plugin-factory'; import { tableSelectionKeymapPlugin } from './pm-plugins/table-selection-keymap'; import { createPlugin as createSizeSelectorPlugin, pluginKey as sizeSelectorPluginKey } from './pm-plugins/table-size-selector'; import { createPlugin as createTableWidthPlugin, pluginKey as tableWidthPluginKey } from './pm-plugins/table-width'; import { createPlugin as createTableWidthInCommentFixPlugin } from './pm-plugins/table-width-in-comment-fix'; import { getHeightInfoPayload, getWidthInfoPayload } from './pm-plugins/utils/analytics'; import { createTableWithWidth } from './pm-plugins/utils/create'; import { createPlugin as createViewModeSortPlugin } from './pm-plugins/view-mode-sort'; import { ContentComponent } from './ui/ContentComponent'; import { getToolbarConfig } from './ui/toolbar'; const defaultGetEditorFeatureFlags = () => ({}); // we want to calculate all the table widths (which causes reflows) after the editor has finished loading to mitigate performance impact const TABLE_WIDTH_INFO_TIMEOUT = 10000; /** * Table plugin to be added to an `EditorPresetBuilder` and used with `ComposableEditor` * from `@atlaskit/editor-core`. */ const tablePlugin = ({ config, api }) => { var _config$tableOptions, _api$analytics, _options$getEditorFea, _options$getEditorFea2; const editorViewRef = { current: null }; const options = { ...config, tableOptions: (_config$tableOptions = config === null || config === void 0 ? void 0 : config.tableOptions) !== null && _config$tableOptions !== void 0 ? _config$tableOptions : {}, dragAndDropEnabled: (config === null || config === void 0 ? void 0 : config.dragAndDropEnabled) || fg('platform_editor_enable_table_dnd'), isTableScalingEnabled: (config === null || config === void 0 ? void 0 : config.isTableScalingEnabled) || fg('platform_editor_enable_table_scaling') }; const defaultGetEditorContainerWidth = () => { var _api$width$sharedStat, _api$width, _document$body$offset, _document, _document$body; return (_api$width$sharedStat = api === null || api === void 0 ? void 0 : (_api$width = api.width) === null || _api$width === void 0 ? void 0 : _api$width.sharedState.currentState()) !== null && _api$width$sharedStat !== void 0 ? _api$width$sharedStat : { width: (_document$body$offset = (_document = document) === null || _document === void 0 ? void 0 : (_document$body = _document.body) === null || _document$body === void 0 ? void 0 : _document$body.offsetWidth) !== null && _document$body$offset !== void 0 ? _document$body$offset : 500 }; }; const editorAnalyticsAPI = api === null || api === void 0 ? void 0 : (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions; const isTableFixedColumnWidthsOptionEnabled = fg('platform_editor_table_fixed_column_width_prop') ? options === null || options === void 0 ? void 0 : options.allowFixedColumnWidthOption : (options === null || options === void 0 ? void 0 : (_options$getEditorFea = options.getEditorFeatureFlags) === null || _options$getEditorFea === void 0 ? void 0 : _options$getEditorFea.call(options).tableWithFixedColumnWidthsOption) || false; const shouldUseIncreasedScalingPercent = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) && (isTableFixedColumnWidthsOptionEnabled || ( // When in comment editor, we need the scaling percent to be 40% while tableWithFixedColumnWidthsOption is not visible options === null || options === void 0 ? void 0 : options.isCommentEditor)); const isTableSelectorEnabled = // eslint-disable-next-line @atlaskit/platform/no-preconditioning !(options !== null && options !== void 0 && options.isChromelessEditor) && !(options !== null && options !== void 0 && options.isCommentEditor) && (options === null || options === void 0 ? void 0 : (_options$getEditorFea2 = options.getEditorFeatureFlags) === null || _options$getEditorFea2 === void 0 ? void 0 : _options$getEditorFea2.call(options).tableSelector) && editorExperiment('platform_editor_controls', 'variant1'); return { name: 'table', // Use getSharedState to store fullWidthEnabled and wasFullWidthModeEnabled to guarantee access // to most up to date values - passing to createPluginState will not re-initialise the state getSharedState: editorState => { var _tablePluginState$tab, _tableWidthResizingPl; if (!editorState) { return undefined; } // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const tablePluginState = pluginKey.getState(editorState); const tableResizingPluginState = getFlexiResizingPlugin(editorState); const tableWidthResizingPluginState = tableWidthPluginKey.getState(editorState); const stickyHeadersState = stickyHeadersPluginKey.getState(editorState); const stickyHeader = stickyHeadersState ? findStickyHeaderForTable(stickyHeadersState, tablePluginState === null || tablePluginState === void 0 ? void 0 : tablePluginState.tablePos) : undefined; const dragAndDropState = dragAndDropPluginKey.getState(editorState); const sizeSelectorPluginState = sizeSelectorPluginKey.getState(editorState); const editorContentAreaHeightPluginState = editorContentAreaHeightPluginKey.getState(editorState); const sharedStateInternal = { isFullWidthModeEnabled: !!(options !== null && options !== void 0 && options.fullWidthEnabled), wasFullWidthModeEnabled: !!(options !== null && options !== void 0 && options.wasFullWidthEnabled), isMaxWidthModeEnabled: !!(options !== null && options !== void 0 && options.maxWidthEnabled), wasMaxWidthModeEnabled: !!(options !== null && options !== void 0 && options.wasMaxWidthEnabled), isHeaderRowEnabled: tablePluginState.isHeaderRowEnabled, isHeaderColumnEnabled: tablePluginState.isHeaderColumnEnabled, ordering: tablePluginState.ordering, isResizing: !!(tableResizingPluginState !== null && tableResizingPluginState !== void 0 && tableResizingPluginState.dragging || tableWidthResizingPluginState !== null && tableWidthResizingPluginState !== void 0 && tableWidthResizingPluginState.resizing), isTableResizing: tableWidthResizingPluginState === null || tableWidthResizingPluginState === void 0 ? void 0 : tableWidthResizingPluginState.resizing, isInDanger: tablePluginState.isInDanger, hoveredRows: tablePluginState.hoveredRows, hoveredColumns: tablePluginState.hoveredColumns, hoveredCell: tablePluginState.hoveredCell, isTableHovered: tablePluginState.isTableHovered, isWholeTableInDanger: tablePluginState.isWholeTableInDanger, // IMPORTANT: Need to continue to pass tableNode to control re-renders // TableComponent listens for node attribute changes to update colgroups tableNode: tablePluginState.tableNode, widthToWidest: tablePluginState.widthToWidest, resizingTableLocalId: tableWidthResizingPluginState === null || tableWidthResizingPluginState === void 0 ? void 0 : tableWidthResizingPluginState.tableLocalId, tableRef: (_tablePluginState$tab = tablePluginState === null || tablePluginState === void 0 ? void 0 : tablePluginState.tableRef) !== null && _tablePluginState$tab !== void 0 ? _tablePluginState$tab : undefined, resizingTableRef: (_tableWidthResizingPl = tableWidthResizingPluginState === null || tableWidthResizingPluginState === void 0 ? void 0 : tableWidthResizingPluginState.tableRef) !== null && _tableWidthResizingPl !== void 0 ? _tableWidthResizingPl : undefined, tablePos: tablePluginState.tablePos, targetCellPosition: tablePluginState.targetCellPosition, isContextualMenuOpen: tablePluginState.isContextualMenuOpen, pluginConfig: tablePluginState.pluginConfig, insertColumnButtonIndex: tablePluginState.insertColumnButtonIndex, insertRowButtonIndex: tablePluginState.insertRowButtonIndex, isDragAndDropEnabled: tablePluginState.isDragAndDropEnabled, tableWrapperTarget: tablePluginState.tableWrapperTarget, isCellMenuOpenByKeyboard: tablePluginState.isCellMenuOpenByKeyboard, stickyHeader, dragMenuDirection: dragAndDropState === null || dragAndDropState === void 0 ? void 0 : dragAndDropState.dragMenuDirection, dragMenuIndex: dragAndDropState === null || dragAndDropState === void 0 ? void 0 : dragAndDropState.dragMenuIndex, isDragMenuOpen: dragAndDropState === null || dragAndDropState === void 0 ? void 0 : dragAndDropState.isDragMenuOpen, isSizeSelectorOpen: sizeSelectorPluginState === null || sizeSelectorPluginState === void 0 ? void 0 : sizeSelectorPluginState.isSelectorOpen, sizeSelectorTargetRef: sizeSelectorPluginState === null || sizeSelectorPluginState === void 0 ? void 0 : sizeSelectorPluginState.targetRef, editorContentAreaHeight: expValEquals('platform_editor_table_sticky_header_improvements', 'cohort', 'test_with_overflow') && fg('platform_editor_table_sticky_header_patch_4') ? editorContentAreaHeightPluginState === null || editorContentAreaHeightPluginState === void 0 ? void 0 : editorContentAreaHeightPluginState.height : undefined }; return sharedStateInternal; }, actions: { insertTable: analyticsPayload => (state, dispatch) => { var _options$tableOptions; if (options !== null && options !== void 0 && (_options$tableOptions = options.tableOptions) !== null && _options$tableOptions !== void 0 && _options$tableOptions.allowNestedTables) { return editorCommandToPMCommand(insertTableWithNestingSupport({ isTableScalingEnabled: options === null || options === void 0 ? void 0 : options.isTableScalingEnabled, isTableAlignmentEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableAlignment, isFullWidthModeEnabled: options === null || options === void 0 ? void 0 : options.fullWidthEnabled, isMaxWidthModeEnabled: options === null || options === void 0 ? void 0 : options.maxWidthEnabled, isCommentEditor: options === null || options === void 0 ? void 0 : options.isCommentEditor, isChromelessEditor: options === null || options === void 0 ? void 0 : options.isChromelessEditor, isTableResizingEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing }, api, analyticsPayload))(state, dispatch); } else { var _api$contentInsertion, _api$contentInsertion2, _api$contentInsertion3; const node = createTableWithWidth({ isTableScalingEnabled: options === null || options === void 0 ? void 0 : options.isTableScalingEnabled, isTableAlignmentEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableAlignment, isFullWidthModeEnabled: options === null || options === void 0 ? void 0 : options.fullWidthEnabled, isMaxWidthModeEnabled: options === null || options === void 0 ? void 0 : options.maxWidthEnabled, isCommentEditor: options === null || options === void 0 ? void 0 : options.isCommentEditor, isChromelessEditor: options === null || options === void 0 ? void 0 : options.isChromelessEditor, isTableResizingEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing })(state.schema); return (_api$contentInsertion = api === null || api === void 0 ? void 0 : (_api$contentInsertion2 = api.contentInsertion) === null || _api$contentInsertion2 === void 0 ? void 0 : (_api$contentInsertion3 = _api$contentInsertion2.actions) === null || _api$contentInsertion3 === void 0 ? void 0 : _api$contentInsertion3.insert({ state, dispatch, node, options: { selectNodeInserted: false, analyticsPayload: { ...analyticsPayload, attributes: { ...analyticsPayload.attributes, localId: node.attrs.localId } } } })) !== null && _api$contentInsertion !== void 0 ? _api$contentInsertion : false; } } }, commands: { insertTableWithSize: (rowsCount, colsCount, inputMethod) => insertTableWithNestingSupport({ isTableScalingEnabled: options === null || options === void 0 ? void 0 : options.isTableScalingEnabled, isTableAlignmentEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableAlignment, isFullWidthModeEnabled: options === null || options === void 0 ? void 0 : options.fullWidthEnabled, isMaxWidthModeEnabled: options === null || options === void 0 ? void 0 : options.maxWidthEnabled, isCommentEditor: options === null || options === void 0 ? void 0 : options.isCommentEditor, isChromelessEditor: options === null || options === void 0 ? void 0 : options.isChromelessEditor, isTableResizingEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing, createTableProps: { rowsCount, colsCount } }, api, { action: ACTION.INSERTED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: ACTION_SUBJECT_ID.TABLE, attributes: { inputMethod: inputMethod !== null && inputMethod !== void 0 ? inputMethod : INPUT_METHOD.PICKER, totalRowCount: rowsCount, totalColumnCount: colsCount }, eventType: EVENT_TYPE.TRACK }) }, nodes() { var _options$tableOptions2, _options$getEditorFea3; const { allowColumnResizing } = pluginConfig(options === null || options === void 0 ? void 0 : options.tableOptions); // TODO: ED-25901 - We need to move this into a plugin config option so we don't accidentally enable nested nodes in Jira const isNestingSupported = Boolean(options === null || options === void 0 ? void 0 : (_options$tableOptions2 = options.tableOptions) === null || _options$tableOptions2 === void 0 ? void 0 : _options$tableOptions2.allowNestedTables); const isTableFixedColumnWidthsOptionEnabled = (fg('platform_editor_table_fixed_column_width_prop') ? options === null || options === void 0 ? void 0 : options.allowFixedColumnWidthOption : options === null || options === void 0 ? void 0 : (_options$getEditorFea3 = options.getEditorFeatureFlags) === null || _options$getEditorFea3 === void 0 ? void 0 : _options$getEditorFea3.call(options).tableWithFixedColumnWidthsOption) || false; const shouldUseIncreasedScalingPercent = (options === null || options === void 0 ? void 0 : options.isTableScalingEnabled) && (isTableFixedColumnWidthsOptionEnabled || ( // When in comment editor, we need the scaling percent to be 40% while tableWithFixedColumnWidthsOption is not visible options === null || options === void 0 ? void 0 : options.isCommentEditor)); const isTableScalingEnabled = options === null || options === void 0 ? void 0 : options.isTableScalingEnabled; const isCommentEditor = options === null || options === void 0 ? void 0 : options.isCommentEditor; const isChromelessEditor = options === null || options === void 0 ? void 0 : options.isChromelessEditor; return isNestingSupported ? [{ name: 'table', node: tableNodeSpecWithFixedToDOM({ allowColumnResizing: Boolean(allowColumnResizing), tableResizingEnabled: Boolean(options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing), getEditorContainerWidth: defaultGetEditorContainerWidth, isNestingSupported, isTableScalingEnabled, shouldUseIncreasedScalingPercent, isCommentEditor, isChromelessEditor }) }, { name: 'tableHeader', node: fg('platform_editor_adf_with_localid') ? tableHeaderWithNestedTableWithLocalId : tableHeaderWithNestedTable }, { name: 'tableRow', node: fg('platform_editor_adf_with_localid') ? tableRowWithNestedTableWithLocalId : tableRowWithNestedTable }, { name: 'tableCell', node: fg('platform_editor_adf_with_localid') ? tableCellWithNestedTableWithLocalId : tableCellWithNestedTable }] : [{ name: 'table', node: tableNodeSpecWithFixedToDOM({ allowColumnResizing: Boolean(allowColumnResizing), tableResizingEnabled: Boolean(options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing), getEditorContainerWidth: defaultGetEditorContainerWidth, isNestingSupported, isTableScalingEnabled, shouldUseIncreasedScalingPercent, isCommentEditor, isChromelessEditor }) }, { name: 'tableHeader', node: fg('platform_editor_adf_with_localid') ? tableHeaderWithLocalId : tableHeader }, { name: 'tableRow', node: fg('platform_editor_adf_with_localid') ? tableRowWithLocalId : tableRow }, { name: 'tableCell', node: fg('platform_editor_adf_with_localid') ? tableCellWithLocalId : tableCell }]; }, pmPlugins() { const plugins = [{ name: 'table', plugin: ({ dispatchAnalyticsEvent, dispatch, portalProviderAPI, nodeViewPortalProviderAPI, eventDispatcher, getIntl }) => { const { fullWidthEnabled, wasFullWidthEnabled, tableOptions, getEditorFeatureFlags, dragAndDropEnabled, isTableScalingEnabled, isCommentEditor, isChromelessEditor } = options || {}; return createPlugin(dispatchAnalyticsEvent, dispatch, portalProviderAPI, nodeViewPortalProviderAPI, eventDispatcher, pluginConfig(tableOptions), defaultGetEditorContainerWidth, getEditorFeatureFlags || defaultGetEditorFeatureFlags, getIntl, fullWidthEnabled, wasFullWidthEnabled, dragAndDropEnabled, editorAnalyticsAPI, api, isTableScalingEnabled, shouldUseIncreasedScalingPercent, isCommentEditor, isChromelessEditor, options === null || options === void 0 ? void 0 : options.allowFixedColumnWidthOption); } }, { name: 'tablePMColResizing', plugin: ({ dispatch, nodeViewPortalProviderAPI }) => { const { fullWidthEnabled, tableOptions, getEditorFeatureFlags, isTableScalingEnabled } = options || {}; const { allowColumnResizing } = pluginConfig(tableOptions); return allowColumnResizing ? createFlexiResizingPlugin(dispatch, { lastColumnResizable: !fullWidthEnabled }, defaultGetEditorContainerWidth, getEditorFeatureFlags || defaultGetEditorFeatureFlags, api, nodeViewPortalProviderAPI, editorAnalyticsAPI, isTableScalingEnabled || false, !!(options !== null && options !== void 0 && options.isCommentEditor)) : undefined; } }, { name: 'tableEditing', plugin: () => createDecorationsPlugin() }, // Needs to be lower priority than editor-tables.tableEditing // plugin as it is currently swallowing backspace events inside tables { name: 'tableKeymap', plugin: ({ getIntl, nodeViewPortalProviderAPI }) => { const { dragAndDropEnabled, isTableScalingEnabled = false, fullWidthEnabled = false, isCommentEditor = false, isChromelessEditor = false, tableOptions } = options || {}; return keymapPlugin(defaultGetEditorContainerWidth, api, nodeViewPortalProviderAPI, editorAnalyticsAPI, dragAndDropEnabled, isTableScalingEnabled, tableOptions === null || tableOptions === void 0 ? void 0 : tableOptions.allowTableAlignment, fullWidthEnabled, api, getIntl, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent, isCommentEditor, isChromelessEditor, tableOptions === null || tableOptions === void 0 ? void 0 : tableOptions.allowTableResizing); } }, { name: 'tableSelectionKeymap', plugin: ({ getIntl }) => tableSelectionKeymapPlugin(api, getIntl) }, { name: 'tableEditing', plugin: () => { const { dragAndDropEnabled } = options || {}; return tableEditing({ reportFixedTable: ({ tr, reason }) => { editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({ action: TABLE_ACTION.FIXED, actionSubject: ACTION_SUBJECT.TABLE, actionSubjectId: null, attributes: { reason }, eventType: EVENT_TYPE.TRACK })(tr); }, dragAndDropEnabled }); } }, { name: 'tableStickyHeaders', plugin: ({ dispatch }) => options && options.tableOptions.stickyHeaders ? createStickyHeadersPlugin(dispatch, () => []) : undefined }, { name: 'tableDragAndDrop', plugin: ({ dispatch }) => { return options !== null && options !== void 0 && options.dragAndDropEnabled ? createDragAndDropPlugin(dispatch, editorAnalyticsAPI, options === null || options === void 0 ? void 0 : options.isTableScalingEnabled, isTableFixedColumnWidthsOptionEnabled, options.isCommentEditor, api) : undefined; } }, { name: 'tableViewModeSort', plugin: ({ nodeViewPortalProviderAPI }) => { return api !== null && api !== void 0 && api.editorViewMode ? createViewModeSortPlugin(api, nodeViewPortalProviderAPI) : undefined; } }, { name: 'tableLocalId', plugin: ({ dispatch }) => !fg('platform_editor_adf_with_localid') ? createTableLocalIdPlugin(dispatch) : undefined }, { name: 'tableWidth', plugin: ({ dispatchAnalyticsEvent, dispatch }) => { var _options$fullWidthEna, _options$maxWidthEnab, _options$isTableScali, _options$tableOptions3, _options$isCommentEdi; return options !== null && options !== void 0 && options.tableOptions.allowTableResizing ? createTableWidthPlugin(dispatch, dispatchAnalyticsEvent, (_options$fullWidthEna = options.fullWidthEnabled) !== null && _options$fullWidthEna !== void 0 ? _options$fullWidthEna : false, (_options$maxWidthEnab = options.maxWidthEnabled) !== null && _options$maxWidthEnab !== void 0 ? _options$maxWidthEnab : false, (_options$isTableScali = options.isTableScalingEnabled) !== null && _options$isTableScali !== void 0 ? _options$isTableScali : false, (_options$tableOptions3 = options.tableOptions.allowTableResizing) !== null && _options$tableOptions3 !== void 0 ? _options$tableOptions3 : false, (_options$isCommentEdi = options.isCommentEditor) !== null && _options$isCommentEdi !== void 0 ? _options$isCommentEdi : false) : undefined; } }, { name: 'tableWidthInCommentFix', plugin: ({ dispatch }) => { var _options$tableOptions4; return options !== null && options !== void 0 && options.tableOptions.allowTableResizing && options !== null && options !== void 0 && options.isCommentEditor ? createTableWidthInCommentFixPlugin(dispatch, (_options$tableOptions4 = options.tableOptions.allowTableAlignment) !== null && _options$tableOptions4 !== void 0 ? _options$tableOptions4 : false) : undefined; } }, // TODO: ED-26961 - should be deprecated and eventually replaced with 'tableAnalyticsPlugin' { name: 'tableOverflowAnalyticsPlugin', plugin: ({ dispatch, dispatchAnalyticsEvent }) => { var _options$tableOptions5; return createTableOverflowAnalyticsPlugin(dispatch, dispatchAnalyticsEvent, (_options$tableOptions5 = options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing) !== null && _options$tableOptions5 !== void 0 ? _options$tableOptions5 : false); } }, { name: 'tableAnalyticsPlugin', plugin: ({ dispatch, dispatchAnalyticsEvent }) => createTableAnalyticsPlugin(dispatch, dispatchAnalyticsEvent) }, { name: 'tableGetEditorViewReferencePlugin', plugin: ({ dispatchAnalyticsEvent }) => { return new SafePlugin({ view: editorView => { editorViewRef.current = editorView; let rafID; let ricID; // send statistics about the widths of the tables on the page for alerting // only send this event once, after the editorView is first initialised const setTimeoutID = setTimeout(() => { const requestIdleCallbackFn = () => { var _api$width$sharedStat2; const editorWidth = api === null || api === void 0 ? void 0 : (_api$width$sharedStat2 = api.width.sharedState.currentState()) === null || _api$width$sharedStat2 === void 0 ? void 0 : _api$width$sharedStat2.width; if (editorViewRef.current) { if (editorWidth) { const payload = getWidthInfoPayload(editorViewRef.current, editorWidth); if (payload) { dispatchAnalyticsEvent(payload); } } if (fg('platform_editor_table_height_analytics_event')) { const payloadHeight = getHeightInfoPayload(editorViewRef.current); if (payloadHeight) { dispatchAnalyticsEvent(payloadHeight); } } } }; if (window && typeof window.requestIdleCallback === 'function') { ricID = window.requestIdleCallback(requestIdleCallbackFn); } else if (window && typeof window.requestAnimationFrame === 'function') { // requestIdleCallback is not supported in safari, fallback to requestAnimationFrame rafID = window.requestAnimationFrame(requestIdleCallbackFn); } }, TABLE_WIDTH_INFO_TIMEOUT); return { destroy: () => { editorViewRef.current = null; if (setTimeoutID) { clearTimeout(setTimeoutID); } if (rafID) { window.cancelAnimationFrame(rafID); } if (ricID) { window.cancelIdleCallback(ricID); } } }; } }); } }, { name: 'tableSizeSelectorPlugin', plugin: ({ dispatch }) => isTableSelectorEnabled ? createSizeSelectorPlugin(dispatch) : undefined }, { name: 'editorContentAreaHeightPlugin', plugin: () => expValEquals('platform_editor_table_sticky_header_improvements', 'cohort', 'test_with_overflow') && fg('platform_editor_table_sticky_header_patch_1') ? createContentAreaHeightPlugin() : undefined }]; if (!expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) && expValEquals('platform_editor_table_sticky_header_improvements', 'cohort', 'test_with_overflow') && fg('platform_editor_table_sticky_header_patch_2')) { plugins.push({ name: 'tableAnchorNames', plugin: () => createTableAnchorNamesPlugin() }); } const browser = expValEquals('platform_editor_hydratable_ui', 'isEnabled', true) ? getBrowserInfo() : browserLegacy; // Workaround for table element breaking issue caused by composition event with an inputType of deleteCompositionText. // https://github.com/ProseMirror/prosemirror/issues/934 if (browser.safari) { plugins.push({ name: 'tableSafariDeleteCompositionTextIssueWorkaround', plugin: () => { return createTableSafariDeleteCompositionTextIssueWorkaroundPlugin(); } }); } return plugins; }, contentComponent({ editorView, popupsMountPoint, popupsBoundariesElement, popupsScrollableElement, dispatchAnalyticsEvent }) { return /*#__PURE__*/React.createElement(ContentComponent, { api: api, editorView: editorView, dispatchAnalyticsEvent: dispatchAnalyticsEvent, options: options, popupsMountPoint: popupsMountPoint, popupsBoundariesElement: popupsBoundariesElement, popupsScrollableElement: popupsScrollableElement, defaultGetEditorContainerWidth: defaultGetEditorContainerWidth, defaultGetEditorFeatureFlags: defaultGetEditorFeatureFlags, isTableSelectorEnabled: isTableSelectorEnabled }); }, pluginsOptions: { quickInsert: ({ formatMessage }) => [{ id: 'table', title: formatMessage(messages.table), description: formatMessage(messages.tableDescription), keywords: ['cell', 'table'], priority: 600, keyshortcut: tooltip(toggleTable), icon: () => /*#__PURE__*/React.createElement(IconTable, null), action(insert, state) { var _api$table, _options$tableOptions6; if (isTableSelectorEnabled) { const tr = insert(''); tr.setMeta(sizeSelectorPluginKey, { isSelectorOpen: true }); return tr; } // see comment on tablesPlugin.getSharedState on usage const tableState = api === null || api === void 0 ? void 0 : (_api$table = api.table) === null || _api$table === void 0 ? void 0 : _api$table.sharedState.currentState(); const tableNodeProps = { isTableScalingEnabled: options === null || options === void 0 ? void 0 : options.isTableScalingEnabled, isTableAlignmentEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableAlignment, isFullWidthModeEnabled: tableState === null || tableState === void 0 ? void 0 : tableState.isFullWidthModeEnabled, isMaxWidthModeEnabled: tableState === null || tableState === void 0 ? void 0 : tableState.isMaxWidthModeEnabled, isCommentEditor: options === null || options === void 0 ? void 0 : options.isCommentEditor, isChromelessEditor: options === null || options === void 0 ? void 0 : options.isChromelessEditor, isTableResizingEnabled: options === null || options === void 0 ? void 0 : options.tableOptions.allowTableResizing }; let tableNode = createTableWithWidth(tableNodeProps)(state.schema); let { tr } = state; // If the cursor is inside a table if (hasParentNodeOfType(state.schema.nodes.table)(state.selection) && options !== null && options !== void 0 && (_options$tableOptions6 = options.tableOptions) !== null && _options$tableOptions6 !== void 0 && _options$tableOptions6.allowNestedTables) { // If trying to nest deeper than one level, we insert the table after the top table if (getParentOfTypeCount(state.schema.nodes.table)(state.selection.$from) > 1) { // Nesting is too deep insert table after the top parent table const positionAfterTopTable = getPositionAfterTopParentNodeOfType(state.schema.nodes.table)(state.selection.$from); tr = safeInsert(tableNode, positionAfterTopTable)(tr); tr.scrollIntoView(); } else { // Table can be nested in parent table tableNode = createTableWithWidth({ ...tableNodeProps, isNestedTable: true })(state.schema); tr = insert(tableNode); } } else { tr = insert(tableNode); } editorAnalyticsAPI === null || editorAnalyticsAPI === void 0 ? void 0 : editorAnalyticsAPI.attachAnalyticsEvent({ action: ACTION.INSERTED, actionSubject: ACTION_SUBJECT.DOCUMENT, actionSubjectId: ACTION_SUBJECT_ID.TABLE, attributes: { inputMethod: INPUT_METHOD.QUICK_INSERT, localId: tableNode.attrs.localId }, eventType: EVENT_TYPE.TRACK })(tr); return tr; } }], floatingToolbar: getToolbarConfig(defaultGetEditorContainerWidth, api, editorAnalyticsAPI, () => editorViewRef.current, options, isTableFixedColumnWidthsOptionEnabled, shouldUseIncreasedScalingPercent)(pluginConfig(options === null || options === void 0 ? void 0 : options.tableOptions)) }, usePluginHook({ editorView }) { const { mode } = useSharedPluginStateWithSelector(api, ['editorViewMode'], states => { var _states$editorViewMod; return { mode: (_states$editorViewMod = states.editorViewModeState) === null || _states$editorViewMod === void 0 ? void 0 : _states$editorViewMod.mode }; }); useEffect(() => { const { state, dispatch } = editorView; const tr = state.tr; tr.setMeta('viewModeState', mode); if (dispatch) { dispatch(tr); } }, [editorView, mode]); } }; }; export default tablePlugin;