From 227be24e0ed10a64d4fd51b74a8f8822c045f5d2 Mon Sep 17 00:00:00 2001 From: Steven Spriggs Date: Tue, 5 Nov 2024 23:52:44 -0500 Subject: [PATCH] fix(accordion): correct expanded and expanded-index functionality --- elements/rh-accordion/rh-accordion-header.ts | 26 +++++--- elements/rh-accordion/rh-accordion-panel.ts | 10 ++- elements/rh-accordion/rh-accordion.ts | 65 ++++++++++++-------- 3 files changed, 66 insertions(+), 35 deletions(-) diff --git a/elements/rh-accordion/rh-accordion-header.ts b/elements/rh-accordion/rh-accordion-header.ts index 5400ae0398..78e793c994 100644 --- a/elements/rh-accordion/rh-accordion-header.ts +++ b/elements/rh-accordion/rh-accordion-header.ts @@ -9,16 +9,16 @@ import { property } from 'lit/decorators/property.js'; import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; import { observes } from '@patternfly/pfe-core/decorators/observes.js'; +import { HeadingLevelController } from '@rhds/elements/lib/context/headings/controller.js'; import { InternalsController } from '@patternfly/pfe-core/controllers/internals-controller.js'; + import { DirController } from '../../lib/DirController.js'; import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/consumer.js'; import { consume } from '@lit/context'; - import { context } from './context.js'; import styles from './rh-accordion-header.css'; -import { HeadingLevelController } from '@rhds/elements/lib/context/headings/controller.js'; export class AccordionHeaderChangeEvent extends Event { declare target: RhAccordionHeader; @@ -49,6 +49,12 @@ const isAccordion = (x: EventTarget): x is RhAccordion => export class RhAccordionHeader extends LitElement { static readonly styles = [styles]; + // Allow focus to apply to shadow button + static override readonly shadowRootOptions: ShadowRootInit = { + ...LitElement.shadowRootOptions, + delegatesFocus: true, + }; + @property({ type: Boolean, reflect: true }) expanded = false; @consume({ context, subscribe: true }) @@ -67,12 +73,14 @@ export class RhAccordionHeader extends LitElement { #heading = new HeadingLevelController(this); + #belongsTo?: RhAccordion | null; + override connectedCallback() { super.connectedCallback(); this.id ||= getRandomId(this.localName); - const accordion = this.closest('rh-accordion'); + this.#belongsTo = this.closest('rh-accordion'); const heading = this.closest('h1,h2,h3,h4,h5,h6'); - if (heading && accordion?.contains(heading)) { + if (heading && this.#belongsTo?.contains(heading)) { this.#internals.ariaLevel = heading.localName.replace('h', ''); heading.replaceWith(this); } else { @@ -104,16 +112,20 @@ export class RhAccordionHeader extends LitElement { `; } - #onClick(event: MouseEvent) { - const accordion = event.composedPath().find(isAccordion); + #onClick() { + this.expanded = !this.expanded; + } + + #dispatchChange(accordion?: RhAccordion | null) { if (accordion) { - this.dispatchEvent(new AccordionHeaderChangeEvent(!this.expanded, this, accordion)); + this.dispatchEvent(new AccordionHeaderChangeEvent(this.expanded, this, accordion)); } } @observes('expanded') private expandedChanged() { this.#internals.ariaExpanded = String(!!this.expanded) as 'true' | 'false'; + this.#dispatchChange(this.#belongsTo); } } diff --git a/elements/rh-accordion/rh-accordion-panel.ts b/elements/rh-accordion/rh-accordion-panel.ts index 62ed3ba47b..68c459066a 100644 --- a/elements/rh-accordion/rh-accordion-panel.ts +++ b/elements/rh-accordion/rh-accordion-panel.ts @@ -1,6 +1,5 @@ import { html, LitElement } from 'lit'; import { classMap } from 'lit/directives/class-map.js'; - import { customElement } from 'lit/decorators/custom-element.js'; import { property } from 'lit/decorators/property.js'; @@ -8,12 +7,12 @@ import { colorContextConsumer, type ColorTheme } from '../../lib/context/color/c import { colorContextProvider, type ColorPalette } from '../../lib/context/color/provider.js'; import { getRandomId } from '@patternfly/pfe-core/functions/random.js'; - -import styles from './rh-accordion-panel.css'; +import { observes } from '@patternfly/pfe-core/decorators/observes.js'; import { consume } from '@lit/context'; import { context, type RhAccordionContext } from './context.js'; +import styles from './rh-accordion-panel.css'; /** * Accordion Panel * @@ -55,6 +54,11 @@ export class RhAccordionPanel extends LitElement { `; } + + @observes('expanded') + private expandedChanged() { + this.hidden = !this.expanded; + } } declare global { diff --git a/elements/rh-accordion/rh-accordion.ts b/elements/rh-accordion/rh-accordion.ts index cd9533f6ec..ff5cc6b72d 100644 --- a/elements/rh-accordion/rh-accordion.ts +++ b/elements/rh-accordion/rh-accordion.ts @@ -17,6 +17,9 @@ import { RhAccordionPanel } from './rh-accordion-panel.js'; import { context, type RhAccordionContext } from './context.js'; +export * from './rh-accordion-header.js'; +export * from './rh-accordion-panel.js'; + import styles from './rh-accordion.css'; export class AccordionExpandEvent extends ComposedEvent { @@ -111,16 +114,6 @@ export class RhAccordion extends LitElement { set expandedIndex(value) { this.#expandedIndex = value; - this.#expanded = !!this.#expandedIndex.length; - this.headers.forEach((header, i) => { - const expanded = this.#expandedIndexSet.has(i); - header.expanded = expanded; - const panel = this.panels[i]; - if (panel) { - panel.expanded = expanded; - panel.hidden = !expanded; - } - }); } /** All headers for this accordion */ @@ -170,14 +163,14 @@ export class RhAccordion extends LitElement { return c && results.every(Boolean); } - override firstUpdated() { - this.headers.forEach((header, index) => { - if (header.expanded) { - this.#expandedIndexSet.add(index); + @observes('expandedIndex') + private updateExpanded() { + this.#expandedIndex.forEach(headerIndex => { + if (!this.headers[headerIndex]) { + return; } + this.#expand(headerIndex); }); - this.expandedIndex = [...this.#expandedIndexSet]; - this.#expanded = !!this.#expandedIndex.length; } @observes('accents') @@ -205,25 +198,47 @@ export class RhAccordion extends LitElement { #expand(index: number) { // If this index is not already listed in the expandedSets array, add it - this.expandedIndex = [...this.#expandedIndexSet.add(index)]; + if (this.#expandedIndexSet.has(index)) { + return; + } + + this.#expandedIndexSet.add(index); + + const header = this.headers[index]; + const panel = this.panels[index]; + + if (header && panel) { + header.expanded = true; + panel.expanded = true; + } } #collapse(index: number) { - if (this.#expandedIndexSet.delete(index)) { - this.expandedIndex = [...this.#expandedIndexSet]; + if (!this.#expandedIndexSet.has(index)) { + return; + } + + const header = this.headers[index]; + const panel = this.panels[index]; + if (header && panel) { + header.expanded = false; + panel.expanded = false; } + this.#expandedIndexSet.delete(index); } #onChange(event: AccordionHeaderChangeEvent) { if (RhAccordion.isAccordionChangeEvent(event)) { const index = this.#getIndex(event.target); + if (event.expanded) { - this.expand(index, event.accordion); - } else { - this.collapse(index); + this.#expand(index); + } + + if (!event.expanded) { + this.#collapse(index); } } - this.requestUpdate('expandedIndex'); } #allHeaders(accordion: RhAccordion = this): RhAccordionHeader[] { @@ -279,9 +294,9 @@ export class RhAccordion extends LitElement { const header = headers[index]; if (!header.expanded) { - await this.expand(index); + await this.#expand(index); } else { - await this.collapse(index); + await this.#collapse(index); } }