1+ import * as React from 'react' ;
2+ import styles from "./FilterBar.module.scss" ;
3+ import { PillGroup } from './PillGroup' ;
4+ import { Pill } from './Pill' ;
5+ import { OverflowPill } from './OverflowPill' ;
6+ import { IFilterBarItem } from './IFilterBarItem' ;
7+ import { IFilterBarItemGroup } from './IFilterBarItemGroup' ;
8+ import * as strings from "ControlStrings" ;
9+ import { findLastIndex , uniq } from "lodash" ;
10+ import { ThemeProvider } from '@fluentui/react/lib/Theme' ;
11+ import { getTheme } from '@fluentui/react/lib/Styling' ;
12+
13+ export interface IFilterPillBarProps {
14+ /**
15+ Filters to be displayed. Multiple filters with the same label are grouped together
16+ */
17+ items : IFilterBarItem [ ] ;
18+ /**
19+ Number of filters, after which filters start showing as overflow
20+ */
21+ inlineItemCount ?: number ;
22+ /**
23+ Callback function called after clicking 'Clear filters' pill.
24+ */
25+ onClearFilters ?: ( ) => void ;
26+ /**
27+ Callback function called after clicking a singular filter pill
28+ */
29+ onRemoveFilter ?: ( label : string , value : string ) => void ;
30+ }
31+
32+ export const FilterBar : React . FunctionComponent < IFilterPillBarProps > = ( props : IFilterPillBarProps ) => {
33+
34+ const orderedArray = ( arr : IFilterBarItem [ ] ) => {
35+ const ret : IFilterBarItem [ ] = [ ] ;
36+ arr . map ( i => {
37+ const index = findLastIndex ( ret , r => r . label === i . label ) ;
38+ if ( index > - 1 )
39+ {
40+ ret . splice ( index + 1 , 0 , i ) ;
41+ }
42+ else {
43+ ret . push ( i ) ;
44+ }
45+ } ) ;
46+ return ret ;
47+ }
48+
49+ const groupItems = ( itms : IFilterBarItem [ ] ) : IFilterBarItemGroup [ ] => itms . reduce ( ( acc : IFilterBarItemGroup [ ] , itm : IFilterBarItem ) => {
50+ const label = itm . label ;
51+ let obj = acc . find ( i => i . label === label ) ;
52+ if ( ! obj ) {
53+ obj = {
54+ label : label ,
55+ values : [ itm . value ]
56+ } ;
57+ acc . push ( obj ) ;
58+ }
59+ else {
60+ if ( ! obj . values . find ( v => v === itm . value ) ) {
61+ obj . values . push ( itm . value ) ;
62+ }
63+ }
64+
65+ return acc ;
66+ } , [ ] ) ;
67+
68+ const clearAll = ( ) => {
69+
70+ if ( props . onClearFilters ) {
71+ props . onClearFilters ( ) ;
72+ }
73+ }
74+
75+ const pillClick = ( label ?: string , value ?: string ) => {
76+ console . log ( label , value ) ;
77+ if ( props . onRemoveFilter ) {
78+ props . onRemoveFilter ( label as string , value as string ) ;
79+ }
80+
81+ }
82+ //const [items, setItems] = React.useState());
83+ const defaultInlineItemCount = 5 ;
84+ const [ inlineCount , setInlineCount ] = React . useState ( defaultInlineItemCount ) ;
85+
86+ const groupedItems : IFilterBarItemGroup [ ] = React . useMemo ( ( ) => groupItems ( orderedArray ( uniq ( props . items ) ) ) , [ props . items ] ) ;
87+
88+ React . useEffect ( ( ) => {
89+ setInlineCount ( props . inlineItemCount ?? defaultInlineItemCount ) ;
90+ } , [ props . inlineItemCount ] )
91+
92+ return (
93+ < >
94+ < ThemeProvider theme = { getTheme ( ) } >
95+ {
96+ groupedItems && groupedItems . length > 0 && (
97+ < div className = { styles . container } aria-label = { strings . AppliedFiltersAriaLabel } role = 'region' >
98+ {
99+ groupedItems . slice ( 0 , inlineCount ) . map ( ( i , index ) => < PillGroup item = { i } key = { index } onRemoveFilter = { pillClick } /> )
100+ }
101+ {
102+ groupedItems . length > inlineCount && (
103+ < OverflowPill items = { groupedItems . slice ( inlineCount ) } onClick = { pillClick } />
104+ )
105+ }
106+ < Pill clearAll = { true } onClick = { clearAll } />
107+ </ div >
108+ )
109+ }
110+ </ ThemeProvider >
111+ </ >
112+ ) ;
113+ } ;
0 commit comments