Skip to content

Commit da84c10

Browse files
fix(accordion): panel checkbox collapsing panel on check (#2538)
* fix(accordion): updating collapse to check for index value before closing panel * chore: changeset * fix(accordion): typecheck in onchange function, removing deprecated code * fix(accordion): instanceof check for change events * docs: update .changeset/neat-colts-jam.md --------- Co-authored-by: Benny Powers <[email protected]> Co-authored-by: Benny Powers <[email protected]>
1 parent dbbe167 commit da84c10

File tree

4 files changed

+69
-70
lines changed

4 files changed

+69
-70
lines changed

.changeset/neat-colts-jam.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@patternfly/elements": patch
3+
---
4+
5+
`<pf-accordion>`: fixed bug which would collapse a panel if it contained a checkbox which got toggled.

elements/pf-accordion/BaseAccordion.ts

Lines changed: 11 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ export abstract class BaseAccordion extends LitElement {
4848
return target instanceof BaseAccordionPanel;
4949
}
5050

51+
static #isAccordionChangeEvent(event: Event): event is AccordionHeaderChangeEvent {
52+
return event instanceof AccordionHeaderChangeEvent;
53+
}
54+
5155
#headerIndex = new RovingTabindexController<BaseAccordionHeader>(this);
5256

5357
#expandedIndex: number[] = [];
@@ -265,51 +269,14 @@ export abstract class BaseAccordion extends LitElement {
265269
}
266270

267271
#onChange(event: AccordionHeaderChangeEvent) {
268-
if (this.classList.contains('animating')) {
269-
return;
270-
}
271-
272-
const index = this.#getIndex(event.target as Element);
273-
274-
if (event.expanded) {
275-
this.expand(index, event.accordion);
276-
} else {
277-
this.collapse(index);
278-
}
279-
}
280-
281-
/**
282-
* @see https://www.w3.org/TR/wai-aria-practices/#accordion
283-
*/
284-
async #onKeydown(evt: KeyboardEvent) {
285-
const currentHeader = evt.target as Element;
286-
287-
if (!BaseAccordion.isHeader(currentHeader)) {
288-
return;
289-
}
290-
291-
let newHeader: BaseAccordionHeader | undefined;
292-
293-
switch (evt.key) {
294-
case 'ArrowDown':
295-
evt.preventDefault();
296-
newHeader = this.#nextHeader();
297-
break;
298-
case 'ArrowUp':
299-
evt.preventDefault();
300-
newHeader = this.#previousHeader();
301-
break;
302-
case 'Home':
303-
evt.preventDefault();
304-
newHeader = this.#firstHeader();
305-
break;
306-
case 'End':
307-
evt.preventDefault();
308-
newHeader = this.#lastHeader();
309-
break;
272+
if (BaseAccordion.#isAccordionChangeEvent(event) && !this.classList.contains('animating')) {
273+
const index = this.#getIndex(event.target);
274+
if (event.expanded) {
275+
this.expand(index, event.accordion);
276+
} else {
277+
this.collapse(index);
278+
}
310279
}
311-
312-
newHeader?.focus?.();
313280
}
314281

315282
#allHeaders(accordion: BaseAccordion = this): BaseAccordionHeader[] {
@@ -320,26 +287,6 @@ export abstract class BaseAccordion extends LitElement {
320287
return Array.from(accordion.children).filter(BaseAccordion.isPanel);
321288
}
322289

