UNPKG

frc-ui

Version:

React Web UI

299 lines (298 loc) 13.2 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import React from 'react'; import classNames from 'classnames'; import Item from './Item'; import { Insert_Type, Render_Type, Scroll_Type } from './types'; class Tree extends React.PureComponent { constructor(props) { super(props); this.showColorKeys = []; this.type = Scroll_Type.ALL; this.showCount = 0; this.resize = () => { const { rowHeight, fixedTopBottom } = this.props; const { tops, options, bottoms } = this.state; if (this.wrap && fixedTopBottom) { const height = this.wrap.clientHeight; const width = this.wrap.clientWidth; if (width !== this.state.width || height !== this.state.height) { this.setState({ width, height }); } const length = (options || []).length + (tops || []).length + (bottoms || []).length; let type; if (length * rowHeight < height) { type = Scroll_Type.ALL; } else { type = Scroll_Type.CONTAINER; } if (type !== this.type || this.showCount !== (options || []).length) { this.showCount = (options || []).length; this.type = type; const opts = this.update(this.getOptions()); this.setState(opts); } } }; this.getProps = (prop) => { return this.props[prop]; }; this.saveRef = (name) => (ele) => { this[name] = ele; }; this.update = (options = []) => { const { rowHeight } = this.props; const { height } = this.state; if (height && options.length * rowHeight > height) { this.type = Scroll_Type.CONTAINER; } else { this.type = Scroll_Type.ALL; } if (this.type !== Scroll_Type.CONTAINER) { return { tops: [], bottoms: [], options }; } const tops = [], opts = [], bottoms = []; let start = Insert_Type.TOP; for (let i = 0; i < options.length; i++) { const o = options[i]; if (o.index === 0) { if (start === Insert_Type.TOP) { tops.push(o); } else { start = Insert_Type.BOTTOM; bottoms.push(o); } } else { start = Insert_Type.MIDDLE; opts.push(o); } } return { tops, options: opts, bottoms }; }; this.onChange = (option) => { return (type, flag) => { const { rowHeight, onChange, onExpand } = this.props; const { height } = this.state; const selectedKeys = this.state.selectedKeys || []; const expandedKeys = this.state.expandedKeys || []; const { value } = option; let keys; switch (type) { case 'check': keys = selectedKeys; if (flag) { if (keys.indexOf(value) < 0) { keys = [...selectedKeys, value]; } } else { keys = selectedKeys.filter((v) => v !== value); } this.showColorKeys = this.getSelectedPath(keys); this.setState({ selectedKeys: keys }, () => { if (typeof onChange === 'function') { onChange(keys || [], option); } }); break; case 'expand': keys = expandedKeys; if (flag) { if (keys.indexOf(value) < 0) { keys = [...expandedKeys, value]; } } else { const cKeys = this.expandKeys(value); keys = keys.filter((v) => cKeys.indexOf(v) < 0); } let options = this.getOptions(keys); if (height && options.length * rowHeight > height) { const childKeys = this.getChildKeys(option.index === 0 ? option.value : option.parent); keys = keys.filter((k) => childKeys.indexOf(k) > -1); } options = this.getOptions(keys); const opts = this.update(options); this.setState(Object.assign({ expandedKeys: keys }, opts), () => { if (typeof onExpand === 'function') { onExpand(keys || [], option); } }); break; } }; }; this.getChildKeys = (value, options = this.props.options, keys = [], flag = false) => { for (let i = 0; i < options.length; i++) { const option = options[i]; if (option.value === value || flag) { keys.push(option.value); const children = option.children || []; if (children.length > 0) { keys = this.getChildKeys(value, children, keys, true); } } } return keys; }; this.expandKeys = (value, options = this.props.options, keys = [], found = false) => { options.forEach((o) => { const children = o.children || []; if (children.length > 0) { if (o.value === value || found) { keys.push(o.value); } keys = this.expandKeys(value, children, keys, o.value === value || found); } }); return keys; }; this.getSelectedPath = (selectedKeys, options = this.props.options, keys = []) => { options.forEach((o) => { const children = o.children || []; if (children.length > 0) { this.getSelectedPath(selectedKeys, children, keys); } if (selectedKeys.indexOf(o.value) > -1 || children.some((c) => keys.indexOf(c.value) > -1)) { keys.push(o.value); } }); return keys; }; this.getOptions = (expandedKeys = this.state.expandedKeys || [], options = this.props.options, opt = [], index = 0, parentExpanded = true, parent = '') => { options = options || []; const expandPlace = options.some((o) => o.children && o.children.length > 0); options.forEach((o) => { const { children } = o, other = __rest(o, ["children"]); const expandEnable = children && children.length > 0; const one = Object.assign(Object.assign({ expandEnable }, other), { index, expandPlace, parent }); const expanded = expandEnable && expandedKeys.indexOf(o.value) > -1; if (index === 0) parent = o.value; if (parentExpanded) { opt.push(one); } if (expandEnable) { this.getOptions(expandedKeys, children || [], opt, index + 1, expanded, parent); } }); return opt; }; this.getStyle = (type) => { const { rowHeight } = this.props; const opts = this.state[type.toString()]; const style = {}; if (opts.length <= 0) { style.display = 'none'; return style; } style.height = opts.length * rowHeight; return style; }; this.renderItem = (type) => { const { prefix, rowHeight, clickRow } = this.props; const options = this.state[type.toString()]; const { selectedKeys, expandedKeys, width } = this.state; return options.map((o) => { return (React.createElement(Item, { key: `${o.value}-${Math.random()}`, prefix: prefix, option: o, clickRow: clickRow, parentWidth: width || 100, rowHeight: rowHeight || 22, hasSelected: this.showColorKeys.indexOf(o.value) > -1, expanded: (expandedKeys || []).indexOf(o.value) > -1, checked: (selectedKeys || []).indexOf(o.value) > -1, onChange: this.onChange(o) })); }); }; this.showColorKeys = this.getSelectedPath(props.selectedKeys || [], props.options); this.state = { selectedKeys: props.selectedKeys || [], expandedKeys: props.expandedKeys || [], tops: [], options: [], bottoms: [], width: 100, height: 100 }; } componentWillMount() { this.setState({ options: this.getOptions() }); } componentDidMount() { if (this.wrap) { this.resize(); this.wrap.addEventListener('resize', this.resize); } window.addEventListener('resize', this.resize); } componentWillReceiveProps(nextProps) { let state = {}; if (nextProps.selectedKeys !== this.props.selectedKeys) { state.selectedKeys = nextProps.selectedKeys || []; this.showColorKeys = this.getSelectedPath(state.selectedKeys, nextProps.options); } if (nextProps.expandedKeys !== this.props.expandedKeys) { state.expandedKeys = nextProps.expandedKeys || []; } if (nextProps.options !== this.props.options) { state.tops = []; state.bottoms = []; state.options = this.getOptions(state.expandedKeys || this.state.expandedKeys, nextProps.options); state = Object.assign(Object.assign({}, state), this.update(state.options)); if (Object.prototype.hasOwnProperty.call(state, 'selectedKeys')) { this.showColorKeys = this.getSelectedPath(state.selectedKeys || [], nextProps.options); } else { this.showColorKeys = this.getSelectedPath(this.state.selectedKeys || [], nextProps.options); } } else { if (!!state.expandedKeys) { state.options = this.getOptions(state.expandedKeys); state = Object.assign(Object.assign({}, state), this.update(state.options)); } } if (Object.keys(state).length > 0) { this.setState(state, this.resize); } } render() { const { className, prefix } = this.props; const cls = classNames(`${prefix}`, className); const fixedTop = `${prefix}-fixed-top`; const fixedBottom = `${prefix}-fixed-bottom`; const topStyle = this.getStyle(Render_Type.tops); const bottomStyle = this.getStyle(Render_Type.bottoms); const containerStyle = {}; const innerStyle = {}; if (this.type === Scroll_Type.CONTAINER) { innerStyle.height = '100%'; innerStyle.overflowY = 'hidden'; innerStyle.paddingTop = topStyle.height || 0; innerStyle.paddingBottom = bottomStyle.height || 0; containerStyle.overflowY = 'auto'; containerStyle.height = '100%'; } return (React.createElement("div", { className: cls, ref: this.saveRef('wrap') }, React.createElement("div", { className: `${prefix}-inner`, style: innerStyle }, React.createElement("div", { className: fixedTop, style: topStyle }, this.renderItem(Render_Type.tops)), React.createElement("div", { className: `${prefix}-container`, style: containerStyle }, this.renderItem(Render_Type.options)), React.createElement("div", { className: fixedBottom, style: bottomStyle }, this.renderItem(Render_Type.bottoms))))); } } Tree.defaultProps = { prefix: 'swc-tree', options: [], selectedKeys: [], expandedKeys: [], rowHeight: 22, fixedTopBottom: true, clickRow: true }; export default Tree;