import { html, css, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { action } from '@storybook/addon-actions'; import './index'; import '../checkbox'; import '../modal'; import '../textInput'; import '../overflowMenu'; import '../tag'; import '@kyndryl-design-system/shidoka-foundation/components/button'; import '@kyndryl-design-system/shidoka-foundation/components/icon'; import '@kyndryl-design-system/shidoka-foundation/components/accordion'; import '@kyndryl-design-system/shidoka-charts/components/chart'; import searchIcon from '@carbon/icons/es/search/24'; import filterIcon from '@carbon/icons/es/filter/20'; import filterEditIcon from '@carbon/icons/es/filter--edit/20'; import refreshIcon from '@carbon/icons/es/renew/20'; import filterRemoveIcon from '@carbon/icons/es/close--filled/16'; export default { title: 'Patterns/Global Filter', component: 'kyn-global-filter', parameters: { design: { type: 'figma', url: 'https://www.figma.com/file/6AovH7Iay9Y7BkpoL5975s/Applications-Specs-for-Devs?node-id=3101%3A467&mode=dev', }, }, }; export const GlobalFilter = { render: () => { return html`
This example shows a standalone Global Filter pattern. It will update the selected Tags automatically when changing checkbox selections. For client-side filtering, you may want to perform the filtering immediately on checkbox change. For server-side filtering, you may want to perform filtering on the modal close event instead. There are example event handler functions for each of the controls contained within. `; }, }; /** Sample Lit component to show global filter pattern. */ @customElement('sample-filter-component') export class SampleFilterComponent extends LitElement { static override styles = css` .filter-text { display: none; } @media (min-width: 42rem) { .filter-text { display: inline; } } `; /** Array of sample checkbox filter options. */ @property({ type: Array }) checkboxOptions: Array = [ { value: '1', text: 'Option 1', }, { value: '2', text: 'Option 2', }, { value: '3', text: 'Option 3', }, { value: '4', text: 'Option 4', }, { value: '5', text: 'Option 5', }, { value: '6', text: 'Option 6', }, ]; override render() { const SelectedOptions = this.checkboxOptions.filter( (option) => option.checked ); return html` this._handleSearch(e)} > Search this._handleModalClose(e)} > Filter Filter 1: ${SelectedOptions.length ? SelectedOptions.length + ' items' : 'Any'}
{ return option.value; })} @on-checkbox-group-change=${(e: any) => this._handleCheckboxes(e)} > Filter 1 ${this.checkboxOptions.map( (option: any) => html` ${option.text} ` )}
Filter 2: Any
Some other filter control here.
this._handleCustomAction(e)} > Custom Action this._handleOverflowClick(e)} > Option 1 this._handleOverflowClick(e)} > Option 2 ${SelectedOptions.map( (filter) => html` this._handleTagClick(e, filter)} > ` )} ${SelectedOptions.length ? html` this._handleClearTags(e)} > Clear All ` : null}
`; } private _handleSearch(e: any) { action(e.type)(e); // console.log(e.detail); // perform filtering here } private _handleCheckboxes(e: any) { action(e.type)(e); // console.log(e.detail); const Value = e.detail.value; // update checked state for each option this.checkboxOptions = this.checkboxOptions.map((option) => { return { ...option, checked: Value.includes(option.value) }; }); // perform filtering here (client-side scenario) } private _handleModalClose(e: any) { action(e.type)(e); // console.log(e.detail); // handle modal close here if (e.detail.returnValue === 'ok') { // modal was closed with OK/primary action, logic to perform filtering here (server-side scenario) } else { // modal was closed with cancel/secondary action/x, logic to revert filters here } } private _handleTagClick(e: any, option: any) { action(e.type)(e); // console.log(e.detail); // remove tag by setting checkbox option checked value to false option.checked = false; // perform filtering here // force update/render, since objects are updated by reference this.requestUpdate(); } private _handleClearTags(e: any) { action(e.type)(e); // console.log(e.detail); // update checked state for each option this.checkboxOptions = this.checkboxOptions.map((option) => { return { ...option, checked: false }; }); // perform filtering here } private _handleCustomAction(e: any) { action(e.type)(e); // console.log(e.detail); // custom action logic here } private _handleOverflowClick(e: any) { action(e.type)(e); // console.log(e.detail); // overflow link click logic here } } declare global { interface HTMLElementTagNameMap { 'sample-filter-component': SampleFilterComponent; } } export const WithChart = { render: () => { return html`
This example shows a Global Filter pattern applied to a Chart. `; }, }; /** Sample Lit component to show global filter pattern applied to a Chart. */ @customElement('sample-filter-chart-component') export class SampleFilterChartComponent extends LitElement { static override styles = css` .filter-text { display: none; } @media (min-width: 42rem) { .filter-text { display: inline; } } `; /** Array of sample checkbox filter options. */ @property({ type: Array }) checkboxOptions: Array = [ { value: 'Red', text: 'Red', }, { value: 'Blue', text: 'Blue', }, { value: 'Yellow', text: 'Yellow', }, { value: 'Green', text: 'Green', }, { value: 'Purple', text: 'Purple', }, { value: 'Orange', text: 'Orange', }, ]; @property({ type: Array }) chartLabels: Array = [ 'Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange', ]; @property({ type: Array }) filteredChartLabels: Array = []; @property({ type: Array }) chartDatasets: Array = [ { label: 'Dataset 1', data: [12, 19, 3, 5, 2, 3], }, { label: 'Dataset 2', data: [8, 15, 7, 9, 6, 13], }, ]; @property({ type: Object }) chartOptions = { scales: { x: { title: { text: 'Color', }, }, y: { title: { text: 'Votes', }, }, }, }; override render() { const SelectedOptions = this.checkboxOptions.filter( (option) => option.checked ); return html` this._handleSearch(e)} > Search this._handleModalClose(e)} > Filter Colors: ${SelectedOptions.length ? SelectedOptions.length + ' items' : 'Any'}
{ return option.value; })} @on-checkbox-group-change=${(e: any) => this._handleCheckboxes(e)} > Filter 1 ${this.checkboxOptions.map( (option: any) => html` ${option.text} ` )}
Filter 2: Any
Some other filter control here.
${SelectedOptions.map( (filter) => html` this._handleTagClick(e, filter)} > ` )} ${SelectedOptions.length ? html` this._handleClearTags(e)} > Clear All ` : null}

