import React from 'react'; import {IDropdownTreeGroup, IPropsDropdownTree} from 'superdesk-api'; interface IState { open: boolean; } function isGroup(x: T | IDropdownTreeGroup): x is IDropdownTreeGroup { return typeof x['items'] !== 'undefined'; } export class DropdownTree extends React.PureComponent, IState> { dropdownNode: HTMLDivElement; constructor(props: IPropsDropdownTree) { super(props); this.state = { open: false, }; this.renderGroupRecursive = this.renderGroupRecursive.bind(this); this.closeDropdown = this.closeDropdown.bind(this); } private closeDropdown() { this.setState({open: false}); } private renderGroupRecursive(item: T | IDropdownTreeGroup, level: number, key: number) { const {renderItem} = this.props; if (isGroup(item)) { return (
{typeof item.render === 'function' ? item.render() : null}
{ item.items.map((_item, i) => ( this.renderGroupRecursive(_item, level + 1, i) )) }
); } else { return renderItem(key.toString(), item, this.closeDropdown); } } render() { const {groups, getToggleElement} = this.props; const onClick = () => this.setState({open: !this.state.open}); return (
{getToggleElement(this.state.open, onClick)} { this.state.open ? (
{ if (node != null) { node.focus(); } this.dropdownNode = node; }} tabIndex={0} onBlur={(event) => { // don't close the dropdown on blur // if focus went to toggle element or an element inside the dropdown if ( this.dropdownNode.contains( event.relatedTarget as Element, ) === false && this.dropdownNode.previousElementSibling.isSameNode( event.relatedTarget as Element, ) === false ) { this.closeDropdown(); } }} style={{ position: 'absolute', zIndex: 1, top: '100%', right: 0, }} >
{ groups.map((group, i) => (
{this.renderGroupRecursive(group, 0, 0)}
)) }
) : null }
); } }