/** * @license * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ import {LitElement, html, css, unsafeCSS} from 'lit'; import {customElement, property, query} from 'lit/decorators.js'; import { breakpoints } from '../../breakpoints'; @customElement('iu-accordion') export class Accordion extends LitElement { static override styles = css` :host{ --iu-comp-bg: transparent; --iu-comp-color: var(--iu-color-black); --iu-comp-bg-hover: var(--iu-color-black); --iu-comp-color-hover: var(--iu-color-white); --iu-comp-border-color: var(--iu-color-grey-200); --iu-comp-border-color-hover: var(--iu-color-grey-500); } :host:has(.accordion.is-open){ border-bottom: 1px solid var(--iu-comp-border-color-hover); } .accordion{ border-top: 1px solid var(--iu-comp-border-color); cursor: pointer; color: var(--iu-comp-color); background: var(--iu-comp-bg); } .accordion.is-open, .accordion.is-open button, :host(:hover), :host(:hover) button{ color: var(--iu-comp-color-hover); background: var(--iu-comp-bg-hover); } .accordion.is-open svg{ transform: rotate(45deg); } button{ color: var(--iu-comp-color); background: var(--iu-comp-bg); cursor: pointer; border: 0; position: relative; font: var(--iu-f-2); text-align: left; width: 100%; padding: 4px 0; display: flex; align-items: center; text-rendering: geometricPrecision; } .size-2 button{ padding: 0; font: var(--iu-f-lg); } svg{ transition: transform .2s ease; } .size-1 svg{ width: 36px; height: 36px; margin-right: .625rem; margin-top: -2px; } .size-2 svg{ width: 50px; height: 50px; margin-right: .9375rem; margin-top: -2px; } @media ${unsafeCSS(breakpoints.xl)} { button{ } } .content{ display: none; color: var(--iu-comp-color); padding-top: var(--iu-spacing-2); padding-bottom: var(--iu-spacing-6); padding-left: calc(3.125rem + .9375rem); padding-right: var(--iu-grid-gutter); } .content.is-open{ display: block; } .content.columns-2{ columns: 2; gap: var(--iu-grid-gutter); } ::slotted(*){ --iu-comp-color: var(--iu-color-white); --iu-comp-border-color: var(--iu-color-grey-500); --iu-comp-bg-hover: var(--iu-color-white); --iu-comp-color-hover: var(--iu-color-black); margin-bottom: 0; color: var(--iu-color-white) !important; } `; @property() text : string = ''; @property() index : number = 0; @property({ type: Boolean, reflect: true}) columns : boolean = false; @property({ type: Boolean, reflect: true}) isOpen : boolean = false; @property() controlled : boolean = false; @property({type: Number}) size = 1; @query('slot') slotElement!: HTMLSlotElement; toggleAccordion(){ //grouped with other accordion if (this.controlled) { this.dispatchEvent(new CustomEvent('iu-toggle-accordion', { detail: {index: this.index }, bubbles: true, composed: true })) } else { //stand alone component this.isOpen = !this.isOpen; } this.classList.toggle('is-open'); } // make sure that every component inside this has <iu-container> set // to nested to disable padding left on the container itself private updateSlottedElements() { // Get all slotted elements const slottedElements = this.slotElement.assignedElements({ flatten: true }); slottedElements.forEach((slot) => { if (slot instanceof HTMLElement) { // Set the `nested` attribute or property slot.setAttribute('nested', 'true'); } }); } override firstUpdated() { super.firstUpdated(); this.updateSlottedElements(); } override render() { return html` <div class="accordion size-${this.size} ${this.isOpen ? 'is-open' : ''}"> <button aria-expanded="false" @click=${this.toggleAccordion}> <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50"><path fill-rule="evenodd" clip-rule="evenodd" d="M37.5 26h-25v-2h25v2Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 37.5v-25h2v25h-2Z" fill="currentColor"/></svg> ${this.text} </button> <div class="content ${this.isOpen ? 'is-open' : ''} ${this.columns ? 'columns-2' : ''}"> <slot></slot> </div> </div> `; } } declare global { interface HTMLElementTagNameMap { 'iu-accordion': Accordion; } }