UNPKG

@alifd/next

Version:

A configurable component library for web built on React.

664 lines (525 loc) 22.7 kB
'use strict'; exports.__esModule = true; var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _typeof2 = require('babel-runtime/helpers/typeof'); var _typeof3 = _interopRequireDefault(_typeof2); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _class, _temp; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _reactLifecyclesCompat = require('react-lifecycles-compat'); var _classnames = require('classnames'); var _classnames2 = _interopRequireDefault(_classnames); var _icon = require('../../icon'); var _icon2 = _interopRequireDefault(_icon); var _checkbox = require('../../checkbox'); var _checkbox2 = _interopRequireDefault(_checkbox); var _animate = require('../../animate'); var _animate2 = _interopRequireDefault(_animate); var _util = require('../../util'); var _treeNodeInput = require('./tree-node-input'); var _treeNodeInput2 = _interopRequireDefault(_treeNodeInput); var _treeNodeIndent = require('./tree-node-indent'); var _treeNodeIndent2 = _interopRequireDefault(_treeNodeIndent); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Expand = _animate2.default.Expand; var bindCtx = _util.func.bindCtx; var isPromise = _util.obj.isPromise, pickOthers = _util.obj.pickOthers, pickAttrsWith = _util.obj.pickAttrsWith; var isRoot = function isRoot(pos) { return (/^0-(\d)+$/.test(pos) ); }; /** * Tree.Node */ var TreeNode = (_temp = _class = function (_Component) { (0, _inherits3.default)(TreeNode, _Component); function TreeNode(props) { (0, _classCallCheck3.default)(this, TreeNode); var _this = (0, _possibleConstructorReturn3.default)(this, _Component.call(this, props)); _this.saveRef = function (ref) { _this.nodeEl = ref; }; _this.saveLabelWrapperRef = function (ref) { _this.labelWrapperEl = ref; }; _this.state = { editing: false, loading: false, label: props.label }; bindCtx(_this, ['handleExpand', 'handleSelect', 'handleCheck', 'handleEditStart', 'handleEditFinish', 'handleRightClick', 'handleDragStart', 'handleDragEnter', 'handleDragOver', 'handleDragLeave', 'handleDragEnd', 'handleDrop', 'handleInputKeyDown', 'handleKeyDown']); return _this; } TreeNode.getDerivedStateFromProps = function getDerivedStateFromProps(props) { if ('label' in props) { return { label: props.label }; } return null; }; TreeNode.prototype.componentDidMount = function componentDidMount() { this.itemNode = (0, _reactDom.findDOMNode)(this.nodeEl); this.setFocus(); }; TreeNode.prototype.componentDidUpdate = function componentDidUpdate() { this.setFocus(); }; TreeNode.prototype.getParentNode = function getParentNode() { return this.props.root.getParentNode(this.props.pos); }; TreeNode.prototype.focusable = function focusable() { var _props = this.props, root = _props.root, disabled = _props.disabled; var focusable = root.props.focusable; return focusable && !disabled; }; TreeNode.prototype.getFocused = function getFocused() { var _props2 = this.props, _key = _props2._key, root = _props2.root; var focusedKey = root.state.focusedKey; return focusedKey === _key; }; TreeNode.prototype.setFocus = function setFocus() { var focused = this.getFocused(); if (focused && this.focusable()) { this.itemNode.focus({ preventScroll: true }); } }; TreeNode.prototype.handleExpand = function handleExpand(e) { var _this2 = this; var _props3 = this.props, root = _props3.root, expanded = _props3.expanded, eventKey = _props3.eventKey; if (root.props.isNodeBlock) { e.stopPropagation(); } var loading = this.state.loading; if (loading) { return; } var returnValue = root.handleExpand(!expanded, eventKey, this); if (isPromise(returnValue)) { this.setLoading(true); return returnValue.then(function () { _this2.setLoading(false); }, function () { _this2.setLoading(false); }); } }; TreeNode.prototype.setLoading = function setLoading(loading) { this.setState({ loading: loading }); }; TreeNode.prototype.handleSelect = function handleSelect(e) { e.preventDefault(); var _props4 = this.props, root = _props4.root, selected = _props4.selected, eventKey = _props4.eventKey; root.handleSelect(!selected, eventKey, this, e); }; TreeNode.prototype.handleCheck = function handleCheck() { var _props5 = this.props, root = _props5.root, checked = _props5.checked, eventKey = _props5.eventKey; root.handleCheck(!checked, eventKey, this); }; TreeNode.prototype.handleEditStart = function handleEditStart(e) { e.preventDefault(); this.setState({ editing: true }); }; TreeNode.prototype.handleEditFinish = function handleEditFinish(e) { var label = e.target.value; this.setState({ editing: false }); var _props6 = this.props, root = _props6.root, eventKey = _props6.eventKey; root.props.onEditFinish(eventKey, label, this); }; TreeNode.prototype.handleRightClick = function handleRightClick(e) { this.props.root.props.onRightClick({ event: e, node: this }); }; TreeNode.prototype.handleDragStart = function handleDragStart(e) { e.stopPropagation(); this.props.root.handleDragStart(e, this); }; TreeNode.prototype.handleDragEnter = function handleDragEnter(e) { e.preventDefault(); e.stopPropagation(); this.props.root.handleDragEnter(e, this); }; TreeNode.prototype.handleDragOver = function handleDragOver(e) { if (this.props.root.canDrop(this)) { e.preventDefault(); this.props.root.handleDragOver(e, this); } e.stopPropagation(); }; TreeNode.prototype.handleDragLeave = function handleDragLeave(e) { e.stopPropagation(); this.props.root.handleDragLeave(e, this); }; TreeNode.prototype.handleDragEnd = function handleDragEnd(e) { e.stopPropagation(); this.props.root.handleDragEnd(e, this); }; TreeNode.prototype.handleDrop = function handleDrop(e) { e.preventDefault(); e.stopPropagation(); this.props.root.handleDrop(e, this); }; TreeNode.prototype.handleInputKeyDown = function handleInputKeyDown(e) { if (e.keyCode === _util.KEYCODE.ENTER) { this.handleEditFinish(e); } e.stopPropagation(); }; TreeNode.prototype.handleKeyDown = function handleKeyDown(e) { var _props7 = this.props, _key = _props7._key, root = _props7.root, disabled = _props7.disabled; if (disabled) { return; } if (this.focusable()) { root.handleItemKeyDown(_key, this, e); } this.props.onKeyDown && this.props.onKeyDown(e); }; TreeNode.prototype.addCallbacks = function addCallbacks(props) { var _props8 = this.props, disabled = _props8.disabled, root = _props8.root; if (!disabled) { var selectable = typeof this.props.selectable !== 'undefined' ? this.props.selectable : root.props.selectable; if (selectable) { props.onClick = this.handleSelect; } var editable = typeof this.props.editable !== 'undefined' ? this.props.editable : root.props.editable; if (editable) { props.onDoubleClick = this.handleEditStart; } var draggable = typeof this.props.draggable !== 'undefined' ? this.props.draggable : root.props.draggable; if (draggable) { props.draggable = true; props.onDragStart = this.handleDragStart; props.onDragEnd = this.handleDragEnd; } props.onContextMenu = this.handleRightClick; } }; TreeNode.prototype.renderSwitcher = function renderSwitcher(showLine) { var _cx, _cx2; var _props9 = this.props, prefix = _props9.prefix, disabled = _props9.disabled, expanded = _props9.expanded, root = _props9.root; var loadData = root.props.loadData; var loading = this.state.loading; var lineState = showLine ? 'line' : 'noline'; var className = (0, _classnames2.default)((_cx = {}, _cx[prefix + 'tree-switcher'] = true, _cx['' + prefix + lineState] = !loading, _cx[prefix + 'close'] = !loading && !showLine && !expanded, _cx[prefix + 'disabled'] = disabled, _cx[prefix + 'loading'] = loading, _cx[prefix + 'loading-' + lineState] = loading, _cx)); var iconType = loadData && loading ? 'loading' : showLine ? expanded ? 'minus' : 'add' : 'arrow-down'; var iconCls = (0, _classnames2.default)((_cx2 = {}, _cx2[prefix + 'tree-switcher-icon'] = true, _cx2[prefix + 'tree-fold-icon'] = iconType === 'arrow-down', _cx2[prefix + 'tree-switcher-fold-icon'] = showLine && !expanded, _cx2[prefix + 'tree-switcher-unfold-icon'] = showLine && expanded, _cx2)); return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events _react2.default.createElement( 'span', { className: className, onClick: disabled ? null : this.handleExpand }, this.renderRightAngle(showLine), _react2.default.createElement(_icon2.default, { className: iconCls, type: iconType }) ) ); }; TreeNode.prototype.renderNoopSwitcher = function renderNoopSwitcher(showLine) { var _cx3; var _props10 = this.props, prefix = _props10.prefix, pos = _props10.pos; var lineState = showLine ? 'line' : 'noline'; var className = (0, _classnames2.default)((_cx3 = {}, _cx3[prefix + 'tree-switcher'] = true, _cx3[prefix + 'noop-' + lineState] = true, _cx3[prefix + 'noop-line-noroot'] = showLine && !isRoot(pos), _cx3)); return _react2.default.createElement( 'span', { className: className }, this.renderRightAngle(showLine) ); }; TreeNode.prototype.renderRightAngle = function renderRightAngle(showLine) { var _props11 = this.props, prefix = _props11.prefix, pos = _props11.pos; return showLine && !isRoot(pos) ? _react2.default.createElement('span', { className: prefix + 'tree-right-angle' }) : null; }; TreeNode.prototype.renderCheckbox = function renderCheckbox() { var _props12 = this.props, checked = _props12.checked, indeterminate = _props12.indeterminate, disabled = _props12.disabled, checkboxDisabled = _props12.checkboxDisabled; var label = this.state.label; return _react2.default.createElement(_checkbox2.default, { 'aria-label': typeof label === 'string' ? label : null, checked: checked, tabIndex: -1, indeterminate: indeterminate, disabled: disabled || checkboxDisabled // don't use onChange, fix https://github.com/alibaba-fusion/next/issues/3850 , onClick: this.handleCheck }); }; TreeNode.prototype.renderLabel = function renderLabel() { var _cx4; var _props13 = this.props, prefix = _props13.prefix, root = _props13.root, disabled = _props13.disabled, icon = _props13.icon; var isNodeBlock = root.props.isNodeBlock; var label = this.state.label; var selectable = typeof this.props.selectable !== 'undefined' ? this.props.selectable : root.props.selectable; var labelProps = { className: (0, _classnames2.default)((_cx4 = {}, _cx4[prefix + 'tree-node-label'] = true, _cx4[prefix + 'tree-node-label-selectable'] = selectable && !disabled, _cx4)) }; if (!isNodeBlock) { this.addCallbacks(labelProps); } var iconEl = typeof icon === 'string' ? _react2.default.createElement(_icon2.default, { type: icon }) : icon; return _react2.default.createElement( 'div', { className: prefix + 'tree-node-label-wrapper', ref: this.saveLabelWrapperRef }, _react2.default.createElement( 'div', labelProps, iconEl, label ) ); }; TreeNode.prototype.renderInput = function renderInput() { var prefix = this.props.prefix; var label = this.state.label; return _react2.default.createElement( 'div', { className: prefix + 'tree-node-label-wrapper', ref: this.saveLabelWrapperRef }, _react2.default.createElement(_treeNodeInput2.default, { prefix: prefix, defaultValue: label, onBlur: this.handleEditFinish, onKeyDown: this.handleInputKeyDown }) ); }; TreeNode.prototype.renderChildTree = function renderChildTree() { var _props14 = this.props, prefix = _props14.prefix, children = _props14.children; return children && this.addAnimationIfNeeded(_react2.default.createElement( 'ul', { role: 'group', className: prefix + 'tree-child-tree' }, children )); }; TreeNode.prototype.addAnimationIfNeeded = function addAnimationIfNeeded(node) { var root = this.props.root; return root && root.props.animation ? _react2.default.createElement( Expand, { animationAppear: false }, node ) : node; }; TreeNode.prototype.render = function render() { var _cx5, _cx6, _ref; var _props15 = this.props, prefix = _props15.prefix, rtl = _props15.rtl, className = _props15.className, isLeaf = _props15.isLeaf, level = _props15.level, root = _props15.root, selected = _props15.selected, checked = _props15.checked, disabled = _props15.disabled, dragOver = _props15.dragOver, dragOverGapTop = _props15.dragOverGapTop, dragOverGapBottom = _props15.dragOverGapBottom, _key = _props15._key, size = _props15.size, posinset = _props15.posinset, children = _props15.children, expanded = _props15.expanded, isLastChild = _props15.isLastChild; var _root$props = root.props, isNodeBlock = _root$props.isNodeBlock, showLine = _root$props.showLine, rootDraggable = _root$props.draggable, filterTreeNode = _root$props.filterTreeNode; var label = this.state.label; var ARIA_PREFIX = 'aria-'; var ariaProps = pickAttrsWith(this.props, ARIA_PREFIX); var others = pickOthers(Object.keys(TreeNode.propTypes), this.props); var hasRenderChildNodes = root && root.props.renderChildNodes; var shouldShouldLine = !isNodeBlock && showLine && !hasRenderChildNodes; var useVirtual = root && root.props.useVirtual; // remove aria keys Object.keys(others).forEach(function (key) { if (key.match(ARIA_PREFIX)) { delete others[key]; } }); if (rootDraggable) { others.onDragEnter = this.handleDragEnter; others.onDragOver = this.handleDragOver; others.onDragLeave = this.handleDragLeave; others.onDrop = this.handleDrop; } var newClassName = (0, _classnames2.default)((_cx5 = {}, _cx5[prefix + 'tree-node'] = true, _cx5[prefix + 'filtered'] = !!filterTreeNode && !!root.filterTreeNode(this), _cx5[className] = !!className, _cx5)); var innerClassName = (0, _classnames2.default)((_cx6 = {}, _cx6[prefix + 'tree-node-inner'] = true, _cx6[prefix + 'selected'] = selected, _cx6[prefix + 'disabled'] = disabled, _cx6[prefix + 'drag-over'] = dragOver, _cx6[prefix + 'drag-over-gap-top'] = dragOverGapTop, _cx6[prefix + 'drag-over-gap-bottom'] = dragOverGapBottom, _cx6)); var defaultPaddingLeft = (typeof isNodeBlock === 'undefined' ? 'undefined' : (0, _typeof3.default)(isNodeBlock)) === 'object' ? parseInt(isNodeBlock.defaultPaddingLeft || 0) : 0; var paddingLeftProp = rtl ? 'paddingRight' : 'paddingLeft'; var indent = (typeof isNodeBlock === 'undefined' ? 'undefined' : (0, _typeof3.default)(isNodeBlock)) === 'object' ? parseInt(isNodeBlock.indent || 24) : 24; var innerStyle = isNodeBlock ? (_ref = {}, _ref[paddingLeftProp] = (useVirtual ? 0 : indent * (level - 1)) + defaultPaddingLeft + 'px', _ref) : null; var innerProps = (0, _extends3.default)({ className: innerClassName, style: innerStyle, onKeyDown: this.handleKeyDown }, ariaProps); if (isNodeBlock) { this.addCallbacks(innerProps); } var checkable = typeof this.props.checkable !== 'undefined' ? this.props.checkable : root.props.checkable; var editing = this.state.editing; innerProps.tabIndex = root.tabbableKey === _key ? '0' : '-1'; if (rtl) { others.dir = 'rtl'; } return this.addAnimationIfNeeded(_react2.default.createElement( 'li', (0, _extends3.default)({ role: 'presentation', className: newClassName }, others), _react2.default.createElement( 'div', (0, _extends3.default)({ ref: this.saveRef, role: 'treeitem', 'aria-selected': selected, 'aria-disabled': disabled, 'aria-checked': checked, 'aria-expanded': !isLeaf, 'aria-label': typeof label === 'string' ? label : null, 'aria-level': level, 'aria-posinset': posinset, 'aria-setsize': size }, innerProps), useVirtual && !hasRenderChildNodes && _react2.default.createElement(_treeNodeIndent2.default, { prefix: prefix, level: level, isLastChild: isLastChild, showLine: shouldShouldLine }), isLeaf ? this.renderNoopSwitcher(shouldShouldLine) : this.renderSwitcher(shouldShouldLine), checkable ? this.renderCheckbox() : null, editing ? this.renderInput() : this.renderLabel() ), expanded && (hasRenderChildNodes ? children : this.renderChildTree(children)) )); }; return TreeNode; }(_react.Component), _class.propTypes = { prefix: _propTypes2.default.string, rtl: _propTypes2.default.bool, _key: _propTypes2.default.string, className: _propTypes2.default.string, /** * 树节点 */ children: _propTypes2.default.node, /** * 节点文本内容 */ label: _propTypes2.default.node, /** * 单独设置是否支持选中,覆盖 Tree 的 selectable */ selectable: _propTypes2.default.bool, /** * 单独设置是否出现复选框,覆盖 Tree 的 checkable */ checkable: _propTypes2.default.bool, /** * 单独设置是否支持编辑,覆盖 Tree 的 editable */ editable: _propTypes2.default.bool, /** * 单独设置是否支持拖拽,覆盖 Tree 的 draggable */ draggable: _propTypes2.default.bool, /** * 是否禁止节点响应 */ disabled: _propTypes2.default.bool, /** * 是否禁止勾选节点复选框 */ checkboxDisabled: _propTypes2.default.bool, /** * 是否是叶子节点,设置loadData时生效 */ isLeaf: _propTypes2.default.bool, root: _propTypes2.default.object, eventKey: _propTypes2.default.string, pos: _propTypes2.default.string, expanded: _propTypes2.default.bool, selected: _propTypes2.default.bool, checked: _propTypes2.default.bool, indeterminate: _propTypes2.default.bool, dragOver: _propTypes2.default.bool, dragOverGapTop: _propTypes2.default.bool, dragOverGapBottom: _propTypes2.default.bool, parentNode: _propTypes2.default.object, onKeyDown: _propTypes2.default.func, // 无障碍化属性:aria-setsize size: _propTypes2.default.number, // 无障碍化属性:aria-posinset posinset: _propTypes2.default.number, // 是否是最后一个子节点,数组类型,包含对祖先节点的判断 isLastChild: _propTypes2.default.arrayOf(_propTypes2.default.bool), /** * 自定义图标,可以使用 Icon 的 type,也可以使用组件 `<Icon type="icon type" />` * @version 1.21 */ icon: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.node]) }, _class.defaultProps = { label: '---', rtl: false, disabled: false, checkboxDisabled: false, size: 1, posinset: 1 }, _temp); TreeNode.displayName = 'TreeNode'; exports.default = (0, _reactLifecyclesCompat.polyfill)(TreeNode); module.exports = exports['default'];