diff --git a/packages/uui-base/lib/mixins/SelectableMixin.ts b/packages/uui-base/lib/mixins/SelectableMixin.ts index 94c05dde3..af40771f9 100644 --- a/packages/uui-base/lib/mixins/SelectableMixin.ts +++ b/packages/uui-base/lib/mixins/SelectableMixin.ts @@ -75,11 +75,11 @@ export const SelectableMixin = >( constructor(...args: any[]) { super(...args); - this.addEventListener('click', this._handleClick); - this.addEventListener('keydown', this.handleSelectKeydown); + this.addEventListener('click', this.#onClick); + this.addEventListener('keydown', this.#onKeydown); } - private handleSelectKeydown = (e: KeyboardEvent) => { + readonly #onKeydown = (e: KeyboardEvent) => { const composePath = e.composedPath(); if ( (this._selectable || (this.deselectable && this.selected)) && @@ -87,13 +87,33 @@ export const SelectableMixin = >( ) { if (this.selectableTarget === this) { if (e.code !== 'Space' && e.code !== 'Enter') return; - this._toggleSelect(); + this.#toggleSelect(); e.preventDefault(); } } }; - private _select() { + readonly #onClick = (e: Event) => { + const composePath = e.composedPath(); + if ( + (this._selectable || (this.deselectable && this.selected)) && + composePath.indexOf(this.selectableTarget) === 0 + ) { + this.#toggleSelect(); + } + }; + + #toggleSelect() { + // Only allow for select-interaction if selectable is true. Deselectable is ignored in this case, we do not want a DX where only deselection is a possibility.. + if (!this.selectable) return; + if (this.deselectable === false) { + this.#select(); + } else { + this.selected ? this.#deselect() : this.#select(); + } + } + + #select() { if (!this.selectable) return; const selectEvent = new UUISelectableEvent(UUISelectableEvent.SELECTED); this.dispatchEvent(selectEvent); @@ -102,7 +122,7 @@ export const SelectableMixin = >( this.selected = true; } - private _deselect() { + #deselect() { if (!this.deselectable) return; const selectEvent = new UUISelectableEvent(UUISelectableEvent.DESELECTED); this.dispatchEvent(selectEvent); @@ -110,22 +130,6 @@ export const SelectableMixin = >( this.selected = false; } - - private _handleClick(e: Event) { - if (e.composedPath().indexOf(this.selectableTarget) !== -1) { - this._toggleSelect(); - } - } - - private _toggleSelect() { - // Only allow for select-interaction if selectable is true. Deselectable is ignored in this case, we do not want a DX where only deselection is a possibility.. - if (!this.selectable) return; - if (this.deselectable === false) { - this._select(); - } else { - this.selected ? this._deselect() : this._select(); - } - } } // prettier-ignore return (SelectableMixinClass as unknown) as Constructor & T; diff --git a/packages/uui-card-media/lib/uui-card-media.test.ts b/packages/uui-card-media/lib/uui-card-media.test.ts index 08b577422..6d55dda48 100644 --- a/packages/uui-card-media/lib/uui-card-media.test.ts +++ b/packages/uui-card-media/lib/uui-card-media.test.ts @@ -99,6 +99,35 @@ describe('UUICardMediaElement', () => { expect(event.type).to.equal(UUISelectableEvent.SELECTED); expect(element.selected).to.be.true; }); + it('do react to a click event on performed in this way', async () => { + element.selectable = true; + await elementUpdated(element); + element.click(); + await Promise.resolve(); + expect(element.selected).to.be.true; + }); + it('do not react to a click event on other parts', async () => { + element.selectable = true; + await elementUpdated(element); + const listener = oneEvent(element, UUICardEvent.OPEN); + element + .shadowRoot!.querySelector('#open-part')! + .click(); + const event = await listener; + expect(event).to.exist; + expect(event.type).to.equal(UUICardEvent.OPEN); + expect(element.selected).to.be.false; + }); + it('do not react to a click event on other parts as href', async () => { + element.selectable = true; + element.href = '#hello'; + await elementUpdated(element); + element + .shadowRoot!.querySelector('#open-part')! + .click(); + await Promise.resolve(); + expect(element.selected).to.be.false; + }); it('can be selected with keyboard', async () => { element.selectable = true; await elementUpdated(element);