nope/resources/ui/layout/selection.tsx

199 lines
7.6 KiB
TypeScript
Raw Normal View History

2020-09-02 15:00:03 +00:00
import React from 'react';
import { FormControl, InputGroup, ListGroup } from 'react-bootstrap';
import { deepClone } from '../../../lib/helpers/objectMethods';
export interface SelecitonProps<T> {
2020-09-07 05:21:53 +00:00
selection: Array<{
2020-09-02 15:00:03 +00:00
groupName: string,
items: SelectionItem<T>[]
2020-09-07 05:21:53 +00:00
} | SelectionItem<T>>,
onItemSelected?: (item: T) => void;
allowUserSelect?: boolean;
2020-09-02 15:00:03 +00:00
}
export interface SelectionItem<T> {
label: string,
keywords: string,
item: T,
id: string | number,
2020-09-07 05:21:53 +00:00
color?: 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'light'
2020-09-02 15:00:03 +00:00
}
export interface LayoutState<T> {
selected: string | number;
search: string;
}
class Selection<T> extends React.Component<SelecitonProps<T>, LayoutState<T>> {
constructor(props) {
super(props);
this.state = {
search: '',
selected: null
}
}
/**
* Function to Filter the Selection.
* @param search The Search Term.
*/
protected _filter(search: string) {
this.setState({
search: search.toLocaleLowerCase(),
selected: this.state.selected
});
}
/**
* Function used to Select an item
* @param item which will be selected
*/
protected _select(item: SelectionItem<T>) {
this.setState({
search: this.state.search,
2020-09-07 05:21:53 +00:00
selected: this.props.allowUserSelect ? item.id : -1
2020-09-02 15:00:03 +00:00
});
2020-09-07 05:21:53 +00:00
if (this.props.allowUserSelect && typeof this.props.onItemSelected === "function") {
this.props.onItemSelected(item.item);
2020-09-02 15:00:03 +00:00
}
}
public render() {
const _this = this;
// Filter only Valid items.
// Therefore iterate over the Groups and
// Filter the Items with the Search String
// and there Labels / Keywords.
// Afterwards filter the groups and remove
// Empty Groups
const items = deepClone(this.props).selection.map(item => {
2020-09-07 05:21:53 +00:00
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
// Filter the Items, that match the Selection
(item as {
groupName: string,
items: SelectionItem<T>[]
}).items = (item as {
groupName: string,
items: SelectionItem<T>[]
}).items.filter(value =>
// Filter the Keywords
value.keywords.toLowerCase().includes(_this.state.search) ||
// Filter the Lable.
value.label.toLowerCase().includes(_this.state.search)
);
}
2020-09-02 15:00:03 +00:00
// Return the Item
return item;
}).filter(
2020-09-07 05:21:53 +00:00
item => {
2020-09-02 15:00:03 +00:00
// Filter the Element by the lenght of the contained elements.
2020-09-07 05:21:53 +00:00
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
// Filter the Keywords
return (item as {
groupName: string,
items: SelectionItem<T>[]
}).items.length > 0;
} else {
// Filter the Keywords
return (item as SelectionItem<T>).keywords.toLowerCase().includes(_this.state.search) ||
// Filter the Lable.
(item as SelectionItem<T>).label.toLowerCase().includes(_this.state.search)
}
}
2020-09-02 15:00:03 +00:00
);
let idx = 0;
return (<>
{/* A Search Field. */}
2020-09-07 05:21:53 +00:00
{this.props.allowUserSelect ?
<InputGroup size="sm" className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="inputGroup-sizing-sm" >Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl aria-label="Small" aria-describedby="inputGroup-sizing-sm" onChange={(event) => {
_this._filter(event.currentTarget.value);
}} />
</InputGroup> : ''
}
2020-09-02 15:00:03 +00:00
{
items.length > 0 ?
items.map(item => {
idx++;
2020-09-07 05:21:53 +00:00
if ((item as {
groupName: string,
items: SelectionItem<T>[]
}).items !== undefined) {
return (
<div key={idx}>
<hr />
<h4>{(item as {
groupName: string,
items: SelectionItem<T>[]
}).groupName}</h4>
<hr />
<ListGroup>
{(item as {
groupName: string,
items: SelectionItem<T>[]
}).items.map(template => {
// Raise the ID
idx++;
// Store the Item Index
const idxOfItem = idx;
// Based on the selected Item assign the Color
// dark = selected
// light = unselected
const variant = _this.props.allowUserSelect ?
(template.id === _this.state.selected ? "dark" : "light") :
template.color || 'light';
// Return the Template variant={variant}
return (
<ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
_this._select(template)
}}>{template.label}</ListGroup.Item>
);
})}
</ListGroup>
</div>
);
} else {
// Store the Item Index
const idxOfItem = idx;
// Based on the selected Item assign the Color
// dark = selected
// light = unselected
const variant = _this.props.allowUserSelect ?
((item as SelectionItem<T>).id === _this.state.selected ? "dark" : "light") :
(item as SelectionItem<T>).color || 'light';
// Return the Template variant={variant}
return (
<ListGroup.Item key={idxOfItem} action variant={variant} onClick={e => {
_this._select(item as SelectionItem<T>)
}}>{(item as SelectionItem<T>).label}</ListGroup.Item>
)
}
2020-09-02 15:00:03 +00:00
}) :
<code>Nothing Found</code>
}
</>);
}
}
export default Selection;