diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 982d5e275..cf710c7a6 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -20,6 +20,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti - Fixed a bug in `` that caused the focus color to show when selecting menu items with a mouse or touch device - Fixed a bug in `` that caused `sl-change` and `sl-input` to be emitted too early [#1201](https://github.com/shoelace-style/shoelace/issues/1201) - Fixed a positioning edge case that caused `` to positioned nested popups incorrectly [#1135](https://github.com/shoelace-style/shoelace/issues/1135) +- Fixed a bug in `` that caused the tree item to collapse when clicking a child item, dragging the mouse, and releasing it on the parent node [#1082](https://github.com/shoelace-style/shoelace/issues/1082) - Updated `@shoelace-style/localize` to 3.1.0 - Updated `@floating-ui/dom` to 1.2.1 diff --git a/src/components/tree/tree.ts b/src/components/tree/tree.ts index 608783551..22f9c3ebf 100644 --- a/src/components/tree/tree.ts +++ b/src/components/tree/tree.ts @@ -90,6 +90,7 @@ export default class SlTree extends ShoelaceElement { private lastFocusedItem: SlTreeItem; private readonly localize = new LocalizeController(this); private mutationObserver: MutationObserver; + private clickTarget: SlTreeItem | null = null; async connectedCallback() { super.connectedCallback(); @@ -292,13 +293,20 @@ export default class SlTree extends ShoelaceElement { } private handleClick(event: Event) { - const target = event.target as HTMLElement; + const target = event.target as SlTreeItem; const treeItem = target.closest('sl-tree-item')!; const isExpandButton = event .composedPath() .some((el: HTMLElement) => el?.classList?.contains('tree-item__expand-button')); - if (!treeItem || treeItem.disabled) { + // + // Don't Do anything if there's no tree item, if it's disabled, or if the click doesn't match the initial target + // from mousedown. The latter case prevents the user from starting a click on one item and ending it on another, + // causing the parent node to collapse. + // + // See https://github.com/shoelace-style/shoelace/issues/1082 + // + if (!treeItem || treeItem.disabled || target !== this.clickTarget) { return; } @@ -309,6 +317,11 @@ export default class SlTree extends ShoelaceElement { } } + handleMouseDown(event: MouseEvent) { + // Record the click target so we know which item the click initially targeted + this.clickTarget = event.target as SlTreeItem; + } + private handleFocusOut(event: FocusEvent) { const relatedTarget = event.relatedTarget as HTMLElement; @@ -392,7 +405,13 @@ export default class SlTree extends ShoelaceElement { render() { return html` -
+
diff --git a/src/internal/test.ts b/src/internal/test.ts index e4dc703c7..a1f10dad8 100644 --- a/src/internal/test.ts +++ b/src/internal/test.ts @@ -50,6 +50,7 @@ export async function clickOnElement( await sendMouse({ type: 'click', position: [clickX, clickY] }); } +/** A testing utility that moves the mouse onto an element. */ export async function moveMouseOnElement( /** The element to click */ el: Element,