mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 02:11:05 +00:00
fix(overflow-menu): avoid dynamic style injection for performance
Fixes #2197
This commit is contained in:
parent
cf267b9ad5
commit
a512d02005
2 changed files with 57 additions and 9 deletions
|
@ -167,17 +167,12 @@
|
||||||
$: if ($items[$currentIndex]) {
|
$: if ($items[$currentIndex]) {
|
||||||
focusedId.set($items[$currentIndex].id);
|
focusedId.set($items[$currentIndex].id);
|
||||||
}
|
}
|
||||||
$: styles = `<style>
|
// Use CSS custom properties instead of dynamic style injection for better
|
||||||
#${id} .bx--overflow-menu-options.bx--overflow-menu-options:after {
|
// performance. The previous approach created individual `style` tags per
|
||||||
width: ${buttonWidth ? buttonWidth + "px" : "2rem"};
|
// instance, causing overhead when many OverflowMenu components are rendered.
|
||||||
}
|
$: overflowMenuOptionsAfterWidth = buttonWidth ? buttonWidth + "px" : "2rem";
|
||||||
<\/style>`;
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
|
||||||
{@html styles}
|
|
||||||
</svelte:head>
|
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
on:click={({ target }) => {
|
on:click={({ target }) => {
|
||||||
if (buttonRef && buttonRef.contains(target)) return;
|
if (buttonRef && buttonRef.contains(target)) return;
|
||||||
|
@ -252,8 +247,15 @@
|
||||||
class:bx--overflow-menu-options--xl={size === "xl"}
|
class:bx--overflow-menu-options--xl={size === "xl"}
|
||||||
class:bx--breadcrumb-menu-options={!!ctxBreadcrumbItem}
|
class:bx--breadcrumb-menu-options={!!ctxBreadcrumbItem}
|
||||||
class={menuOptionsClass}
|
class={menuOptionsClass}
|
||||||
|
style="--overflow-menu-options-after-width: {overflowMenuOptionsAfterWidth}"
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
</ul>
|
</ul>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.bx--overflow-menu-options:after {
|
||||||
|
width: var(--overflow-menu-options-after-width, 2rem);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -81,4 +81,50 @@ describe("OverflowMenu", () => {
|
||||||
await user.click(document.body);
|
await user.click(document.body);
|
||||||
expect(menuButton).toHaveAttribute("aria-expanded", "false");
|
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");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue