From 14edf41e57fea1ddbb2cf24c37e79475849bdea1 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Fri, 5 Sep 2025 08:09:07 -0700 Subject: [PATCH] fix(overflow-menu): avoid dynamic style injection for performance (#2198) Fixes #2197 --- src/OverflowMenu/OverflowMenu.svelte | 20 ++++++----- tests/OverflowMenu/OverflowMenu.test.ts | 46 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/OverflowMenu/OverflowMenu.svelte b/src/OverflowMenu/OverflowMenu.svelte index 6287a091..43a88547 100644 --- a/src/OverflowMenu/OverflowMenu.svelte +++ b/src/OverflowMenu/OverflowMenu.svelte @@ -167,17 +167,12 @@ $: if ($items[$currentIndex]) { focusedId.set($items[$currentIndex].id); } - $: styles = ` diff --git a/tests/OverflowMenu/OverflowMenu.test.ts b/tests/OverflowMenu/OverflowMenu.test.ts index 59b07a29..ed20fb74 100644 --- a/tests/OverflowMenu/OverflowMenu.test.ts +++ b/tests/OverflowMenu/OverflowMenu.test.ts @@ -81,4 +81,50 @@ describe("OverflowMenu", () => { await user.click(document.body); expect(menuButton).toHaveAttribute("aria-expanded", "false"); }); + + it("uses CSS custom properties for performance optimization", async () => { + const { container } = render(OverflowMenu); + + const styleTags = document.querySelectorAll("style"); + const initialStyleCount = styleTags.length; + expect(styleTags.length).toBe(initialStyleCount); + + await user.click(screen.getByRole("button")); + expect(container.querySelector(".bx--overflow-menu-options")).toHaveStyle( + "--overflow-menu-options-after-width: 2rem", + ); + expect(styleTags.length).toBe(initialStyleCount); + }); + + it("stress test: multiple instances don't create individual style tags", async () => { + const { container: container1 } = render(OverflowMenu); + const { container: container2 } = render(OverflowMenu); + const { container: container3 } = render(OverflowMenu); + + const styleTagsBefore = document.querySelectorAll("style").length; + const menuButtons1 = container1.querySelectorAll("button"); + const menuButtons2 = container2.querySelectorAll("button"); + const menuButtons3 = container3.querySelectorAll("button"); + + await user.click(menuButtons1[0]); + await user.click(menuButtons2[0]); + await user.click(menuButtons3[0]); + + const styleTagsAfter = document.querySelectorAll("style").length; + + // Verify no additional style tags created (old approach would create 3+) + expect(styleTagsAfter).toBe(styleTagsBefore); + + // Verify all menus have CSS custom property set. + const allMenus = [ + ...container1.querySelectorAll(".bx--overflow-menu-options"), + ...container2.querySelectorAll(".bx--overflow-menu-options"), + ...container3.querySelectorAll(".bx--overflow-menu-options"), + ]; + + expect(allMenus.length).toBeGreaterThan(0); + allMenus.forEach((menu) => { + expect(menu).toHaveStyle("--overflow-menu-options-after-width: 2rem"); + }); + }); });