diff --git a/packages/web-components/src/components/filter-panel/filter-group-item.ts b/packages/web-components/src/components/filter-panel/filter-group-item.ts index 8c8901a7010..b70575ce354 100644 --- a/packages/web-components/src/components/filter-panel/filter-group-item.ts +++ b/packages/web-components/src/components/filter-panel/filter-group-item.ts @@ -7,13 +7,17 @@ * LICENSE file in the root directory of this source tree. */ -import { customElement } from 'lit-element'; +import { customElement, property, TemplateResult, html, query, state } from 'lit-element'; +import settings from 'carbon-components/es/globals/js/settings'; import ddsSettings from '@carbon/ibmdotcom-utilities/es/utilities/settings/settings.js'; import BXAccordionItem from 'carbon-web-components/es/components/accordion/accordion-item'; import styles from './filter-panel.scss'; import StableSelectorMixin from '../../globals/mixins/stable-selector'; const { stablePrefix: ddsPrefix } = ddsSettings; +const { prefix } = settings; + +const viewAllClassName = `${ddsPrefix}-filter-group-item__view-all`; /** * DDSFilterGroupItem renders each individual accordion @@ -30,6 +34,96 @@ class DDSFilterGroupItem extends StableSelectorMixin(BXAccordionItem) { } static styles = styles; // `styles` here is a `CSSResult` generated by custom WebPack loader + + static get viewAllSelector(): string { + return `button.${viewAllClassName}`; + }; + + /** + * The element containing the default slot. + */ + @query(`.${prefix}--accordion__content`) + accordionContent: any + + /** + * The text for the button that reveals all filters in the group. + */ + @property({ type: String, attribute: 'view-all-text' }) + viewAllText: string = 'View all'; + + /** + * The number of filters that can be shown without needing to hide any. + */ + @property({ type: Number, attribute: 'max-filters' }) + maxFilters: number = 7; + + /** + * The number of filters to show when not all filters are visible. + */ + @property({ type: Number, attribute: 'filter-cutoff' }) + filterCutoff: number = 5; + + /** + * Whether or not any hidden filters have been revealed. + */ + @property({ type: Boolean, reflect: true }) + expanded = true; + + protected _setChildrenExpanded(expanded: boolean = false) { + const { children, filterCutoff, accordionContent } = this; + [...children].slice(filterCutoff, children.length).forEach(elem => { + (elem as HTMLElement).style.display = expanded ? '' : 'none'; + }) + + if (!expanded) { + accordionContent.appendChild(this._renderViewAll()); + } + } + + protected _renderViewAll(): HTMLButtonElement { + const viewAll = document.createElement('button'); + viewAll.classList.add(viewAllClassName, `${prefix}--input-container__heading`); + viewAll.type = 'button'; + viewAll.innerText = this.viewAllText; + + viewAll.addEventListener('click', (e): void => { + const { children, filterCutoff } = this; + const { target } = e; + const firstHidden = children[filterCutoff]; + + if (firstHidden instanceof HTMLElement) firstHidden.focus(); + if (target instanceof HTMLElement) target.remove(); + this.expanded = true; + }, { passive: true, once: true }); + + return viewAll; + } + + protected updated(_changedProperties: Map): void { + const { children, maxFilters } = this; + + const hasOpen = _changedProperties.has('open'); + const prevOpen = _changedProperties.get('open'); + const hasExpanded = _changedProperties.has('expanded'); + const prevExpanded = _changedProperties.get('expanded'); + + if (children.length > maxFilters) { + // Reset expanded on toggle. + if (hasOpen && prevOpen !== undefined) { + this.expanded = false; + } + + // Respect `expanded` attribute + if (hasExpanded) { + if (prevExpanded) { + this._setChildrenExpanded(false); + } + else { + this._setChildrenExpanded(true); + } + } + } + } } /* @__GENERATE_REACT_CUSTOM_ELEMENT_TYPE__ */