From 2401b2ee27d4975cbe77bab2c6300abc791f4310 Mon Sep 17 00:00:00 2001 From: Lukas Maurer Date: Fri, 13 Sep 2024 13:51:38 +0200 Subject: [PATCH] =?UTF-8?q?fix(core/tree):=20prevent=20hyperlist=20from=20?= =?UTF-8?q?disposing=20dropdowns=20linked=20to=20=E2=80=A6=20(#1460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Leroux --- .changeset/spicy-ravens-care.md | 5 ++ packages/angular/src/components.ts | 2 +- packages/core/component-doc.json | 2 +- packages/core/src/components.d.ts | 2 +- .../src/components/tree-item/tree-item.tsx | 2 +- .../core/src/components/tree/test/tree.ct.ts | 58 +++++++++++++++++++ packages/core/src/components/tree/tree.tsx | 23 ++++++-- .../src/components/Accordion/accordion.scss | 4 ++ 8 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 .changeset/spicy-ravens-care.md diff --git a/.changeset/spicy-ravens-care.md b/.changeset/spicy-ravens-care.md new file mode 100644 index 00000000000..f377f150e06 --- /dev/null +++ b/.changeset/spicy-ravens-care.md @@ -0,0 +1,5 @@ +--- +"@siemens/ix": patch +--- + +fix(core/tree): prevent hyperlist from disposing dropdowns linked to tree items diff --git a/packages/angular/src/components.ts b/packages/angular/src/components.ts index 877b9a5d565..9eb6d100afe 100644 --- a/packages/angular/src/components.ts +++ b/packages/angular/src/components.ts @@ -2349,7 +2349,7 @@ export declare interface IxTreeItem extends Components.IxTreeItem { */ toggle: EventEmitter>; /** - * Clicked + * Click on item not on the expand/collapse icon */ itemClick: EventEmitter>; } diff --git a/packages/core/component-doc.json b/packages/core/component-doc.json index e3e9fa69e5c..b5162896243 100644 --- a/packages/core/component-doc.json +++ b/packages/core/component-doc.json @@ -16582,7 +16582,7 @@ }, "cancelable": true, "composed": true, - "docs": "Clicked", + "docs": "Click on item not on the expand/collapse icon", "docsTags": [] }, { diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index 730da09e6c2..03f40e0d391 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -6600,7 +6600,7 @@ declare namespace LocalJSX { */ "hasChildren"?: boolean; /** - * Clicked + * Click on item not on the expand/collapse icon */ "onItemClick"?: (event: IxTreeItemCustomEvent) => void; /** diff --git a/packages/core/src/components/tree-item/tree-item.tsx b/packages/core/src/components/tree-item/tree-item.tsx index 9886da17351..bcf829eac0e 100644 --- a/packages/core/src/components/tree-item/tree-item.tsx +++ b/packages/core/src/components/tree-item/tree-item.tsx @@ -37,7 +37,7 @@ export class TreeItem { @Event() toggle!: EventEmitter; /** - * Clicked + * Click on item not on the expand/collapse icon */ @Event() itemClick!: EventEmitter; diff --git a/packages/core/src/components/tree/test/tree.ct.ts b/packages/core/src/components/tree/test/tree.ct.ts index 3df9e3d3ca2..c3241744925 100644 --- a/packages/core/src/components/tree/test/tree.ct.ts +++ b/packages/core/src/components/tree/test/tree.ct.ts @@ -8,6 +8,7 @@ */ import { expect, Locator, Page } from '@playwright/test'; import { test } from '@utils/test'; +import { TreeItem } from '../tree-model'; const defaultModel = { root: { @@ -171,3 +172,60 @@ test('update tree', async ({ mount, page }) => { await expect(newChildItem).toBeVisible(); await expect(newChildItem).toHaveCSS('padding-left', '32px'); }); + +test('dropdown trigger', async ({ mount, page }) => { + const tree = await initializeTree(mount, page); + + await tree.evaluate( + (t) => + ((t as HTMLIxTreeElement).renderItem = ( + _index, + item, + _dataList, + context, + update + ) => { + const el = document.createElement('ix-tree-item'); + const treeItem = item as TreeItem; + el.hasChildren = treeItem.hasChildren; + el.context = context[treeItem.id]; + el.id = `trigger-${treeItem.id}`; + + const div = document.createElement('div'); + div.style.display = 'flex'; + + const name = document.createElement('span'); + const dd = document.createElement('ix-dropdown'); + const ddItem = document.createElement('ix-dropdown-item'); + ddItem.innerHTML = 'Action 1'; + dd.trigger = `trigger-${treeItem.id}`; + + div.appendChild(name); + div.appendChild(dd); + dd.appendChild(ddItem); + + name.innerText = treeItem.id; + + el.appendChild(div); + + update((updateTreeItem) => { + name.innerText = updateTreeItem.data.name; + }); + + return el; + }) + ); + + const root = tree.locator('ix-tree-item').first(); + await root.locator('.icon-toggle-container').click(); + + const item1 = tree.locator('ix-tree-item').nth(1); + const dropdown1 = item1.locator('ix-dropdown'); + await item1.click(); + await expect(dropdown1).toBeVisible(); + + const item2 = tree.locator('ix-tree-item').nth(2); + const dropdown2 = item2.locator('ix-dropdown'); + await item2.click(); + await expect(dropdown2).toBeVisible(); +}); diff --git a/packages/core/src/components/tree/tree.tsx b/packages/core/src/components/tree/tree.tsx index ae26e665f55..0c52fd177de 100644 --- a/packages/core/src/components/tree/tree.tsx +++ b/packages/core/src/components/tree/tree.tsx @@ -27,6 +27,7 @@ import { TreeModel, UpdateCallback, } from './tree-model'; +import { dropdownController } from '../dropdown/dropdown-controller'; @Component({ tag: 'ix-tree', @@ -173,16 +174,30 @@ export class Tree { this.updatePadding(el, item); if (!this.itemClickListener.has(el)) { - const itemClickCallback = (e: Event) => { - e.preventDefault(); - e.stopPropagation(); + const itemClickCallback = (event: Event) => { + const path = event.composedPath(); + const treeIndex = path.indexOf(this.hostElement); + const treePath = path.slice(0, treeIndex); + const hasTrigger = dropdownController.pathIncludesTrigger(treePath); + + if (event.defaultPrevented) { + return; + } + + if (hasTrigger) { + return; + } + Object.values(this.context).forEach((c) => (c.isSelected = false)); const context = this.getContext(item.id); context.isSelected = true; this.setContext(item.id, context); this.nodeClicked.emit(item.id); }; - el.addEventListener('itemClick', itemClickCallback); + el.addEventListener('toggle', (event) => { + event.preventDefault(); + }); + el.addEventListener('click', itemClickCallback); this.itemClickListener.set(el, itemClickCallback); } diff --git a/packages/documentation/src/components/Accordion/accordion.scss b/packages/documentation/src/components/Accordion/accordion.scss index 5188b6247d5..128eaa0dce9 100644 --- a/packages/documentation/src/components/Accordion/accordion.scss +++ b/packages/documentation/src/components/Accordion/accordion.scss @@ -7,6 +7,10 @@ * LICENSE file in the root directory of this source tree. */ +.Accordion > a { + display: flex; +} + .Accordion.Accordion__Last { border-block-end: solid 1px var(--theme-color-contrast-bdr); }