import * as React from "react"; import * as _ from "lodash"; import * as DefaultStyles from "./style"; import { CheckItem } from "../../types/global"; import HierarchyList, { HierarchyList as HL } from "../HierarchyList"; import ListBar from "./ListBar"; import Search from "./Search"; export type ListComponent = React.ComponentType; export type ListFunc = (props: HL.Props) => JSX.Element; export type List = ListComponent | ListFunc; export const PickerContext = React.createContext({}); export namespace ListPicker { export interface Props { items: CheckItem[]; checkedItems?: CheckItem[]; styles?: ListPicker.Styles; listComponent?: List; listChange: (list: CheckItem[]) => void; id?: string; name?: string; } export interface State { checkedItems: CheckItem[]; flatItems: CheckItem[]; displayItems: CheckItem[]; searchTerm: string; } export interface Styles { Container?: any; Median?: any; ListWrapper?: any; SearchInput?: any; SearchContainer?: any; ResetIcon?: any; } } class ListPicker extends React.Component { private Styles: ListPicker.Styles; private List: List; constructor(props: ListPicker.Props) { super(props); this.state = { checkedItems: props.checkedItems ? props.checkedItems : [], flatItems: this.flattenItems(props.items), displayItems: _.cloneDeep(props.items), searchTerm: "", }; this.List = this.props.listComponent ? this.props.listComponent : HierarchyList; } toggleItem = (item: CheckItem): void => { const cloned = _.cloneDeep(item); cloned.children = []; let checkedItems: CheckItem[] = []; this.isSelected(cloned) ? (checkedItems = this.state.checkedItems.filter( i => i.id !== cloned.id )) : (checkedItems = _.concat(this.state.checkedItems, [cloned])); this.setState({ checkedItems }); this.props.listChange(checkedItems); }; flattenItems = (list: CheckItem[]): CheckItem[] => _.flattenDeep( list.reduce((accum: any, item: CheckItem) => { accum.push([item, this.flattenItems(item.children)]); return accum; }, []) ); reset = () => { this.setState({ searchTerm: "", displayItems: _.cloneDeep(this.props.items), checkedItems: [], }); this.props.listChange([]); }; handleSearch = value => { let displayItems = this.state.flatItems.filter(item => item.name.toLowerCase().includes(value.toLowerCase()) ); value === "" ? (displayItems = _.cloneDeep(this.props.items)) : null; this.setState({ searchTerm: value, displayItems }); }; isSelected = (item: CheckItem): boolean => Boolean(this.state.checkedItems.find(i => i.id === item.id)); configureLayout = () => { const childArr = React.Children.toArray(this.props.children); const searchChild = childArr.find((c: any) => c.type === Search); const listBarChild = childArr.find((c: any) => c.type === ListBar); if (searchChild && listBarChild) { return React.Children.map(this.props.children, (child: any) => { if (child.type === ListBar) { return React.cloneElement(child, { toggleItem: this.toggleItem, displayItems: this.state.displayItems, checkedItems: this.state.checkedItems, }); } if (child.type === Search) { return React.cloneElement(child, { value: this.state.searchTerm, onChange: this.handleSearch, onReset: this.reset, }); } return child; }); } else if (!searchChild && listBarChild) { return ( <> {React.Children.map(this.props.children, (child: any) => { if (child.type === ListBar) { return React.cloneElement(child, { toggleItem: this.toggleItem, displayItems: this.state.displayItems, checkedItems: this.state.checkedItems, }); } return null; })} ); } else { const { Styles, List } = this; return ( <> ); } }; render() { const Styles: ListPicker.Styles = _.merge({}, this.props.styles); return {this.configureLayout()} ; } } export default ListPicker;