@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
532 lines (526 loc) • 28.3 kB
JavaScript
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import rafSchd from 'raf-schd';
import { useIntl } from 'react-intl-next';
import { CHANGE_ALIGNMENT_REASON, INPUT_METHOD, TABLE_OVERFLOW_CHANGE_TRIGGER } from '@atlaskit/editor-common/analytics';
import { browser as browserLegacy, getBrowserInfo } from '@atlaskit/editor-common/browser';
import { getGuidelinesWithHighlights } from '@atlaskit/editor-common/guideline';
import { useSharedPluginStateWithSelector } from '@atlaskit/editor-common/hooks';
import { focusTableResizer, ToolTipContent } from '@atlaskit/editor-common/keymaps';
import { tableMessages as messages } from '@atlaskit/editor-common/messages';
import { logException } from '@atlaskit/editor-common/monitoring';
import { ResizerNext } from '@atlaskit/editor-common/resizer';
import { useSharedPluginStateSelector } from '@atlaskit/editor-common/use-shared-plugin-state-selector';
import { chainCommands } from '@atlaskit/editor-prosemirror/commands';
import { akEditorGutterPaddingDynamic, akEditorGutterPaddingReduced, akEditorFullPageNarrowBreakout } from '@atlaskit/editor-shared-styles';
import { findTable } from '@atlaskit/editor-tables/utils';
import { insm } from '@atlaskit/insm';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { setTableAlignmentWithTableContentWithPosWithAnalytics } from '../pm-plugins/commands/commands-with-analytics';
import { updateWidthToWidest } from '../pm-plugins/commands/misc';
import { META_KEYS } from '../pm-plugins/table-analytics';
import { getColgroupChildrenLength } from '../pm-plugins/table-resizing/utils/colgroup';
import { COLUMN_MIN_WIDTH, TABLE_MAX_WIDTH, TABLE_FULL_WIDTH, TABLE_OFFSET_IN_COMMENT_EDITOR } from '../pm-plugins/table-resizing/utils/consts';
import { previewScaleTable, scaleTable } from '../pm-plugins/table-resizing/utils/scale-table';
import { pluginKey as tableWidthPluginKey } from '../pm-plugins/table-width';
import { ALIGN_CENTER, ALIGN_START, normaliseAlignment, shouldChangeAlignmentToCenterResized } from '../pm-plugins/utils/alignment';
import { generateResizedPayload, generateResizeFrameRatePayloads, useMeasureFramerate } from '../pm-plugins/utils/analytics';
import { defaultGuidelines, defaultGuidelinesForPreserveTable, PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET } from '../pm-plugins/utils/guidelines';
import { defaultSnappingWidths, defaultTablePreserveSnappingWidths, findClosestSnap, PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET } from '../pm-plugins/utils/snapping';
import { TABLE_GUIDELINE_VISIBLE_ADJUSTMENT, TABLE_HIGHLIGHT_GAP, TABLE_HIGHLIGHT_TOLERANCE, TABLE_SNAP_GAP } from '../ui/consts';
const RESIZE_STEP_VALUE = 10;
const handles = {
right: true
};
const handleStyles = {
right: {
// eslint-disable-next-line @atlaskit/design-system/ensure-design-token-usage/preview
right: '-14px',
marginTop: "var(--ds-space-150, 12px)"
}
};
const getResizerHandleHeight = tableRef => {
var _tableRef$clientHeigh;
const tableHeight = (_tableRef$clientHeigh = tableRef === null || tableRef === void 0 ? void 0 : tableRef.clientHeight) !== null && _tableRef$clientHeigh !== void 0 ? _tableRef$clientHeigh : 0;
/*
- One row table height (minimum possible table height) ~ 45px
- Two row table height ~ 90px
- Three row table height ~ 134px
In the if below we need to use:
- > 46 because the height of the table can be a float number like 45.44.
- < 96 is the height of large resize handle.
*/
if (tableHeight >= 96) {
return 'large';
}
if (tableHeight > 46) {
return 'medium';
}
return 'small';
};
const getResizerMinWidth = node => {
const currentColumnCount = getColgroupChildrenLength(node);
const minColumnWidth = Math.min(3, currentColumnCount) * COLUMN_MIN_WIDTH;
// add an extra pixel as the scale table logic will scale columns to be tableContainerWidth - 1
// the table can't scale past its min-width, so instead restrict table container min width to avoid that situation
return minColumnWidth + 1;
};
const getPadding = containerWidth => {
return containerWidth <= akEditorFullPageNarrowBreakout && editorExperiment('platform_editor_preview_panel_responsiveness', true, {
exposure: true
}) ? akEditorGutterPaddingReduced : akEditorGutterPaddingDynamic();
};
/**
* When guidelines are outside the viewport, filter them out, do not show
* So the guideline container won't make the fabric-editor-popup-scroll-parent overflow
* @param guidelines
* @param containerWidth editorWidth
* @param lineLength
* @param isTableScalingEnabled
* @param isFullWidthModeEnabled
*/
const getVisibleGuidelines = (guidelines, containerWidth, lineLength, isTableScalingEnabled, isFullWidthModeEnabled) => {
let guidelineVisibleAdjustment = TABLE_GUIDELINE_VISIBLE_ADJUSTMENT;
if (isTableScalingEnabled) {
// Notes:
// Example: containerWidth = 1244, lineLength = 1180 (used for when editor full width mode is enabled)
// Full width/dynamic x coordinate can be float number.
// Ex: guideline.position.x can be 590.5. So 590.5 * 2 = 1181 (not 1180).
// For PTW we need to ensure that dynamic guideline never gets excluded: 1181 should be > width + guidelineVisibleAdjustment
// guidelineVisibleAdjustment is set as a negative value, so we making it positive and adding + 1
const preserve_table_widths_adjustment = -1 * PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET + 1;
const padding = getPadding(containerWidth);
guidelineVisibleAdjustment = isFullWidthModeEnabled ? preserve_table_widths_adjustment // guidelineVisibleAdjustment = -2, if lineLength = 1180, 1181 < 1180 + 2 is true.
: -2 * padding + preserve_table_widths_adjustment; // guidelineVisibleAdjustment = -62, if containerWidth is 1244, 1181 < 1244 - 62 = 1182 is true.
}
const width = isTableScalingEnabled && isFullWidthModeEnabled ? lineLength : containerWidth;
return guidelines.filter(guideline => {
return guideline.position && guideline.position.x !== undefined && typeof guideline.position.x === 'number' && Math.abs(guideline.position.x * 2) < width + guidelineVisibleAdjustment;
});
};
const selector = states => {
var _states$tableState;
return {
widthToWidest: (_states$tableState = states.tableState) === null || _states$tableState === void 0 ? void 0 : _states$tableState.widthToWidest
};
};
export const TableResizer = ({
children,
width,
maxWidth,
containerWidth,
lineLength,
updateWidth,
onResizeStop,
onResizeStart,
editorView,
getPos,
node,
tableRef,
displayGuideline,
attachAnalyticsEvent,
displayGapCursor,
isTableScalingEnabled,
allowFixedColumnWidthOption,
isTableAlignmentEnabled,
isWholeTableInDanger,
shouldUseIncreasedScalingPercent,
pluginInjectionApi,
isFullWidthModeEnabled,
isCommentEditor,
disabled
}) => {
var _editorView$state, _pluginInjectionApi$a2, _pluginInjectionApi$u2;
const currentGap = useRef(0);
// track resizing state - use ref over state to avoid re-render
const isResizing = useRef(false);
const areResizeMetaKeysPressed = useRef(false);
const resizerRef = useRef(null);
const interactionState = useSharedPluginStateSelector(pluginInjectionApi, 'interaction.interactionState');
const {
widthToWidest
} = useSharedPluginStateWithSelector(pluginInjectionApi, ['table'], selector);
// used to reposition tooltip when table is resizing via keyboard
const updateTooltip = React.useRef();
const [snappingEnabled, setSnappingEnabled] = useState(false);
const {
formatMessage
} = useIntl();
const currentSelection = (_editorView$state = editorView.state) === null || _editorView$state === void 0 ? void 0 : _editorView$state.selection;
const tableFromSelection = useMemo(() => {
return findTable(currentSelection);
}, [currentSelection]);
const tableFromSelectionPosition = tableFromSelection === null || tableFromSelection === void 0 ? void 0 : tableFromSelection.pos;
const isTableSelected = useMemo(() => {
// Avoid call getPos if there is no table in the current selection,
if (typeof tableFromSelectionPosition !== 'number') {
return false;
}
if (interactionState === 'hasNotHadInteraction') {
return false;
}
let currentNodePosition;
try {
// The React Table and the ProseMirror can endup out-of-sync
// ProseMirror always assume the DOM is not managed by other framework
currentNodePosition = getPos();
} catch (e) {
logException(e, {
location: 'editor-plugin-table/table-resizer'
});
return false;
}
return tableFromSelectionPosition === currentNodePosition;
}, [tableFromSelectionPosition, interactionState, getPos]);
const resizerMinWidth = getResizerMinWidth(node);
const handleSize = getResizerHandleHeight(tableRef);
const {
startMeasure,
endMeasure,
countFrames
} = useMeasureFramerate();
const excludeGuidelineConfig = useMemo(() => ({
innerGuidelines: !!isTableAlignmentEnabled,
breakoutPoints: !!(isTableAlignmentEnabled && isFullWidthModeEnabled)
}), [isFullWidthModeEnabled, isTableAlignmentEnabled]);
const updateActiveGuidelines = useCallback(({
gap,
keys
}) => {
if (gap !== currentGap.current) {
currentGap.current = gap;
const visibleGuidelines = getVisibleGuidelines(isTableScalingEnabled ? defaultGuidelinesForPreserveTable(PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET, isFullWidthModeEnabled ? lineLength + 2 * getPadding(containerWidth) : containerWidth, excludeGuidelineConfig) : defaultGuidelines, containerWidth, lineLength, Boolean(isTableScalingEnabled), Boolean(isFullWidthModeEnabled));
displayGuideline(getGuidelinesWithHighlights(gap, TABLE_SNAP_GAP, keys, visibleGuidelines));
}
}, [isTableScalingEnabled, excludeGuidelineConfig, containerWidth, displayGuideline, lineLength, isFullWidthModeEnabled]);
const guidelineSnaps = useMemo(() => snappingEnabled ? {
x: isTableScalingEnabled ? defaultTablePreserveSnappingWidths(PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET,
// was hardcoded to 0, using PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET instead.
isFullWidthModeEnabled ? lineLength + 2 * getPadding(containerWidth) : containerWidth, excludeGuidelineConfig) : defaultSnappingWidths
} : undefined, [snappingEnabled, isTableScalingEnabled, excludeGuidelineConfig, containerWidth, lineLength, isFullWidthModeEnabled]);
const switchToCenterAlignment = useCallback((pos, node, newWidth, state, dispatch) => {
if (shouldChangeAlignmentToCenterResized(isTableAlignmentEnabled, node, lineLength, newWidth) && isResizing.current) {
var _pluginInjectionApi$a;
const tableNodeWithPos = {
pos,
node
};
setTableAlignmentWithTableContentWithPosWithAnalytics(pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions)(ALIGN_CENTER, ALIGN_START, tableNodeWithPos, INPUT_METHOD.AUTO, CHANGE_ALIGNMENT_REASON.EDITOR_APPEARANCE_CHANGED)(state, dispatch);
return true;
}
return false;
}, [isTableAlignmentEnabled, lineLength, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a2 = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a2 === void 0 ? void 0 : _pluginInjectionApi$a2.actions]);
useEffect(() => {
return () => {
// only bring back the cursor if this table was deleted - i.e. if a user was resizing, then another
// deleted this table
if (isResizing.current) {
const {
dispatch,
state: {
tr
}
} = editorView;
displayGapCursor(true);
displayGuideline([]);
tr.setMeta(tableWidthPluginKey, {
resizing: false,
tableLocalId: '',
tableRef: null
});
dispatch(tr);
}
};
}, [editorView, displayGuideline, displayGapCursor]);
const handleResizeStart = useCallback(() => {
var _pluginInjectionApi$u;
if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) {
var _insm$session;
(_insm$session = insm.session) === null || _insm$session === void 0 ? void 0 : _insm$session.startFeature('tableResize');
}
startMeasure();
isResizing.current = true;
const {
dispatch,
state: {
tr
}
} = editorView;
displayGapCursor(false);
tr.setMeta(tableWidthPluginKey, {
resizing: true,
tableLocalId: node.attrs.localId,
tableRef: tableRef
});
tr.setMeta('is-resizer-resizing', true);
tr.setMeta(META_KEYS.OVERFLOW_TRIGGER, {
name: TABLE_OVERFLOW_CHANGE_TRIGGER.RESIZED
});
pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$u = pluginInjectionApi.userIntent) === null || _pluginInjectionApi$u === void 0 ? void 0 : _pluginInjectionApi$u.commands.setCurrentUserIntent('resizing')({
tr
});
dispatch(tr);
const visibleGuidelines = getVisibleGuidelines(isTableScalingEnabled ? defaultGuidelinesForPreserveTable(PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET, isFullWidthModeEnabled ? lineLength + 2 * getPadding(containerWidth) : containerWidth, excludeGuidelineConfig) : defaultGuidelines, containerWidth, lineLength, Boolean(isTableScalingEnabled), Boolean(isFullWidthModeEnabled));
setSnappingEnabled(displayGuideline(visibleGuidelines));
if (onResizeStart) {
onResizeStart();
}
}, [startMeasure, editorView, displayGapCursor, node.attrs.localId, tableRef, isTableScalingEnabled, isFullWidthModeEnabled, lineLength, containerWidth, excludeGuidelineConfig, displayGuideline, onResizeStart, pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$u2 = pluginInjectionApi.userIntent) === null || _pluginInjectionApi$u2 === void 0 ? void 0 : _pluginInjectionApi$u2.commands]);
const handleResize = useCallback(
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(originalState, delta) => {
var _node$attrs$localId, _node$attrs;
countFrames();
const newWidth = originalState.width + delta.width;
let pos;
try {
pos = getPos();
} catch {
return;
}
if (typeof pos !== 'number') {
return;
}
const editorContainerWidth = isFullWidthModeEnabled ? lineLength + 2 * getPadding(containerWidth) : containerWidth;
const closestSnap = !isCommentEditor && findClosestSnap(newWidth, isTableScalingEnabled ? defaultTablePreserveSnappingWidths(PRESERVE_TABLE_SNAPPING_LENGTH_OFFSET, editorContainerWidth, excludeGuidelineConfig) : defaultSnappingWidths, isTableScalingEnabled ? defaultGuidelinesForPreserveTable(PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET, editorContainerWidth, excludeGuidelineConfig) : defaultGuidelines, TABLE_HIGHLIGHT_GAP, TABLE_HIGHLIGHT_TOLERANCE);
closestSnap && updateActiveGuidelines(closestSnap);
// When snapping to the full width guideline, resize the table to be 1800px
const {
state,
dispatch
} = editorView;
const currentTableNodeLocalId = (_node$attrs$localId = node === null || node === void 0 ? void 0 : (_node$attrs = node.attrs) === null || _node$attrs === void 0 ? void 0 : _node$attrs.localId) !== null && _node$attrs$localId !== void 0 ? _node$attrs$localId : '';
const fullWidthGuideline = defaultGuidelinesForPreserveTable(PRESERVE_TABLE_GUIDELINES_LENGTH_OFFSET, editorContainerWidth, excludeGuidelineConfig).filter(guideline => guideline.isFullWidth)[0];
const isFullWidthGuidelineActive = expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true) ? closestSnap && fullWidthGuideline && closestSnap.keys.includes(fullWidthGuideline.key) : closestSnap && closestSnap.keys.includes(fullWidthGuideline.key);
const tableMaxWidth = isCommentEditor ? Math.floor(containerWidth - TABLE_OFFSET_IN_COMMENT_EDITOR) : expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true) ? TABLE_MAX_WIDTH : TABLE_FULL_WIDTH;
const shouldUpdateWidthToWidest = isCommentEditor ? tableMaxWidth <= newWidth : !!isTableScalingEnabled && isFullWidthGuidelineActive;
const previewParentWidth = isCommentEditor && shouldUpdateWidthToWidest ? tableMaxWidth : newWidth;
previewScaleTable(tableRef, {
node,
prevNode: node,
start: pos + 1,
parentWidth: previewParentWidth
}, editorView.domAtPos.bind(editorView), isTableScalingEnabled, allowFixedColumnWidthOption, isCommentEditor);
chainCommands((state, dispatch) => {
return switchToCenterAlignment(pos, node, newWidth, state, dispatch);
}, updateWidthToWidest({
[currentTableNodeLocalId]: shouldUpdateWidthToWidest
}))(state, dispatch);
updateWidth(shouldUpdateWidthToWidest ? tableMaxWidth : newWidth);
return newWidth;
}, [countFrames, isCommentEditor, isTableScalingEnabled, allowFixedColumnWidthOption, isFullWidthModeEnabled, excludeGuidelineConfig, tableRef, node, editorView, updateActiveGuidelines, containerWidth, lineLength, updateWidth, getPos, switchToCenterAlignment]);
const scheduleResize = useMemo(() => rafSchd(handleResize), [handleResize]);
const handleResizeStop = useCallback((originalState, delta) => {
var _node$attrs$localId2, _node$attrs2, _pluginInjectionApi$u3;
isResizing.current = false;
let newWidth = originalState.width + delta.width;
const originalNewWidth = newWidth;
const {
state,
dispatch
} = editorView;
const pos = getPos();
const currentTableNodeLocalId = (_node$attrs$localId2 = node === null || node === void 0 ? void 0 : (_node$attrs2 = node.attrs) === null || _node$attrs2 === void 0 ? void 0 : _node$attrs2.localId) !== null && _node$attrs$localId2 !== void 0 ? _node$attrs$localId2 : '';
const tableMaxWidth = isCommentEditor ? undefined // Table's full-width in comment appearance inherit the width of the Editor/Renderer
: expValEquals('editor_tinymce_full_width_mode', 'isEnabled', true) || expValEquals('confluence_max_width_content_appearance', 'isEnabled', true) ? TABLE_MAX_WIDTH : TABLE_FULL_WIDTH;
newWidth = widthToWidest && currentTableNodeLocalId && widthToWidest[currentTableNodeLocalId] ? tableMaxWidth : newWidth;
let tr = state.tr.setMeta(tableWidthPluginKey, {
resizing: false,
tableLocalId: '',
tableRef: null
});
tr.setMeta('is-resizer-resizing', false);
pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$u3 = pluginInjectionApi.userIntent) === null || _pluginInjectionApi$u3 === void 0 ? void 0 : _pluginInjectionApi$u3.commands.setCurrentUserIntent('default')({
tr
});
const frameRateSamples = endMeasure();
if (frameRateSamples.length > 0) {
const resizeFrameRatePayloads = generateResizeFrameRatePayloads({
docSize: state.doc.nodeSize,
frameRateSamples,
originalNode: node
});
resizeFrameRatePayloads.forEach(payload => {
var _attachAnalyticsEvent;
(_attachAnalyticsEvent = attachAnalyticsEvent(payload)) === null || _attachAnalyticsEvent === void 0 ? void 0 : _attachAnalyticsEvent(tr);
});
}
if (typeof pos === 'number') {
var _attachAnalyticsEvent2;
tr = tr.setNodeMarkup(pos, undefined, {
...node.attrs,
width: newWidth,
layout: node.attrs.layout !== ALIGN_START && node.attrs.layout !== ALIGN_CENTER ? ALIGN_CENTER : node.attrs.layout
});
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const newNode = tr.doc.nodeAt(pos);
tr = scaleTable(tableRef, {
node: newNode,
prevNode: node,
start: pos + 1,
// We use originalNewWidth in comment editor, because in comment editor
// newWidth can be underined when table is resized to 'full-width'
// scaleTable function needs number value to work correctly.
parentWidth: isCommentEditor ? originalNewWidth : newWidth
}, editorView.domAtPos.bind(editorView), pluginInjectionApi, isTableScalingEnabled, shouldUseIncreasedScalingPercent || false, isCommentEditor)(tr);
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const scaledNode = tr.doc.nodeAt(pos);
(_attachAnalyticsEvent2 = attachAnalyticsEvent(generateResizedPayload({
originalNode: node,
resizedNode: scaledNode
}))) === null || _attachAnalyticsEvent2 === void 0 ? void 0 : _attachAnalyticsEvent2(tr);
}
displayGapCursor(true);
dispatch(tr);
if (delta.width < 0 && newWidth !== undefined) {
var _pluginInjectionApi$a3;
pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a3 = pluginInjectionApi.accessibilityUtils) === null || _pluginInjectionApi$a3 === void 0 ? void 0 : _pluginInjectionApi$a3.actions.ariaNotify(formatMessage(messages.tableSizeDecreaseScreenReaderInformation, {
newWidth: newWidth
}));
} else if (delta.width > 0 && newWidth !== undefined) {
var _pluginInjectionApi$a4;
pluginInjectionApi === null || pluginInjectionApi === void 0 ? void 0 : (_pluginInjectionApi$a4 = pluginInjectionApi.accessibilityUtils) === null || _pluginInjectionApi$a4 === void 0 ? void 0 : _pluginInjectionApi$a4.actions.ariaNotify(formatMessage(messages.tableSizeIncreaseScreenReaderInformation, {
newWidth: newWidth
}));
}
// Hide guidelines when resizing stops
displayGuideline([]);
newWidth !== undefined && updateWidth(newWidth);
scheduleResize.cancel();
if (onResizeStop) {
onResizeStop();
}
if (expValEquals('cc_editor_interactivity_monitoring', 'isEnabled', true)) {
var _insm$session2;
(_insm$session2 = insm.session) === null || _insm$session2 === void 0 ? void 0 : _insm$session2.endFeature('tableResize');
}
return newWidth;
}, [editorView, getPos, node, isCommentEditor, widthToWidest, endMeasure, displayGapCursor, displayGuideline, updateWidth, scheduleResize, onResizeStop, pluginInjectionApi, attachAnalyticsEvent, tableRef, isTableScalingEnabled, shouldUseIncreasedScalingPercent, formatMessage]);
const handleTableSizeChangeOnKeypress = useCallback(step => {
const newWidth = width + step;
if (newWidth < resizerMinWidth) {
return;
}
handleResizeStop({
width: width,
x: 0,
y: 0,
height: 0
}, {
width: step,
height: 0
});
}, [width, handleResizeStop, resizerMinWidth]);
const handleEscape = useCallback(() => {
editorView === null || editorView === void 0 ? void 0 : editorView.focus();
}, [editorView]);
const handleKeyDown = useCallback(event => {
const isBracketKey = event.code === 'BracketRight' || event.code === 'BracketLeft';
const browser = expValEquals('platform_editor_hydratable_ui', 'isEnabled', true) ? getBrowserInfo() : browserLegacy;
const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
if (event.altKey || metaKey || event.shiftKey) {
areResizeMetaKeysPressed.current = true;
}
if (event.altKey && metaKey) {
if (isBracketKey) {
event.preventDefault();
handleTableSizeChangeOnKeypress(event.code === 'BracketRight' ? RESIZE_STEP_VALUE : -RESIZE_STEP_VALUE);
}
} else if (!areResizeMetaKeysPressed.current) {
handleEscape();
}
}, [handleEscape, handleTableSizeChangeOnKeypress]);
const handleKeyUp = useCallback(event => {
if (event.altKey || event.metaKey) {
areResizeMetaKeysPressed.current = false;
}
return;
}, [areResizeMetaKeysPressed]);
useLayoutEffect(() => {
if (!resizerRef.current) {
return;
}
const resizeHandleThumbEl = resizerRef.current.getResizerThumbEl();
const globalKeyDownHandler = event => {
const browser = expValEquals('platform_editor_hydratable_ui', 'isEnabled', true) ? getBrowserInfo() : browserLegacy;
const metaKey = browser.mac ? event.metaKey : event.ctrlKey;
if (!isTableSelected) {
return;
}
if (event.altKey && event.shiftKey && metaKey && event.code === 'KeyR') {
event.preventDefault();
if (!resizeHandleThumbEl) {
return;
}
resizeHandleThumbEl.focus();
resizeHandleThumbEl.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});
}
};
const editorViewDom = editorView === null || editorView === void 0 ? void 0 : editorView.dom;
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.addEventListener('keydown', globalKeyDownHandler);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.addEventListener('keydown', handleKeyDown);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.addEventListener('keyup', handleKeyUp);
return () => {
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
editorViewDom === null || editorViewDom === void 0 ? void 0 : editorViewDom.removeEventListener('keydown', globalKeyDownHandler);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.removeEventListener('keydown', handleKeyDown);
// Ignored via go/ees005
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
resizeHandleThumbEl === null || resizeHandleThumbEl === void 0 ? void 0 : resizeHandleThumbEl.removeEventListener('keyup', handleKeyUp);
};
}, [resizerRef, editorView, handleResizeStop, isTableSelected, handleKeyDown, handleKeyUp]);
useLayoutEffect(() => {
var _updateTooltip$curren;
(_updateTooltip$curren = updateTooltip.current) === null || _updateTooltip$curren === void 0 ? void 0 : _updateTooltip$curren.call(updateTooltip);
}, [width]);
const resizeRatio = !isTableAlignmentEnabled || isTableAlignmentEnabled && normaliseAlignment(node.attrs.layout) === ALIGN_CENTER ? 2 : 1;
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ResizerNext, {
ref: resizerRef,
enable: disabled ? {} : handles,
width: width,
handleAlignmentMethod: "sticky",
handleSize: handleSize,
handleStyles: handleStyles,
handleResizeStart: handleResizeStart,
handleResize: scheduleResize,
handleResizeStop: handleResizeStop,
resizeRatio: resizeRatio,
minWidth: resizerMinWidth,
maxWidth: maxWidth,
snapGap: TABLE_SNAP_GAP,
snap: guidelineSnaps,
handlePositioning: "adjacent",
isHandleVisible: isTableSelected,
needExtendedResizeZone: expValEquals('platform_editor_table_resizer_extended_zone', 'isEnabled', true) ? true : !isTableSelected,
appearance: isTableSelected && isWholeTableInDanger ? 'danger' : undefined,
handleHighlight: "shadow"
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
handleTooltipContent: ({
update
}) => {
updateTooltip.current = update;
return /*#__PURE__*/React.createElement(ToolTipContent, {
description: formatMessage(messages.resizeTable),
keymap: focusTableResizer
});
},
"data-vc-nvs": "true"
}, children));
};