diff --git a/packages/accordion/src/vaadin-accordion-mixin.d.ts b/packages/accordion/src/vaadin-accordion-mixin.d.ts index bcddcd5998..bbda53e6cb 100644 --- a/packages/accordion/src/vaadin-accordion-mixin.d.ts +++ b/packages/accordion/src/vaadin-accordion-mixin.d.ts @@ -21,6 +21,12 @@ export declare class AccordionMixinClass { */ opened: number | null; + /** + * Indicates whether all the accordion panels are closed. + * Setting this property to true closes all the accordion panels. + */ + closed: boolean | null; + /** * The list of `` child elements. * It is populated from the elements passed to the light DOM, diff --git a/packages/accordion/src/vaadin-accordion-mixin.js b/packages/accordion/src/vaadin-accordion-mixin.js index 247d3427ef..9e06792e86 100644 --- a/packages/accordion/src/vaadin-accordion-mixin.js +++ b/packages/accordion/src/vaadin-accordion-mixin.js @@ -30,6 +30,16 @@ export const AccordionMixin = (superClass) => reflectToAttribute: true, }, + /** + * Indicates whether all the accordion panels are closed. + * Setting this property to true closes all the accordion panels. + */ + closed: { + type: Boolean, + notify: true, + reflectToAttribute: true, + }, + /** * The list of `` child elements. * It is populated from the elements passed to the light DOM, @@ -45,7 +55,7 @@ export const AccordionMixin = (superClass) => } static get observers() { - return ['_updateItems(items, opened)']; + return ['_updateItems(items, opened, closed)']; } constructor() { @@ -112,13 +122,21 @@ export const AccordionMixin = (superClass) => } /** @private */ - _updateItems(items, opened) { + _updateItems(items, opened, closed) { if (items) { this.__itemsSync = true; - const itemToOpen = items[opened]; - items.forEach((item) => { - item.opened = item === itemToOpen; - }); + if (closed) { + items.forEach((item) => { + item.opened = false; + }); + this.opened = null; + } else { + const itemToOpen = items[opened]; + items.forEach((item) => { + item.opened = item === itemToOpen; + }); + } + this.__itemsSync = false; } } @@ -147,6 +165,7 @@ export const AccordionMixin = (superClass) => if (this.__itemsSync) { return; } + const target = this._filterItems(e.composedPath())[0]; const idx = this.items.indexOf(target); if (e.detail.value) { @@ -155,8 +174,12 @@ export const AccordionMixin = (superClass) => } this.opened = idx; + this.closed = null; } else if (!this.items.some((item) => item.opened)) { this.opened = null; + this.closed = true; + } else { + this.closed = true; } } }; diff --git a/packages/accordion/test/accordion.test.js b/packages/accordion/test/accordion.test.js index c4e4f72d07..8753f01385 100644 --- a/packages/accordion/test/accordion.test.js +++ b/packages/accordion/test/accordion.test.js @@ -89,6 +89,7 @@ describe('vaadin-accordion', () => { it('should open the first panel by default', () => { expect(accordion.opened).to.equal(0); expect(accordion.items[0].opened).to.be.true; + expect(accordion.closed).to.be.null; }); it('should reflect opened property to attribute', () => { @@ -100,6 +101,7 @@ describe('vaadin-accordion', () => { await nextUpdate(accordion); expect(accordion.items[1].opened).to.be.true; expect(accordion.opened).to.equal(1); + expect(accordion.closed).to.be.null; }); it('should not update opened to new index when clicking disabled panel', async () => { @@ -108,6 +110,7 @@ describe('vaadin-accordion', () => { await nextUpdate(accordion); expect(accordion.items[1].opened).to.be.false; expect(accordion.opened).to.equal(0); + expect(accordion.closed).to.be.null; }); it('should close currently opened panel when another one is opened', async () => { @@ -115,19 +118,29 @@ describe('vaadin-accordion', () => { await nextUpdate(accordion); expect(accordion.items[1].opened).to.be.true; expect(accordion.items[0].opened).to.be.false; + expect(accordion.closed).to.be.null; }); - it('should set opened to null when the opened panel is closed', async () => { + it('should set opened to null and add closed to true when the opened panel is closed', async () => { getHeading(0).click(); await nextUpdate(accordion); expect(accordion.items[0].opened).to.be.false; expect(accordion.opened).to.equal(null); + expect(accordion.closed).to.be.true; }); it('should close currently opened panel when opened set to null', async () => { accordion.opened = null; await nextUpdate(accordion); expect(accordion.items[0].opened).to.be.false; + expect(accordion.closed).to.be.true; + }); + + it('should close currently opened panel when closed set to true', async () => { + accordion.closed = true; + await nextUpdate(accordion); + expect(accordion.items[0].opened).to.be.false; + expect(accordion.closed).to.be.true; }); it('should not change opened state if panel has been removed', async () => {