From 8b58f98a829fa93e2278ad041bf136cc9ed8b354 Mon Sep 17 00:00:00 2001 From: Material Web Team Date: Wed, 22 Feb 2023 09:55:50 -0800 Subject: [PATCH] fix(controller)!: fix label activation utility on slotted elements PiperOrigin-RevId: 511523410 --- controller/events.ts | 4 ++++ controller/events_test.ts | 27 +++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/controller/events.ts b/controller/events.ts index 3911aa487c..4be1b4ee7d 100644 --- a/controller/events.ts +++ b/controller/events.ts @@ -97,6 +97,10 @@ export function dispatchActivationClick(element: HTMLElement) { */ export function isActivationClick(event: Event) { // Event must start at the event target. + if (event.currentTarget !== event.target) { + return false; + } + // Event must not be retargeted from shadowRoot. if (event.composedPath()[0] !== event.target) { return false; } diff --git a/controller/events_test.ts b/controller/events_test.ts index 367ce70ee8..18505ef786 100644 --- a/controller/events_test.ts +++ b/controller/events_test.ts @@ -13,7 +13,8 @@ describe('events', () => { beforeEach(() => { instance = document.createElement('div'); - instance.attachShadow({mode: 'open'}); + instance.attachShadow({mode: 'open'}) + .append(document.createElement('slot')); // To have event.target set correctly, the EventTarget instance must be // attached to the DOM. document.body.appendChild(instance); @@ -113,7 +114,7 @@ describe('events', () => { }); describe('isActivationClick()', () => { - it('should return true only if the event originated from target', () => { + it('returns true for click on listener', () => { const listener = jasmine.createSpy('listener', isActivationClick); listener.and.callThrough(); instance.addEventListener('click', listener); @@ -121,12 +122,30 @@ describe('events', () => { new MouseEvent('click', {bubbles: true, composed: true})); expect(listener).toHaveBeenCalledTimes(1); expect(listener.calls.mostRecent().returnValue).toBe(true); + }); + + it('returns false for click on element listener shadowRoot', () => { + const listener = jasmine.createSpy('listener', isActivationClick); + listener.and.callThrough(); + instance.addEventListener('click', listener); const innerEl = document.createElement('div'); instance.shadowRoot!.append(innerEl); - innerEl.dispatchEvent( new MouseEvent('click', {bubbles: true, composed: true})); - expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenCalledTimes(1); + expect(listener.calls.mostRecent().returnValue).toBe(false); + }); + + it('returns false for click on element listener child', () => { + const listener = jasmine.createSpy('listener', isActivationClick); + listener.and.callThrough(); + instance.addEventListener('click', listener); + const slottedEl = document.createElement('div'); + instance.append(slottedEl); + + slottedEl.dispatchEvent( + new MouseEvent('click', {bubbles: true, composed: true})); + expect(listener).toHaveBeenCalledTimes(1); expect(listener.calls.mostRecent().returnValue).toBe(false); }); });