@ui5/webcomponents-react
Version:
React Wrapper for UI5 Web Components and additional components
118 lines (116 loc) • 4.4 kB
JavaScript
'use client';
import { debounce } from '@ui5/webcomponents-react-base/utils';
import { useEffect, useRef } from 'react';
import { getProjectedWidth } from '../hooks/useColumnResizing.js';
/**
* Plugin Hook that adds a callback which is fired on column resize.
*
* @param {event} callback Fired when the column is resized by dragging the "Resizer".
* @param {Object=} options Additional options.
* @param {number=} options.wait If `liveUpdate` is `true`, the resize function will fire every time the width has changed depending on the `options.wait` delay.
* @param {boolean=} options.liveUpdate The number of milliseconds for which the calls are to be delayed. Defaults to `100`.
*/
export const useOnColumnResize = (callback, options) => {
const debouncedEvent = debounce(callback, options?.wait ?? 100);
// for liveUpdate mousemove/touchmove listeners have to be added via getResizerProps to fire the callback. Number of calls is defined by debounce value `wait`.
const getLiveResizerProps = (props, {
instance,
header
}) => {
return {
...props,
onMouseDown: e => {
props.onMouseDown?.(e);
const startClientX = e.clientX;
const columnWidth = header.totalWidth;
const columnId = header.id;
const handleMouseMove = moveEvent => {
const deltaX = moveEvent.clientX - startClientX;
if (Math.abs(deltaX) < 3) {
return;
}
const projectedWidth = getProjectedWidth(deltaX, columnWidth, instance.state.isRtl);
const currentHeader = instance.columns.find(item => item.id === columnId);
debouncedEvent({
columnWidth: projectedWidth,
header: currentHeader
});
};
const handleMouseUp = () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
},
onTouchStart: e => {
props.onTouchStart?.(e);
if (e.touches && e.touches.length > 1) {
return;
}
const startClientX = Math.round(e.touches[0].clientX);
const columnWidth = header.totalWidth;
const columnId = header.id;
const handleTouchMove = moveEvent => {
const deltaX = moveEvent.touches[0].clientX - startClientX;
if (Math.abs(deltaX) < 3) {
return;
}
const projectedWidth = getProjectedWidth(deltaX, columnWidth, instance.state.isRtl);
const currentHeader = instance.columns.find(item => item.id === columnId);
debouncedEvent({
columnWidth: projectedWidth,
header: currentHeader
});
};
const handleTouchEnd = () => {
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleTouchEnd);
};
document.addEventListener('touchmove', handleTouchMove);
document.addEventListener('touchend', handleTouchEnd);
}
};
};
const useInstance = instance => {
const {
state,
columns
} = instance;
const {
columnResizing
} = state;
const {
isResizingColumn,
columnWidths
} = columnResizing;
const prevHeaderIsResizing = useRef(undefined);
useEffect(() => {
if (options?.liveUpdate) {
return () => debouncedEvent.cancel();
}
}, []);
useEffect(() => {
if (!options?.liveUpdate) {
const currentHeader = columns.find(item => item.id === prevHeaderIsResizing.current);
if (isResizingColumn) {
prevHeaderIsResizing.current = isResizingColumn;
}
if (!isResizingColumn && prevHeaderIsResizing.current) {
callback({
columnWidth: columnWidths[prevHeaderIsResizing.current],
header: currentHeader
});
}
}
}, [columnResizing, columns, isResizingColumn, columnWidths]);
};
const useOnColumnResizeHooks = hooks => {
hooks.useFinalInstance.push(useInstance);
if (options?.liveUpdate) {
hooks.getResizerProps.push(getLiveResizerProps);
}
};
useOnColumnResizeHooks.pluginName = 'useOnColumnResize';
return useOnColumnResizeHooks;
};