diff --git a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs index 06444e79f94..cca10f327de 100644 --- a/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Tables.spec.mjs @@ -6181,4 +6181,60 @@ test.describe.parallel('Tables', () => { ), ); }); + + test(`Table action menu is hidden when cell overflows`, async ({ + page, + isPlainText, + isCollab, + browserName, + }) => { + // The way that the clicks happen in test doesn't work in firefox for some reason + // but it does seem to work when you do it by hand + test.fixme(browserName === 'firefox'); + test.skip(isPlainText || isCollab); + await initialize({isCollab, page}); + await focusEditor(page); + + // Insert a 2x2 table + await insertTable(page, 2, 2); + + // Find and drag the column resize handle + const firstCell = await page.$('th >> nth=0'); + const firstCellBox = await firstCell.boundingBox(); + + // Click the cell in 2nd column + await click(page, 'th >> nth=1'); + + // Check that the action menu button is visible when no overflow + const menuVisible = await page.evaluate(() => { + const button = document.querySelector('.table-cell-action-button'); + // If button exists, menu is visible + return !!button; + }); + + expect(menuVisible).toBe(true); + + // Make the column very wide to ensure overflow + await page.mouse.move( + firstCellBox.x + firstCellBox.width - 5, + firstCellBox.y + firstCellBox.height / 2, + ); + await page.mouse.down(); + await page.mouse.move( + firstCellBox.x + 2000, // Make column very wide - 2000 for more scroll space + firstCellBox.y + firstCellBox.height / 2, + ); + await page.mouse.up(); + + // Click the cell + await click(page, 'th >> nth=0'); + + const menuHidden = await page.evaluate(() => { + const button = document.querySelector('.table-cell-action-button'); + // If button doesn't exist, menu is hidden + return !button; + }); + + expect(menuHidden).toBe(true); + }); }); diff --git a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx index d41fc95928a..b2f2065de38 100644 --- a/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx +++ b/packages/lexical-playground/src/plugins/TableActionMenuPlugin/index.tsx @@ -801,6 +801,35 @@ function TableCellActionMenuContainer({ const [colorPickerModal, showColorPickerModal] = useModal(); + const checkTableCellOverflow = useCallback( + (tableCellParentNodeDOM: HTMLElement): boolean => { + const scrollableContainer = tableCellParentNodeDOM.closest( + '.PlaygroundEditorTheme__tableScrollableWrapper', + ); + if (scrollableContainer) { + const containerRect = ( + scrollableContainer as HTMLElement + ).getBoundingClientRect(); + const cellRect = tableCellParentNodeDOM.getBoundingClientRect(); + + // Calculate where the action button would be positioned (5px from right edge of cell) + // Also account for the button width and table cell padding (8px) + const actionButtonRight = cellRect.right - 5; + const actionButtonLeft = actionButtonRight - 28; // 20px width + 8px padding + + // Only hide if the action button would overflow the container + if ( + actionButtonRight > containerRect.right || + actionButtonLeft < containerRect.left + ) { + return true; + } + } + return false; + }, + [], + ); + const $moveMenu = useCallback(() => { const menu = menuButtonRef.current; const selection = $getSelection(); @@ -847,6 +876,10 @@ function TableCellActionMenuContainer({ return disable(); } + if (checkTableCellOverflow(tableCellParentNodeDOM)) { + return disable(); + } + const tableNode = $getTableNodeFromLexicalNodeOrThrow( tableCellNodeFromSelection, ); @@ -881,6 +914,14 @@ function TableCellActionMenuContainer({ ); tableObserver = getTableObserverFromTableElement(tableElement); tableCellParentNodeDOM = editor.getElementByKey(anchorNode.getKey()); + + if (tableCellParentNodeDOM === null) { + return disable(); + } + + if (checkTableCellOverflow(tableCellParentNodeDOM)) { + return disable(); + } } else if (!activeElement) { return disable(); } @@ -903,7 +944,7 @@ function TableCellActionMenuContainer({ const left = tableCellRect.right - anchorRect.left; menu.style.transform = `translate(${left}px, ${top}px)`; } - }, [editor, anchorElem]); + }, [editor, anchorElem, checkTableCellOverflow]); useEffect(() => { // We call the $moveMenu callback every time the selection changes,