UNPKG

@airplane/views

Version:

A React library for building Airplane views. Views components are optimized in style and functionality to produce internal apps that are easy to build and maintain.

293 lines (292 loc) 8.68 kB
import React__default from "react"; import { defaultColumn, actions, useGetLatest, makePropGetter, ensurePluginOrder, useMountedLayoutEffect } from "react-table"; defaultColumn.canResize = true; actions.columnStartResizing = "columnStartResizing"; actions.columnResizing = "columnResizing"; actions.columnDoneResizing = "columnDoneResizing"; actions.resetResize = "resetResize"; const useResizeColumns = (hooks) => { hooks.getResizerProps = [defaultGetResizerProps]; hooks.getHeaderProps.push({ style: { position: "relative" } }); hooks.stateReducers.push(reducer); hooks.useInstance.push(useInstance); hooks.useInstanceBeforeDimensions.push(useInstanceBeforeDimensions); }; function getFirstDefined(...args) { for (let i = 0; i < args.length; i += 1) { if (typeof args[i] !== "undefined") { return args[i]; } } } let passiveSupported = null; function passiveEventSupported() { if (typeof passiveSupported === "boolean") return passiveSupported; let supported = false; try { const options = { get passive() { supported = true; return false; } }; window.addEventListener("test", null, options); window.removeEventListener("test", null, options); } catch (err) { supported = false; } passiveSupported = supported; return passiveSupported; } const defaultGetResizerProps = (props, { instance, header }) => { const { dispatch, visibleColumns, rowOffsetWidth } = instance; const onResizeStart = (e, header2) => { let isTouchEvent = false; if (e.type === "touchstart") { if (e.touches && e.touches.length > 1) { return; } isTouchEvent = true; } const headersToResize = getLeafHeaders(header2); const headerIdWidths = headersToResize.map((d) => [d.id, d.totalWidth]); const clientX = isTouchEvent ? Math.round(e.touches[0].clientX) : e.clientX; let raf; let mostRecentClientX; const dispatchEnd = () => { window.cancelAnimationFrame(raf); raf = null; dispatch({ type: actions.columnDoneResizing }); }; const dispatchMove = () => { window.cancelAnimationFrame(raf); raf = null; dispatch({ type: actions.columnResizing, clientX: mostRecentClientX }); }; const scheduleDispatchMoveOnNextAnimationFrame = (clientXPos) => { mostRecentClientX = clientXPos; if (!raf) { raf = window.requestAnimationFrame(dispatchMove); } }; const handlersAndEvents = { mouse: { moveEvent: "mousemove", moveHandler: (e2) => scheduleDispatchMoveOnNextAnimationFrame(e2.clientX), upEvent: "mouseup", upHandler: (e2) => { document.removeEventListener("mousemove", handlersAndEvents.mouse.moveHandler); document.removeEventListener("mouseup", handlersAndEvents.mouse.upHandler); dispatchEnd(); } }, touch: { moveEvent: "touchmove", moveHandler: (e2) => { if (e2.cancelable) { e2.preventDefault(); e2.stopPropagation(); } scheduleDispatchMoveOnNextAnimationFrame(e2.touches[0].clientX); return false; }, upEvent: "touchend", upHandler: (e2) => { document.removeEventListener(handlersAndEvents.touch.moveEvent, handlersAndEvents.touch.moveHandler); document.removeEventListener(handlersAndEvents.touch.upEvent, handlersAndEvents.touch.moveHandler); dispatchEnd(); } } }; const events = isTouchEvent ? handlersAndEvents.touch : handlersAndEvents.mouse; const passiveIfSupported = passiveEventSupported() ? { passive: false } : false; document.addEventListener(events.moveEvent, events.moveHandler, passiveIfSupported); document.addEventListener(events.upEvent, events.upHandler, passiveIfSupported); dispatch({ type: actions.columnStartResizing, columnId: header2.id, columnWidth: header2.totalWidth, headerIdWidths, clientX, // CHANGE: we dispatch the start-resizing event including both the real // row width, as well as the sum of the flex width (to compute the ratio between them). rowOffsetWidth, totalFlexWidth: visibleColumns.reduce((sum, col) => sum + col.totalFlexWidth, 0) }); }; return [props, { onMouseDown: (e) => e.persist() || onResizeStart(e, header), onTouchStart: (e) => e.persist() || onResizeStart(e, header), style: { cursor: "col-resize" }, draggable: false, role: "separator" }]; }; useResizeColumns.pluginName = "useResizeColumns"; function reducer(state, action) { if (action.type === actions.init) { return { columnResizing: { columnWidths: {} }, ...state }; } if (action.type === actions.resetResize) { return { ...state, columnResizing: { columnWidths: {} } }; } if (action.type === actions.columnStartResizing) { const { clientX, columnId, columnWidth, headerIdWidths, rowOffsetWidth, totalFlexWidth } = action; return { ...state, columnResizing: { ...state.columnResizing, startX: clientX, headerIdWidths, columnWidth, isResizingColumn: columnId, rowOffsetWidth, totalFlexWidth } }; } if (action.type === actions.columnResizing) { const { clientX } = action; const { startX, columnWidth, headerIdWidths = [], rowOffsetWidth } = state.columnResizing; const deltaX = clientX - startX; const actualColumnWidth = state.columnResizing.totalFlexWidth !== 0 ? columnWidth * rowOffsetWidth / state.columnResizing.totalFlexWidth : columnWidth; const targetColumnWidth = deltaX + actualColumnWidth; const columnWidthDelta = rowOffsetWidth !== targetColumnWidth ? (targetColumnWidth * state.columnResizing.totalFlexWidth - rowOffsetWidth * columnWidth) / (rowOffsetWidth - targetColumnWidth) : deltaX; const newColumnWidths = {}; headerIdWidths.forEach(([headerId, headerWidth]) => { newColumnWidths[headerId] = Math.max(headerWidth + columnWidthDelta, 0); }); return { ...state, columnResizing: { ...state.columnResizing, columnWidths: { ...state.columnResizing.columnWidths, ...newColumnWidths } } }; } if (action.type === actions.columnDoneResizing) { return { ...state, columnResizing: { ...state.columnResizing, startX: null, isResizingColumn: null } }; } } const useInstanceBeforeDimensions = (instance) => { const { flatHeaders, disableResizing, getHooks, state: { columnResizing } } = instance; const getInstance = useGetLatest(instance); flatHeaders.forEach((header) => { const canResize = getFirstDefined(header.disableResizing === true ? false : void 0, disableResizing === true ? false : void 0, true); header.canResize = canResize; if (columnResizing.columnWidths[header.id] > 0) { header.width = columnResizing.columnWidths[header.id]; } else if (columnResizing.columnWidths[header.id] === 0) { header.width = header.minWidth || header.originalWidth || header.width; } else { header.width = header.originalWidth || header.width; } header.isResizing = columnResizing.isResizingColumn === header.id; if (canResize) { header.getResizerProps = makePropGetter(getHooks().getResizerProps, { instance: getInstance(), header }); } }); }; function useInstance(instance) { const { plugins, dispatch, autoResetResize = true, columns } = instance; ensurePluginOrder(plugins, ["useAbsoluteLayout"], "useResizeColumns"); const getAutoResetResize = useGetLatest(autoResetResize); useMountedLayoutEffect(() => { if (getAutoResetResize()) { dispatch({ type: actions.resetResize }); } }, [columns]); const resetResizing = React__default.useCallback(() => dispatch({ type: actions.resetResize }), [dispatch]); Object.assign(instance, { resetResizing }); } function getLeafHeaders(header) { const leafHeaders = []; const recurseHeader = (header2) => { if (header2.columns && header2.columns.length) { header2.columns.map(recurseHeader); } leafHeaders.push(header2); }; recurseHeader(header); return leafHeaders; } export { useResizeColumns }; //# sourceMappingURL=useResizeColumns.js.map