From 3f76e04fb71ad263e067838050bd550c009b1a69 Mon Sep 17 00:00:00 2001 From: Nick Schaap Date: Tue, 3 Oct 2023 13:38:35 -0400 Subject: [PATCH] fix(action-button): allow change events to bubble and pierce shadowdom (#3614) * fix(action-button): allow change events to bubble and pierce shadowdom * fix(action-group): guarantee one `change` event when children toggle --------- Co-authored-by: Westbrook Johnson --- packages/action-button/src/ActionButton.ts | 2 + packages/action-group/src/ActionGroup.ts | 16 ++++++++ .../action-group/test/action-group.test.ts | 40 +++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/packages/action-button/src/ActionButton.ts b/packages/action-button/src/ActionButton.ts index 5651c09dc4..b88858d19b 100644 --- a/packages/action-button/src/ActionButton.ts +++ b/packages/action-button/src/ActionButton.ts @@ -127,6 +127,8 @@ export class ActionButton extends SizedMixin(ButtonBase, { const applyDefault = this.dispatchEvent( new Event('change', { cancelable: true, + bubbles: true, + composed: true, }) ); if (!applyDefault) { diff --git a/packages/action-group/src/ActionGroup.ts b/packages/action-group/src/ActionGroup.ts index 991b8cf79e..d5ae37d3e9 100644 --- a/packages/action-group/src/ActionGroup.ts +++ b/packages/action-group/src/ActionGroup.ts @@ -183,6 +183,11 @@ export class ActionGroup extends SizedMixin(SpectrumElement, { }); } + private handleActionButtonChange(event: Event): void { + event.stopPropagation(); + event.preventDefault(); + } + private handleClick(event: Event): void { const target = event.target as ActionButton; if (typeof target.value === 'undefined') { @@ -339,6 +344,17 @@ export class ActionGroup extends SizedMixin(SpectrumElement, { if (changes.has('selects')) { this.manageSelects(); this.manageChildren(); + if (!!this.selects) { + this.shadowRoot.addEventListener( + 'change', + this.handleActionButtonChange + ); + } else { + this.shadowRoot.removeEventListener( + 'change', + this.handleActionButtonChange + ); + } } if ( changes.has('quiet') || diff --git a/packages/action-group/test/action-group.test.ts b/packages/action-group/test/action-group.test.ts index 5ba7555b0d..66c268f331 100644 --- a/packages/action-group/test/action-group.test.ts +++ b/packages/action-group/test/action-group.test.ts @@ -535,6 +535,46 @@ describe('ActionGroup', () => { 'Updates value of `selected`' ); }); + it('consumes descendant `change` events when `[selects]`', async () => { + const changeSpy = spy(); + const el = await fixture( + html` + changeSpy()} + label="Selects Single Group" + selects="single" + > + + First + + + Second + + + Third + + + ` + ); + const thirdElement = el.querySelector('.third') as ActionButton; + + await elementUpdated(el); + expect(el.selected.length).to.equal(1); + expect(el.selected.includes('second')); + expect(changeSpy.callCount).to.equal(0); + + thirdElement.click(); + + await elementUpdated(el); + + expect(thirdElement.selected, 'third child selected').to.be.true; + expect(changeSpy.callCount).to.equal(1); + + await waitUntil( + () => el.selected.length === 1 && el.selected.includes('third'), + 'Updates value of `selected`' + ); + }); it('does not respond to clicks on itself', async () => { const el = await fixture( html`