SplitBar.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. "use strict";
  2. "use client";
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  5. Object.defineProperty(exports, "__esModule", {
  6. value: true
  7. });
  8. exports.default = void 0;
  9. var _react = _interopRequireWildcard(require("react"));
  10. var _DownOutlined = _interopRequireDefault(require("@ant-design/icons/DownOutlined"));
  11. var _LeftOutlined = _interopRequireDefault(require("@ant-design/icons/LeftOutlined"));
  12. var _RightOutlined = _interopRequireDefault(require("@ant-design/icons/RightOutlined"));
  13. var _UpOutlined = _interopRequireDefault(require("@ant-design/icons/UpOutlined"));
  14. var _classnames = _interopRequireDefault(require("classnames"));
  15. var _useEvent = _interopRequireDefault(require("rc-util/lib/hooks/useEvent"));
  16. var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect"));
  17. function getValidNumber(num) {
  18. return typeof num === 'number' && !Number.isNaN(num) && Number.isFinite(num) ? Math.round(num) : 0;
  19. }
  20. const SplitBar = props => {
  21. const {
  22. prefixCls,
  23. vertical,
  24. index,
  25. active,
  26. ariaNow,
  27. ariaMin,
  28. ariaMax,
  29. resizable,
  30. startCollapsible,
  31. endCollapsible,
  32. onOffsetStart,
  33. onOffsetUpdate,
  34. onOffsetEnd,
  35. onCollapse,
  36. lazy,
  37. containerSize,
  38. showStartCollapsibleIcon,
  39. showEndCollapsibleIcon
  40. } = props;
  41. const splitBarPrefixCls = `${prefixCls}-bar`;
  42. // ======================== Resize ========================
  43. const [startPos, setStartPos] = (0, _react.useState)(null);
  44. const [constrainedOffset, setConstrainedOffset] = (0, _react.useState)(0);
  45. const constrainedOffsetX = vertical ? 0 : constrainedOffset;
  46. const constrainedOffsetY = vertical ? constrainedOffset : 0;
  47. const onMouseDown = e => {
  48. if (resizable && e.currentTarget) {
  49. setStartPos([e.pageX, e.pageY]);
  50. onOffsetStart(index);
  51. }
  52. };
  53. const onTouchStart = e => {
  54. if (resizable && e.touches.length === 1) {
  55. const touch = e.touches[0];
  56. setStartPos([touch.pageX, touch.pageY]);
  57. onOffsetStart(index);
  58. }
  59. };
  60. // Updated constraint calculation
  61. const getConstrainedOffset = rawOffset => {
  62. const currentPos = containerSize * ariaNow / 100;
  63. const newPos = currentPos + rawOffset;
  64. // Calculate available space
  65. const minAllowed = Math.max(0, containerSize * ariaMin / 100);
  66. const maxAllowed = Math.min(containerSize, containerSize * ariaMax / 100);
  67. // Constrain new position within bounds
  68. const clampedPos = Math.max(minAllowed, Math.min(maxAllowed, newPos));
  69. return clampedPos - currentPos;
  70. };
  71. const handleLazyMove = (0, _useEvent.default)((offsetX, offsetY) => {
  72. const constrainedOffsetValue = getConstrainedOffset(vertical ? offsetY : offsetX);
  73. setConstrainedOffset(constrainedOffsetValue);
  74. });
  75. const handleLazyEnd = (0, _useEvent.default)(() => {
  76. onOffsetUpdate(index, constrainedOffsetX, constrainedOffsetY, true);
  77. setConstrainedOffset(0);
  78. onOffsetEnd(true);
  79. });
  80. const getVisibilityClass = mode => {
  81. switch (mode) {
  82. case true:
  83. return `${splitBarPrefixCls}-collapse-bar-always-visible`;
  84. case false:
  85. return `${splitBarPrefixCls}-collapse-bar-always-hidden`;
  86. case 'auto':
  87. return `${splitBarPrefixCls}-collapse-bar-hover-only`;
  88. }
  89. };
  90. (0, _useLayoutEffect.default)(() => {
  91. if (!startPos) {
  92. return;
  93. }
  94. const onMouseMove = e => {
  95. const {
  96. pageX,
  97. pageY
  98. } = e;
  99. const offsetX = pageX - startPos[0];
  100. const offsetY = pageY - startPos[1];
  101. if (lazy) {
  102. handleLazyMove(offsetX, offsetY);
  103. } else {
  104. onOffsetUpdate(index, offsetX, offsetY);
  105. }
  106. };
  107. const onMouseUp = () => {
  108. if (lazy) {
  109. handleLazyEnd();
  110. } else {
  111. onOffsetEnd();
  112. }
  113. setStartPos(null);
  114. };
  115. const handleTouchMove = e => {
  116. if (e.touches.length === 1) {
  117. const touch = e.touches[0];
  118. const offsetX = touch.pageX - startPos[0];
  119. const offsetY = touch.pageY - startPos[1];
  120. if (lazy) {
  121. handleLazyMove(offsetX, offsetY);
  122. } else {
  123. onOffsetUpdate(index, offsetX, offsetY);
  124. }
  125. }
  126. };
  127. const handleTouchEnd = () => {
  128. if (lazy) {
  129. handleLazyEnd();
  130. } else {
  131. onOffsetEnd();
  132. }
  133. setStartPos(null);
  134. };
  135. const eventHandlerMap = {
  136. mousemove: onMouseMove,
  137. mouseup: onMouseUp,
  138. touchmove: handleTouchMove,
  139. touchend: handleTouchEnd
  140. };
  141. for (const [event, handler] of Object.entries(eventHandlerMap)) {
  142. // eslint-disable-next-line react-web-api/no-leaked-event-listener
  143. window.addEventListener(event, handler);
  144. }
  145. return () => {
  146. for (const [event, handler] of Object.entries(eventHandlerMap)) {
  147. window.removeEventListener(event, handler);
  148. }
  149. };
  150. }, [startPos, index, lazy]);
  151. const transformStyle = {
  152. [`--${splitBarPrefixCls}-preview-offset`]: `${constrainedOffset}px`
  153. };
  154. // ======================== Render ========================
  155. const StartIcon = vertical ? _UpOutlined.default : _LeftOutlined.default;
  156. const EndIcon = vertical ? _DownOutlined.default : _RightOutlined.default;
  157. return /*#__PURE__*/_react.default.createElement("div", {
  158. className: splitBarPrefixCls,
  159. role: "separator",
  160. "aria-valuenow": getValidNumber(ariaNow),
  161. "aria-valuemin": getValidNumber(ariaMin),
  162. "aria-valuemax": getValidNumber(ariaMax)
  163. }, lazy && (/*#__PURE__*/_react.default.createElement("div", {
  164. className: (0, _classnames.default)(`${splitBarPrefixCls}-preview`, {
  165. [`${splitBarPrefixCls}-preview-active`]: !!constrainedOffset
  166. }),
  167. style: transformStyle
  168. })), /*#__PURE__*/_react.default.createElement("div", {
  169. className: (0, _classnames.default)(`${splitBarPrefixCls}-dragger`, {
  170. [`${splitBarPrefixCls}-dragger-disabled`]: !resizable,
  171. [`${splitBarPrefixCls}-dragger-active`]: active
  172. }),
  173. onMouseDown: onMouseDown,
  174. onTouchStart: onTouchStart
  175. }), startCollapsible && (/*#__PURE__*/_react.default.createElement("div", {
  176. className: (0, _classnames.default)(`${splitBarPrefixCls}-collapse-bar`, `${splitBarPrefixCls}-collapse-bar-start`, getVisibilityClass(showStartCollapsibleIcon)),
  177. onClick: () => onCollapse(index, 'start')
  178. }, /*#__PURE__*/_react.default.createElement(StartIcon, {
  179. className: (0, _classnames.default)(`${splitBarPrefixCls}-collapse-icon`, `${splitBarPrefixCls}-collapse-start`)
  180. }))), endCollapsible && (/*#__PURE__*/_react.default.createElement("div", {
  181. className: (0, _classnames.default)(`${splitBarPrefixCls}-collapse-bar`, `${splitBarPrefixCls}-collapse-bar-end`, getVisibilityClass(showEndCollapsibleIcon)),
  182. onClick: () => onCollapse(index, 'end')
  183. }, /*#__PURE__*/_react.default.createElement(EndIcon, {
  184. className: (0, _classnames.default)(`${splitBarPrefixCls}-collapse-icon`, `${splitBarPrefixCls}-collapse-end`)
  185. }))));
  186. };
  187. var _default = exports.default = SplitBar;