UNPKG

@mentor-apm/react-sortable-tree

Version:

Drag-and-drop sortable component for nested data and hierarchies

234 lines (199 loc) 6.18 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var jsxRuntime = require('react/jsx-runtime'); var react = require('react'); var throttle = require('lodash.throttle'); var reactDnd = require('react-dnd'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var throttle__default = /*#__PURE__*/_interopDefaultLegacy(throttle); const noop = () => {}; const intBetween = (min, max, val) => Math.floor(Math.min(max, Math.max(min, val))); const getCoords = evt => { if (evt.type === 'touchmove') { return { x: evt.changedTouches[0].clientX, y: evt.changedTouches[0].clientY }; } return { x: evt.clientX, y: evt.clientY }; }; const DEFAULT_BUFFER = 150; const createHorizontalStrength = _buffer => ({ x, w, y, h }, point) => { const buffer = Math.min(w / 2, _buffer); const inRange = point.x >= x && point.x <= x + w; const inBox = inRange && point.y >= y && point.y <= y + h; if (inBox) { if (point.x < x + buffer) { return (point.x - x - buffer) / buffer; } if (point.x > x + w - buffer) { return -(x + w - point.x - buffer) / buffer; } } return 0; }; const createVerticalStrength = _buffer => ({ y, h, x, w }, point) => { const buffer = Math.min(h / 2, _buffer); const inRange = point.y >= y && point.y <= y + h; const inBox = inRange && point.x >= x && point.x <= x + w; if (inBox) { if (point.y < y + buffer) { return (point.y - y - buffer) / buffer; } if (point.y > y + h - buffer) { return -(y + h - point.y - buffer) / buffer; } } return 0; }; const defaultProps = { onScrollChange: noop, verticalStrength: createVerticalStrength(DEFAULT_BUFFER), horizontalStrength: createHorizontalStrength(DEFAULT_BUFFER), strengthMultiplier: 30 }; const createScrollingComponent = WrappedComponent => { return props => { props = { ...defaultProps, ...props }; let container; const wrappedInstance = react.createRef(); let frame; let scaleX = 0; let scaleY = 0; let attached = false; let dragging = false; const updateScrolling = throttle__default["default"](evt => { const { left: x, top: y, width: w, height: h } = container.getBoundingClientRect(); const box = { x, y, w, h }; const coords = getCoords(evt); scaleX = props.horizontalStrength(box, coords); scaleY = props.verticalStrength(box, coords); if (!frame && (scaleX || scaleY)) { startScrolling(); } }, 100, { trailing: false }); const handleEvent = evt => { if (dragging && !attached) { attached = true; window.document.body.addEventListener('dragover', updateScrolling); window.document.body.addEventListener('touchmove', updateScrolling); updateScrolling(evt); } }; react.useEffect(() => { container = wrappedInstance.current; if (container && typeof container.addEventListener === 'function') { container.addEventListener('dragover', handleEvent); } window.document.body.addEventListener('touchmove', handleEvent); const clearMonitorSubscription = props.dragDropManager.getMonitor().subscribeToStateChange(handleMonitorChange); return () => { if (container && typeof container.removeEventListener === 'function') { container.removeEventListener('dragover', handleEvent); } window.document.body.removeEventListener('touchmove', handleEvent); clearMonitorSubscription(); stopScrolling(); }; }, []); const handleMonitorChange = () => { const isDragging = props.dragDropManager.getMonitor().isDragging(); if (!dragging && isDragging) { dragging = true; } else if (dragging && !isDragging) { dragging = false; stopScrolling(); } }; const startScrolling = () => { let i = 0; const tick = () => { if (props.strengthMultiplier === 0 || scaleX + scaleY === 0) { stopScrolling(); return; } i += 1; if (i % 2) { const { scrollLeft, scrollTop, scrollWidth, scrollHeight, clientWidth, clientHeight } = container; const newLeft = scaleX ? container.scrollLeft = intBetween(0, scrollWidth - clientWidth, scrollLeft + scaleX * props.strengthMultiplier) : scrollLeft; const newTop = scaleY ? container.scrollTop = intBetween(0, scrollHeight - clientHeight, scrollTop + scaleY * props.strengthMultiplier) : scrollTop; props.onScrollChange(newLeft, newTop); } frame = requestAnimationFrame(tick); }; tick(); }; const stopScrolling = () => { attached = false; window.document.body.removeEventListener('dragover', updateScrolling); window.document.body.removeEventListener('touchmove', updateScrolling); scaleX = 0; scaleY = 0; if (frame) { cancelAnimationFrame(frame); frame = undefined; } }; const { strengthMultiplier, verticalStrength, horizontalStrength, onScrollChange, ...other } = props; return jsxRuntime.jsx(WrappedComponent, { ref: wrappedInstance, ...other }); }; }; const createScrollingComponentWithConsumer = WrappedComponent => { const ScrollingComponent = createScrollingComponent(WrappedComponent); return props => { return jsxRuntime.jsx(reactDnd.DndContext.Consumer, { children: ({ dragDropManager }) => !dragDropManager ? undefined : jsxRuntime.jsx(ScrollingComponent, { ...props, dragDropManager: dragDropManager }) }); }; }; exports.createHorizontalStrength = createHorizontalStrength; exports.createScrollingComponent = createScrollingComponent; exports.createVerticalStrength = createVerticalStrength; exports["default"] = createScrollingComponentWithConsumer;