323-
#previousHeader() {
324-
const { headers } = this;
325-
const newIndex = headers.findIndex(header => header.matches(':focus,:focus-within')) - 1;
326-
return headers[(newIndex + headers.length) % headers.length];
327-
}
328-
329-
#nextHeader() {
330-
const { headers } = this;
331-
const newIndex = headers.findIndex(header => header.matches(':focus,:focus-within')) + 1;
332-
return headers[newIndex % headers.length];
333-
}
334-
335-
#firstHeader() {
336-
return this.headers.at(0);
337-
}
338-
339-
#lastHeader() {
340-
return this.headers.at(-1);
341-
}
342-
343290
#getIndex(el: Element | null) {
344291
if (BaseAccordion.isHeader(el)) {
345292
return this.headers.findIndex(header => header.id === el.id);
@@ -386,10 +333,6 @@ export abstract class BaseAccordion extends LitElement {
386333
* Accepts an optional parent accordion to search for headers and panels.
387334
*/
388335
public async expand(index: number, parentAccordion?: BaseAccordion) {
389-
if (index === -1) {
390-
return;
391-
}
392-
393336
const allHeaders: Array<BaseAccordionHeader> = this.#allHeaders(parentAccordion);
394337

395338
const header = allHeaders[index];

elements/pf-accordion/BaseAccordionHeader.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const isPorHeader =
1515
el instanceof HTMLElement && !!el.tagName.match(/P|^H[1-6]/);
1616

1717
export class AccordionHeaderChangeEvent extends ComposedEvent {
18+
declare target: BaseAccordionHeader;
1819
constructor(
1920
public expanded: boolean,
2021
public toggle: BaseAccordionHeader,

elements/pf-accordion/test/pf-accordion.spec.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import type { ReactiveElement } from 'lit';
2-
31
import { expect, html, aTimeout, nextFrame } from '@open-wc/testing';
42
import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js';
53
import { sendKeys } from '@web/test-runner-commands';
64

75
// Import the element we're testing.
86
import { PfAccordion, PfAccordionPanel, PfAccordionHeader } from '@patternfly/elements/pf-accordion/pf-accordion.js';
7+
import { PfSwitch } from '@patternfly/elements/pf-switch/pf-switch.js';
98

109
import { Logger } from '@patternfly/pfe-core/controllers/logger.js';
1110

@@ -1321,4 +1320,55 @@ describe('<pf-accordion>', function() {
13211320
});
13221321
});
13231322
});
1323+
1324+
describe('with a single expanded header and panel containing a checkbox and a switch', function() {
1325+
let element: PfAccordion;
1326+
let headers: NodeListOf<PfAccordionHeader>;
1327+
let panels: NodeListOf<PfAccordionPanel>;
1328+
let checkbox: HTMLInputElement;
1329+
let pfswitch: PfSwitch;
1330+
let accordionPanelOne: PfAccordionPanel;
1331+
1332+
beforeEach(async function() {
1333+
element = await createFixture<PfAccordion>(html`
1334+
<pf-accordion>
1335+
<pf-accordion-header expanded id="header-1-1" data-index="0"></pf-accordion-header>
1336+
<pf-accordion-panel id="panel-1-1" data-index="0">
1337+
<pf-switch></pf-switch>
1338+
<input type="checkbox">
1339+
</pf-accordion-panel>
1340+
</pf-accordion>
1341+
`);
1342+
headers = document.querySelectorAll('pf-accordion-header');
1343+
panels = document.querySelectorAll('pf-accordion-panel');
1344+
checkbox = element.querySelector('input')!;
1345+
pfswitch = element.querySelector('pf-switch')!;
1346+
expect(checkbox).to.be.ok;
1347+
expect(pfswitch).to.be.ok;
1348+
[accordionPanelOne] = panels;
1349+
});
1350+
1351+
describe('clicking the checkbox', function() {
1352+
beforeEach(async function() {
1353+
checkbox.click();
1354+
await element.updateComplete;
1355+
});
1356+
it('does not collapse the panel', function() {
1357+
expect(accordionPanelOne.expanded).to.be.true;
1358+
});
1359+
});
1360+
1361+
describe('clicking the switch', function() {
1362+
beforeEach(async function() {
1363+
const { checked } = pfswitch;
1364+
pfswitch.click();
1365+
await element.updateComplete;
1366+
await pfswitch.updateComplete;
1367+
expect(pfswitch.checked).to.not.equal(checked);
1368+
});
1369+
it('does not collapse the panel', function() {
1370+
expect(accordionPanelOne.expanded).to.be.true;
1371+
});
1372+
});
1373+
});
13241374
});

0 commit comments

Comments
 (0)