diff --git a/.changeset/tall-badgers-reply.md b/.changeset/tall-badgers-reply.md new file mode 100644 index 00000000000..54c2dcc7d45 --- /dev/null +++ b/.changeset/tall-badgers-reply.md @@ -0,0 +1,7 @@ +--- +'@siemens/ix': patch +--- + +Prevent **ix-menu-category** from closing its dropdown during touch interaction. + +Fixes #2679 diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index 5b8a529625f..c555e9915ab 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -6131,7 +6131,7 @@ declare global { new (): HTMLIxMenuAvatarItemElement; }; interface HTMLIxMenuCategoryElementEventMap { - "closeOtherCategories": any; + "closeOtherCategories": string; } interface HTMLIxMenuCategoryElement extends Components.IxMenuCategory, HTMLStencilElement { addEventListener(type: K, listener: (this: HTMLIxMenuCategoryElement, ev: IxMenuCategoryCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; @@ -9943,7 +9943,7 @@ declare namespace LocalJSX { * Show notification count on the category */ "notifications"?: number; - "onCloseOtherCategories"?: (event: IxMenuCategoryCustomEvent) => void; + "onCloseOtherCategories"?: (event: IxMenuCategoryCustomEvent) => void; /** * Will be shown as tooltip text, if not provided menu text content will be used. * @since 4.0.0 diff --git a/packages/core/src/components/menu-category/menu-category.tsx b/packages/core/src/components/menu-category/menu-category.tsx index e1bf540549e..2bcaa0efd00 100644 --- a/packages/core/src/components/menu-category/menu-category.tsx +++ b/packages/core/src/components/menu-category/menu-category.tsx @@ -81,7 +81,7 @@ export class MenuCategory /** @internal */ @Event({ bubbles: true, cancelable: true }) - closeOtherCategories!: EventEmitter; + closeOtherCategories!: EventEmitter; @State() menuExpand = false; @State() showItems = false; @@ -171,7 +171,7 @@ export class MenuCategory if (this.ixMenu?.expand) { return; } - this.closeOtherCategories.emit(); + this.closeOtherCategories.emit(this.categoryId); if (this.dropdownRef.current) { const ref = dropdownController.getDropdownById( @@ -185,7 +185,11 @@ export class MenuCategory } @Listen('closeOtherCategories', { target: 'window' }) - private hideMenuItemDropdown() { + private hideMenuItemDropdown(event?: CustomEvent) { + if (event?.detail === this.categoryId) { + return; + } + if (this.dropdownRef.current) { const ref = dropdownController.getDropdownById( this.dropdownRef.current.dataset.ixDropdown! diff --git a/packages/core/src/components/menu-category/test/menu-category.ct.ts b/packages/core/src/components/menu-category/test/menu-category.ct.ts index e2392612c1f..0feaf0a5057 100644 --- a/packages/core/src/components/menu-category/test/menu-category.ct.ts +++ b/packages/core/src/components/menu-category/test/menu-category.ct.ts @@ -8,6 +8,22 @@ */ import { regressionTest, test, expect } from '@utils/test'; +regressionTest('accessibility', async ({ mount, makeAxeBuilder }) => { + await mount(` + + + + Test + Test + + + + `); + + const accessibilityScanResults = await makeAxeBuilder().analyze(); + expect(accessibilityScanResults.violations).toEqual([]); +}); + regressionTest('renders', async ({ mount, page }) => { await mount(` @@ -129,6 +145,71 @@ regressionTest('should show items as dropdown', async ({ mount, page }) => { await expect(itemTwo).toBeVisible(); }); +regressionTest( + 'should not close current category dropdown on own closeOtherCategories event', + async ({ mount, page }) => { + await mount(` + + + + Item 1 + + + Item 2 + + + + `); + + await page + .locator('ix-application') + .evaluate( + (menu: HTMLIxApplicationElement) => (menu.breakpoints = ['md']) + ); + + const categoryOne = page.locator('ix-menu-category').nth(0); + const dropdownOne = categoryOne.locator('ix-dropdown'); + + await categoryOne.hover(); + await expect(dropdownOne).toBeVisible(); + + const sourceCategoryId = await categoryOne + .locator('.category-parent') + .getAttribute('id'); + + expect(sourceCategoryId).toBeTruthy(); + + await page.evaluate((id) => { + window.dispatchEvent( + new CustomEvent('closeOtherCategories', { + detail: id, + bubbles: true, + composed: true, + }) + ); + }, sourceCategoryId); + + await expect(dropdownOne).toBeVisible(); + + const categoryTwo = page.locator('ix-menu-category').nth(1); + const dropdownTwo = categoryTwo.locator('ix-dropdown'); + await categoryTwo.hover(); + await expect(dropdownTwo).toBeVisible(); + + await page.evaluate((id) => { + window.dispatchEvent( + new CustomEvent('closeOtherCategories', { + detail: id, + bubbles: true, + composed: true, + }) + ); + }, sourceCategoryId); + + await expect(dropdownTwo).not.toBeVisible(); + } +); + regressionTest( 'should collapse category after collapse menu', async ({ mount, page }) => {