ukelli-ui
Version:
Base on React's UI lib. Make frontend's dev simpler and faster.
286 lines (285 loc) • 12.3 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import React from 'react';
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import { IsFunc, DebounceClass } from 'basic-helper';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import { Icon } from '../icon';
import { ClickAway } from '../click-away';
import { getElementOffsetInfo } from '../utils/get-elem-offset';
import positionFilter from '../position-filter';
import setDOMById from '../set-dom';
import { getTop, getBottom, } from '../utils/position';
var dropdownContainerID = 'DropdownContainer';
var dropdownContainerDOM;
var offset = 10;
var calculateOverlayPosition = function (options) {
var target = options.target, position = options.position, overlayElem = options.overlayElem, scrollX = options.scrollX, scrollY = options.scrollY;
var _a = getElementOffsetInfo(target), offsetTop = _a.offsetTop, offsetLeft = _a.offsetLeft, offsetWidth = _a.offsetWidth, offsetHeight = _a.offsetHeight;
var overlayElemWidth = overlayElem.offsetWidth;
var overlayElemHeight = overlayElem.offsetHeight;
var offsetInfo = {
offsetWidth: offsetWidth,
offsetHeight: offsetHeight,
elemHeight: overlayElemHeight,
elemWidth: overlayElemWidth,
offsetLeft: offsetLeft,
offsetTop: offsetTop
};
var posiInfo;
var _position = [];
// const left = getLeft(offsetInfo);
if (position.indexOf('top') !== -1) {
posiInfo = getTop(offsetInfo);
}
else if (position.indexOf('bottom') !== -1) {
posiInfo = getBottom(offsetInfo);
}
if (position.indexOf('right') !== -1) {
posiInfo.left = offsetLeft + offsetWidth - overlayElemWidth;
_position.push('right');
}
else {
_position.push('left');
}
_position.push(posiInfo.position);
// overlayElem.classList.add(position);
// console.log(overlayElem.classList)
_position.forEach(function (p) {
overlayElem.classList.add(p);
});
// res = { top, left };
// topAnimation(overlayElem, top);
overlayElem.style.left = posiInfo.left - scrollX + "px";
overlayElem.style.top = posiInfo.top - scrollY + "px";
// setTimeout(() => overlayElem.classList.add('done'), 50);
// return { top, left };
return posiInfo;
};
var DropdownWrapper = /** @class */ (function (_super) {
__extends(DropdownWrapper, _super);
function DropdownWrapper(props) {
var _this = _super.call(this, props) || this;
_this.state = {
isShow: false,
searchValue: ''
};
// 记录是否已经渲染过一次 overlay
_this._shown = false;
_this.handleClickAway = function () {
if (_this.state.isShow)
_this.hide();
};
_this.handleClickMenu = function (e, preventDefault) {
if (preventDefault === void 0) { preventDefault = false; }
var _a = _this.props, outside = _a.outside, scrollElem = _a.scrollElem;
if (outside) {
if (preventDefault)
e.preventDefault();
// const { clientX, clientY } = e;
if (!_this.addScrollListener && scrollElem) {
var _scrollElem = scrollElem();
_scrollElem.addEventListener('scroll', _this.hide);
}
_this.addScrollListener = true;
}
_this.showSubMenu();
_this.focusInput();
};
_this.showSubMenu = function (isShow) {
if (isShow === void 0) { isShow = true; }
_this.setState({
isShow: !!isShow,
});
};
_this.hide = function () {
var scrollElem = _this.props.scrollElem;
if (_this.addScrollListener && scrollElem) {
var elem = scrollElem();
elem.removeEventListener('scroll', _this.hide);
_this.addScrollListener = false;
}
/** 一定隐藏成功 */
if (!_this.hideDebounce)
_this.hideDebounce = new DebounceClass();
_this.hideDebounce.exec(_this._hide, 50);
};
_this._hide = function () {
_this.setState({
isShow: false,
searchValue: ''
});
};
_this.saveInput = function (_i) {
if (_i)
_this._input = _i;
};
_this.onSearch = function (e) {
var val = e.target.value.trim();
_this.setState({
searchValue: val
});
};
_this.getPropsForOverlay = function () { return (__assign(__assign({}, _this.state), { hide: _this.hide, showSubMenu: _this.showSubMenu, focusInput: _this.focusInput })); };
_this.saveItems = function (e) {
_this.overlayElem = e;
if (!e)
return;
var _a = _this.props, scrollX = _a.scrollX, scrollY = _a.scrollY;
calculateOverlayPosition({
overlayElem: _this.overlayElem,
target: _this.displayTitleDOM,
position: _this._position,
scrollX: scrollX,
scrollY: scrollY
});
};
_this.overlayRender = function () {
var _a = _this.props, overlay = _a.overlay, outside = _a.outside, _b = _a.position, position = _b === void 0 ? '' : _b;
var isShow = _this.state.isShow;
// const isLeft = position.indexOf('left') !== -1;
// const caretOffset = this.displayTitleDOM ? this.displayTitleDOM.offsetWidth / 2 : 10;
var overlayClasses = classnames("dropdown-items", !outside && _this._position, isShow && 'show');
var dropdownCom = (React.createElement(TransitionGroup, { component: null },
React.createElement(CSSTransition, { key: isShow ? "opened" : "closed", classNames: "drop-menu", timeout: 200 }, isShow ? (React.createElement("div", __assign({ ref: outside ? function (e) { return _this.saveItems(e); } : null }, _this.bindOverlayTrigger(), { className: overlayClasses }),
React.createElement("span", { className: "caret" }),
overlay && overlay(_this.getPropsForOverlay()))) : React.createElement("span", null))));
return outside ? ReactDOM.createPortal(dropdownCom, dropdownContainerDOM) : dropdownCom;
};
_this.saveClickAway = function (e) {
_this.clickAwayRef = e;
if (e) {
_this.updateNodeRef = e.updateNodeRef;
}
};
_this.getDfaultChild = function (menuTitle) {
var withInput = _this.props.withInput;
var searchValue = _this.state.searchValue;
return (React.createElement("div", { className: "display-menu" },
React.createElement("div", { className: "display-title" }, menuTitle),
withInput && (React.createElement("input", { type: "text", ref: _this.saveInput, placeholder: typeof menuTitle === 'string' ? menuTitle : '', value: searchValue, className: "search-input", onChange: _this.onSearch })),
React.createElement("div", { className: "icon-wrap" },
React.createElement(Icon, { n: "angle-down" }))));
};
_this.childrenRender = function () {
var _a = _this.props, children = _a.children, menuTitle = _a.menuTitle;
var child;
var _title = menuTitle;
switch (true) {
case IsFunc(children):
child = children(_this.getPropsForOverlay());
break;
case React.isValidElement(children):
child = children;
break;
default:
if (typeof children === 'string') {
_title = children;
}
child = _this.getDfaultChild(_title);
break;
}
return child;
};
_this.handleMouseEnter = function (event) {
if (_this.delayExec)
_this.delayExec.cancel();
_this.handleClickMenu(event);
};
_this.handleMouseLeave = function () {
if (!_this.delayExec)
_this.delayExec = new DebounceClass();
_this.delayExec.exec(_this.handleClickAway, 200);
};
_this.bindOverlayTrigger = function () {
var _a = _this.props, trigger = _a.trigger, outside = _a.outside;
var res = {};
switch (trigger) {
case 'click':
if (outside) {
res = {
onClick: function (e) { return _this.handleClickMenu(e, true); }
};
}
break;
case 'hover':
res = {
onMouseEnter: _this.handleMouseEnter,
onMouseLeave: _this.handleMouseLeave
};
break;
}
return res;
};
_this.bindWrapperTrigger = function () {
var trigger = _this.props.trigger;
var res = {};
switch (trigger) {
case 'click':
res = {
onClick: _this.handleClickMenu
};
break;
case 'hover':
res = {
onMouseEnter: _this.handleMouseEnter,
onMouseLeave: _this.handleMouseLeave
};
break;
}
return res;
};
_this._position = positionFilter(props.position).split(' ');
if (!dropdownContainerDOM)
dropdownContainerDOM = setDOMById(dropdownContainerID, '__dropdown-menu outside');
return _this;
}
DropdownWrapper.prototype.focusInput = function () {
this._input && this._input.focus();
};
DropdownWrapper.prototype.render = function () {
var _this = this;
var isShow = this.state.isShow;
var _a = this.props, className = _a.className, withInput = _a.withInput, style = _a.style, error = _a.error, outside = _a.outside;
var classNames = classnames("__dropdown-menu", className && className, withInput && "input-mode", error && 'error', isShow && 'show', !outside && this._position);
return (React.createElement(ClickAway, { ref: this.saveClickAway, onClickAway: this.handleClickAway },
React.createElement("div", { className: classNames, style: style },
React.createElement("span", __assign({ className: "menu-wrapper", ref: function (e) { _this.displayTitleDOM = e; } }, this.bindWrapperTrigger()), this.childrenRender()),
this.overlayRender())));
};
DropdownWrapper.defaultProps = {
withInput: true,
menuTitle: 'Title',
trigger: 'click',
outside: false,
scrollX: 0,
scrollY: 0,
position: 'bottom,left',
scrollElem: function () { return document; }
};
return DropdownWrapper;
}(React.PureComponent));
export default DropdownWrapper;