`; } private _handleSearch(e: any) { action(e.type)(e); // console.log(e.detail); // perform filtering here this._filter(e.detail.value); } private _handleCheckboxes(e: any) { action(e.type)(e); // console.log(e.detail); const Value = e.detail.value; // update checked state for each option this.checkboxOptions = this.checkboxOptions.map((option) => { return { ...option, checked: Value.includes(option.value) }; }); // perform filtering here (client-side scenario) this._filter(''); } private _handleModalClose(e: any) { action(e.type)(e); // console.log(e.detail); // handle modal close here if (e.detail.returnValue === 'ok') { // modal was closed with OK/primary action, logic to perform filtering here (server-side scenario) } else { // modal was closed with cancel/secondary action/x, logic to revert filters here } } private _handleTagClick(e: any, option: any) { action(e.type)(e); // console.log(e.detail); // remove tag by setting checkbox option checked value to false option.checked = false; // perform filtering here this._filter(''); // force update/render, since objects are updated by reference this.requestUpdate(); } private _handleClearTags(e: any) { action(e.type)(e); // console.log(e.detail); // update checked state for each option this.checkboxOptions = this.checkboxOptions.map((option) => { return { ...option, checked: false }; }); // perform filtering here this._filter(''); } private _filter(query: string) { //get selected filters const SelectedOptions = this.checkboxOptions.filter( (option) => option.checked ); if (SelectedOptions.length) { // filter the labels based on selected checkboxes this.filteredChartLabels = this.chartLabels.filter((label) => { return this.checkboxOptions.some( (option) => option.value === label && option.checked ); }); } else { // show all labels if no filters applied this.filteredChartLabels = this.chartLabels; } // perform search query filtering if (query !== '') { this.filteredChartLabels = this.filteredChartLabels.filter((label) => { return label.toLowerCase().includes(query.toLowerCase()); }); } } override firstUpdated() { // perform initial filtering on first update/render this._filter(''); } } declare global { interface HTMLElementTagNameMap { 'sample-filter-chart-component': SampleFilterChartComponent; } } export const WithTable = { render: () => { return html` To Do `; }, };