@sms-frontend/components
Version:
SMS Design React UI Library.
135 lines (134 loc) • 6.61 kB
JavaScript
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import React, { forwardRef, useContext, useImperativeHandle, useState, useRef, useEffect, } from 'react';
import cs from '../_util/classNames';
import ResizeTrigger from './resize-trigger';
import { ConfigContext } from '../ConfigProvider';
import { on, off } from '../_util/dom';
import useIsomorphicLayoutEffect from '../_util/hooks/useIsomorphicLayoutEffect';
var DIRECTION_HORIZONTAL = 'horizontal';
var DIRECTION_VERTICAL = 'vertical';
function Split(props, ref) {
var style = props.style, className = props.className, _a = props.component, component = _a === void 0 ? 'div' : _a, _b = props.direction, direction = _b === void 0 ? 'horizontal' : _b, icon = props.icon, _c = props.size, size = _c === void 0 ? 0.5 : _c, min = props.min, max = props.max, panes = props.panes, disabled = props.disabled, trigger = props.trigger;
var getPrefixCls = useContext(ConfigContext).getPrefixCls;
var prefixCls = getPrefixCls('resizebox-split');
var isHorizontal = direction === DIRECTION_HORIZONTAL;
var isTriggerHorizontal = !isHorizontal;
var classNames = cs(prefixCls, prefixCls + "-" + (isHorizontal ? DIRECTION_HORIZONTAL : DIRECTION_VERTICAL), className);
var _d = __read(panes, 2), firstPane = _d[0], secondPane = _d[1];
var isPxSize = typeof size === 'string';
var _e = __read(useState(parseFloat(size)), 2), offset = _e[0], setOffset = _e[1];
var _f = __read(useState(0), 2), triggerSize = _f[0], setTriggerSize = _f[1];
var recordRef = useRef({
startX: 0,
startY: 0,
startWidth: 0,
startHeight: 0,
startOffset: 0,
moving: false,
});
var wrapperRef = useRef();
var paneContainers = useRef([]);
useImperativeHandle(ref, function () { return wrapperRef.current; }, []);
function px2percent(numerator, denominator) {
return parseFloat(numerator) / parseFloat(denominator);
}
function getOffset(startSize, startOffset, startPosition, currentPosition) {
var minOffset = min ? parseFloat(min) : 0;
var maxOffset = max ? parseFloat(max) : isPxSize ? startSize : 1;
var moveOffset = isPxSize
? startOffset + (currentPosition - startPosition)
: px2percent(startSize * startOffset + currentPosition - startPosition, startSize);
moveOffset = Math.max(moveOffset, minOffset);
moveOffset = Math.min(moveOffset, maxOffset);
return moveOffset;
}
// 移动开始,记录初始值,绑定移动事件
function onTriggerMouseDown(e) {
var _a, _b;
props.onMovingStart && props.onMovingStart();
recordRef.current.moving = true;
recordRef.current.startX = e.pageX;
recordRef.current.startY = e.pageY;
recordRef.current.startWidth = (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth;
recordRef.current.startHeight = (_b = wrapperRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight;
recordRef.current.startOffset = offset;
on(window, 'mousemove', moving);
on(window, 'touchmove', moving);
on(window, 'mouseup', moveEnd);
on(window, 'touchend', moveEnd);
on(window, 'contextmenu', moveEnd);
document.body.style.cursor = isTriggerHorizontal ? 'row-resize' : 'col-resize';
}
// 移动中,更新 firstPane 的占位大小
function moving(e) {
if (recordRef.current.moving) {
/* eslint-disable */
var newOffset = isHorizontal
? getOffset(recordRef.current.startWidth, recordRef.current.startOffset, recordRef.current.startX, e.pageX)
: getOffset(recordRef.current.startHeight, recordRef.current.startOffset, recordRef.current.startY, e.pageY);
setOffset(newOffset);
props.onMoving && props.onMoving(e, isPxSize ? newOffset + "px" : newOffset);
}
}
// 移动结束,解除事件绑定
function moveEnd() {
recordRef.current.moving = false;
off(window, 'mousemove', moving);
off(window, 'touchmove', moving);
off(window, 'mouseup', moveEnd);
off(window, 'touchend', moveEnd);
off(window, 'contextmenu', moveEnd);
document.body.style.cursor = 'default';
props.onMovingEnd && props.onMovingEnd();
}
// 更新 trigger 大小
function onTriggerResize(e) {
var contentRect = e[0].contentRect;
var newTriggerSize = contentRect[isTriggerHorizontal ? 'height' : 'width'];
setTriggerSize(newTriggerSize);
}
// 根据 offset 和 triggerSize 计算 firstPane 的样式
function getFirstPaneSize() {
var unit = isPxSize ? 'px' : '%';
if (!offset)
return "0" + unit;
var baseVal = isPxSize ? offset : offset * 100;
return "calc(" + baseVal + unit + " - " + triggerSize / 2 + "px)";
}
useEffect(function () {
props.onPaneResize && props.onPaneResize(paneContainers.current);
}, [offset, triggerSize]);
useIsomorphicLayoutEffect(function () {
var newOffset = parseFloat(size);
if (offset !== newOffset) {
setOffset(newOffset);
}
}, [size]);
var Tag = component;
return (React.createElement(Tag, { style: style, className: classNames, ref: wrapperRef },
React.createElement("div", { className: cs(prefixCls + "-pane", 'first-pane'), style: { flexBasis: getFirstPaneSize() }, ref: function (el) {
paneContainers.current[0] = el;
} }, firstPane),
!disabled && (React.createElement(ResizeTrigger, { className: prefixCls + "-trigger", direction: isTriggerHorizontal ? DIRECTION_HORIZONTAL : DIRECTION_VERTICAL, icon: icon, onMouseDown: onTriggerMouseDown, onResize: onTriggerResize }, trigger)),
React.createElement("div", { className: cs(prefixCls + "-pane", 'second-pane'), ref: function (el) {
paneContainers.current[1] = el;
} }, secondPane)));
}
var SplitComponent = forwardRef(Split);
SplitComponent.displayName = 'ResizeBoxSplit';
export default SplitComponent;