@cfpb/cfpb-design-system
Version:
CFPB's UI framework
128 lines (113 loc) • 3.7 kB
JavaScript
import { LitElement, html, css, unsafeCSS } from 'lit';
import { defineComponent } from '../cfpb-utilities/shared-config';
import styles from './styles.component.scss?inline';
import { CfpbIcon } from '../cfpb-icon';
import { MaxHeightTransition } from '../../utilities/transition/max-height-transition';
import { FlyoutMenu } from '../../utilities/behavior/flyout-menu';
/**
*
* @element cfpb-expandable
* @slot header - The header content for the expandable.
* @slot content - The content within the expandable.
*/
export class CfpbExpandable extends LitElement {
static styles = css`
${unsafeCSS(styles)}
`;
#flyoutMenu;
#transition;
/**
* @property {boolean} isExpanded - Whether the expandable is expanded or not.
* @returns {object} The map of properties.
*/
static get properties() {
return {
isExpanded: { type: Boolean, attribute: 'open', reflect: true },
};
}
constructor() {
super();
}
firstUpdated() {
const root = this.shadowRoot.querySelector('div');
const contentDom = root.querySelector('.o-expandable__content');
// If it's expanded we don't set an initial height,
// as it will be calculated internally.
const initialClass = this.isExpanded
? MaxHeightTransition.CLASSES.MH_DEFAULT
: MaxHeightTransition.CLASSES.MH_ZERO;
this.#transition = new MaxHeightTransition(contentDom).init(initialClass);
this.#flyoutMenu = new FlyoutMenu(root);
this.#flyoutMenu.setTransition(
this.#transition,
this.#transition.maxHeightZero,
this.#transition.maxHeightDefault,
);
this.#flyoutMenu.init(this.isExpanded);
// Add events.
this.#flyoutMenu.addEventListener('expandbegin', () => {
this.isExpanded = true;
contentDom.classList.remove('u-hidden');
this.dispatchEvent(
new CustomEvent('expandbegin', {
detail: { target: this },
bubbles: true,
composed: true,
}),
);
});
this.#flyoutMenu.addEventListener('collapseend', () => {
this.isExpanded = false;
contentDom.classList.add('u-hidden');
});
}
updated(changedProps) {
if (changedProps.has('isExpanded')) {
const oldVal = changedProps.get('isExpanded');
const newVal = this.isExpanded;
if (newVal !== oldVal) {
if (newVal) {
this.#flyoutMenu.expand();
} else {
this.#flyoutMenu.collapse();
}
}
}
}
render() {
return html`
<div
class="o-expandable o-expandable--background o-expandable--border"
data-js-hook="behavior_flyout-menu"
>
<button
class="o-expandable__header"
title="Expand content"
data-js-hook="behavior_flyout-menu_trigger"
>
<slot name="header" class="o-expandable__label"></slot>
<span class="o-expandable__cues">
<span class="o-expandable__cue-open" role="img" aria-label="Show">
<cfpb-icon name="plus-round" color="pacific"></cfpb-icon>
<span class="u-visually-hidden">Show</span>
</span>
<span class="o-expandable__cue-close" role="img" aria-label="Hide">
<cfpb-icon name="minus-round" color="pacific"></cfpb-icon>
<span class="u-visually-hidden">Hide</span>
</span>
</span>
</button>
<div
class="o-expandable__content"
data-js-hook="behavior_flyout-menu_content"
>
<slot name="content"></slot>
</div>
</div>
`;
}
static init() {
CfpbIcon.init();
defineComponent('cfpb-expandable', CfpbExpandable);
}
}