rc-tree@2.0.0

tree ui component for react

/* eslint react/no-multi-comp:0 */
/* eslint no-console:0 */
/* eslint react/no-string-refs:0 */

import 'rc-tree/assets/index.css';
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import Tree, { TreeNode } from 'rc-tree';
import Trigger from 'rc-trigger';
import { gData } from './util';
import './dropdown.less';

const placements = {
  topLeft: {
    points: ['bl', 'tl'],
    overflow: {
      adjustX: 1,
      adjustY: 1,
    },
    offset: [0, -3],
    targetOffset: [0, 0],
  },
  bottomLeft: {
    points: ['tl', 'bl'],
    overflow: {
      adjustX: 1,
      adjustY: 1,
    },
    offset: [0, 3],
    targetOffset: [0, 0],
  },
};
class DropdownTree extends React.Component {
  static propTypes = {
    onVisibleChange: PropTypes.func,
    prefixCls: PropTypes.string,
    children: PropTypes.any,
    transitionName: PropTypes.string,
    overlayClassName: PropTypes.string,
    animation: PropTypes.any,
    align: PropTypes.object,
    overlayStyle: PropTypes.object,
    placement: PropTypes.string,
    trigger: PropTypes.array,
    defaultVisible: PropTypes.bool,
    visible: PropTypes.bool,
  };
  static defaultProps = {
    prefixCls: 'demo-dropdown-tree',
    trigger: ['hover'],
    overlayClassName: '',
    overlayStyle: {},
    defaultVisible: false,
    onVisibleChange() {
    },
    placement: 'bottomLeft',
  };
  constructor(props) {
    super(props);
    if ('visible' in props) {
      this.state = {
        visible: props.visible,
      };
      return;
    }
    this.state = {
      visible: props.defaultVisible,
    };
  }
  componentWillReceiveProps(props) {
    if ('visible' in props) {
      this.setState({
        visible: props.visible,
      });
    }
  }
  onChange = (value) => {
    console.log('change', value);
  }
  onSelect = (value) => {
    console.log('select ', value);
  }
  onClick = (e) => {
    const props = this.props;
    const overlayProps = props.overlay.props;
    if (!('visible' in props)) {
      this.setState({
        visible: false,
      });
    }
    if (overlayProps.onClick) {
      overlayProps.onClick(e);
    }
  }
  onVisibleChange = (v) => {
    const props = this.props;
    if (!('visible' in props)) {
      this.setState({
        visible: v,
      });
    }
    props.onVisibleChange(v);
  }
  getPopupElement = () => {
    const props = this.props;
    return React.cloneElement(props.overlay, {
      // prefixCls: `${props.prefixCls}-menu`,
      onClick: this.onClick,
    });
  }
  render() {
    const { prefixCls, children,
      transitionName, animation,
      align, placement,
      overlayClassName, overlayStyle,
      trigger } = this.props;
    return (
      <Trigger
        prefixCls={prefixCls}
        ref="trigger"
        popupClassName={overlayClassName}
        popupStyle={overlayStyle}
        builtinPlacements={placements}
        action={trigger}
        popupPlacement={placement}
        popupAlign={align}
        popupTransitionName={transitionName}
        popupAnimation={animation}
        popupVisible={this.state.visible}
        popup={this.getPopupElement()}
        onPopupVisibleChange={this.onVisibleChange}
      >{children}</Trigger>
    );
  }
}

class Demo extends React.Component {
  state = {
    visible: false,
    inputValue: '',
    sel: '',
    expandedKeys: [],
    autoExpandParent: true,
  };
  onChange = (event) => {
    this.filterKeys = [];
    this.setState({
      inputValue: event.target.value,
    });
  }
  onVisibleChange = (visible) => {
    this.setState({
      visible,
    });
  }
  onSelect = (selectedKeys, info) => {
    console.log('selected: ', info);
    this.setState({
      visible: false,
      sel: info.node.props.title,
    });
  }
  onExpand = (expandedKeys) => {
    this.filterKeys = undefined;
    console.log('onExpand', arguments);
    // if not set autoExpandParent to false, if children expanded, parent can not collapse.
    // or, you can remove all expanded chilren keys.
    this.setState({
      expandedKeys,
      autoExpandParent: false,
    });
  }
  filterTreeNode = (treeNode) => {
    console.log(treeNode);
    // 根据 key 进行搜索,可以根据其他数据,如 value
    return this.filterFn(treeNode.props.eventKey);
  }
  filterFn = (key) => {
    if (this.state.inputValue && key.indexOf(this.state.inputValue) > -1) {
      return true;
    }
    return false;
  }
  render() {
    const loop = data => {
      return data.map((item) => {
        if (this.filterKeys && this.filterFn(item.key)) {
          this.filterKeys.push(item.key);
        }
        if (item.children) {
          return <TreeNode key={item.key} title={item.key}>{loop(item.children)}</TreeNode>;
        }
        return <TreeNode key={item.key} title={item.key} />;
      });
    };
    let expandedKeys = this.state.expandedKeys;
    let autoExpandParent = this.state.autoExpandParent;
    if (this.filterKeys) {
      expandedKeys = this.filterKeys;
      autoExpandParent = true;
    }

    const overlay = (<div>
      <input placeholder="请筛选" value={this.state.inputValue} onChange={this.onChange} />
      <Tree
        onExpand={this.onExpand} expandedKeys={expandedKeys}
        autoExpandParent={autoExpandParent}
        onSelect={this.onSelect} filterTreeNode={this.filterTreeNode}
      >
        {loop(gData)}
      </Tree>
    </div>);

    return (<div style={{ padding: '10px 30px' }}>
      <h3>tree in dropdown</h3>
      <DropdownTree
        trigger={['click']}
        onVisibleChange={this.onVisibleChange}
        visible={this.state.visible}
        closeOnSelect={false}
        overlay={overlay} animation="slide-up"
      >
        <div className="demo-dropdown-trigger">{this.state.sel}</div>
      </DropdownTree>
    </div>);
  }
}

ReactDOM.render(<Demo />, document.getElementById('__react-content'));
Fork me on GitHub