From c457dd87aeb77c420f2fdf97deca357b11983b29 Mon Sep 17 00:00:00 2001 From: Josh Black Date: Wed, 24 Jun 2026 17:44:33 -0500 Subject: [PATCH] feat: add React Compiler support for ActionMenu Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/react-compiler-action-menu.md | 5 ++ packages/react/script/react-compiler.mjs | 1 - .../react/src/ActionMenu/ActionMenu.test.tsx | 74 ++++++++++++------- 3 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 .changeset/react-compiler-action-menu.md diff --git a/.changeset/react-compiler-action-menu.md b/.changeset/react-compiler-action-menu.md new file mode 100644 index 00000000000..ada01379494 --- /dev/null +++ b/.changeset/react-compiler-action-menu.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +ActionMenu: Improve rendering performance with React Compiler support diff --git a/packages/react/script/react-compiler.mjs b/packages/react/script/react-compiler.mjs index 184c468cfc0..91ed6e93b8f 100644 --- a/packages/react/script/react-compiler.mjs +++ b/packages/react/script/react-compiler.mjs @@ -12,7 +12,6 @@ const files = glob return path.join(PACKAGE_DIR, match) }) const unsupportedPatterns = [ - 'src/ActionMenu/**/*.tsx', 'src/Autocomplete/**/*.tsx', 'src/AvatarStack/**/*.tsx', 'src/Banner/**/*.tsx', diff --git a/packages/react/src/ActionMenu/ActionMenu.test.tsx b/packages/react/src/ActionMenu/ActionMenu.test.tsx index 946e802fdc3..ced9dcc3100 100644 --- a/packages/react/src/ActionMenu/ActionMenu.test.tsx +++ b/packages/react/src/ActionMenu/ActionMenu.test.tsx @@ -82,8 +82,12 @@ function ExampleWithTooltip(): JSX.Element { ) } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function ExampleWithTooltipV2(actionMenuTrigger: React.ReactElement): JSX.Element { +function ExampleWithTooltipV2({ + actionMenuTrigger, +}: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + actionMenuTrigger: React.ReactElement +}): JSX.Element { return ( @@ -99,6 +103,8 @@ function ExampleWithTooltipV2(actionMenuTrigger: React.ReactElement): JSX.E } function ExampleWithReplaceableAnchor(): JSX.Element { + 'use no memo' + const anchorRef = useRef(null) const [open, setOpen] = useState(false) const [anchorKey, setAnchorKey] = useState(0) @@ -392,11 +398,13 @@ describe('ActionMenu', () => { it('should open menu on menu button click and it is wrapped with tooltip v2', async () => { const component = HTMLRender( - ExampleWithTooltipV2( - - Toggle Menu - , - ), + + Toggle Menu + + } + />, ) const button = component.getByRole('button') @@ -415,11 +423,13 @@ describe('ActionMenu', () => { it('should display tooltip v2 when menu button is focused', async () => { const component = HTMLRender( - ExampleWithTooltipV2( - - Toggle Menu - , - ), + + Toggle Menu + + } + />, ) const button = component.getByRole('button') act(() => { @@ -431,13 +441,15 @@ describe('ActionMenu', () => { it('should open menu on menu anchor click and it is wrapped with tooltip v2', async () => { const component = HTMLRender( - ExampleWithTooltipV2( - - - - - , - ), + + + + + + } + />, ) const button = component.getByRole('button') @@ -449,13 +461,15 @@ describe('ActionMenu', () => { it('should display tooltip v2 and menu anchor is focused', async () => { const component = HTMLRender( - ExampleWithTooltipV2( - - - - - , - ), + + + + + + } + />, ) const button = component.getByRole('button') act(() => { @@ -805,11 +819,15 @@ describe('ActionMenu', () => { const newAnchor = component.getByRole('button', {name: 'Open menu'}) expect(newAnchor).not.toBe(initialAnchor) + const newOverlay = component.baseElement.querySelector('[data-component="ActionMenu.Overlay"]') as HTMLElement + expect(newOverlay).not.toBeNull() // The new anchor should have the same anchor-name re-applied, and the // overlay should still reference it via position-anchor. - expect(newAnchor.style.getPropertyValue('anchor-name')).toBe(initialAnchorName) - expect(overlay.style.getPropertyValue('position-anchor')).toBe(initialPositionAnchor) + await waitFor(() => { + expect(newAnchor.style.getPropertyValue('anchor-name')).toBe(initialAnchorName) + expect(newOverlay.style.getPropertyValue('position-anchor')).toBe(initialPositionAnchor) + }) }) })