UNPKG

@wix/design-system

Version:

@wix/design-system

156 lines 6.03 kB
import React, { useState, useMemo, useCallback, createContext } from 'react'; import { getStickyColumnStyle, CELL_PADDING, CELL_EDGE_PADDING, } from '../DataTable/DataTable.utils'; const MIN_COLUMN_WIDTH = 60; const parseColumnWidth = (width) => { if (!width) return MIN_COLUMN_WIDTH; if (typeof width === 'number') { return width; } if (typeof width === 'string') { if (width.endsWith('px')) { const parsed = parseInt(width, 10); return isNaN(parsed) ? MIN_COLUMN_WIDTH : parsed; } if (width.endsWith('%')) { return width; } const parsed = parseInt(width, 10); return isNaN(parsed) ? MIN_COLUMN_WIDTH : parsed; } return MIN_COLUMN_WIDTH; }; const createDefaultContext = () => ({ columnWidths: null, getEffectiveColumnWidth: (column) => column.width, // default handling of sticky columns style is the exsisting util getStickyColumnStyle: (columns, column) => { return getStickyColumnStyle(columns, column); }, getTableWidth: (fallback) => fallback || '100%', resizeColumn: () => { }, }); export const ColumnResizeContext = createContext(createDefaultContext()); /** * ColumnResize manages the state and logic of column resizing for tables. * Given an array of columns with resize configuration, it provides a context with resize handlers, * width calculations, and sticky column positioning. * * Key features: * - Manages column width state with min/max constraints * - Provides effective width calculations for columns * - Handles sticky column positioning with dynamic widths * - Supports both resizable and non-resizable table modes * - Offers resize event callbacks (onColumnResize, onColumnResizeStart, onColumnResizeEnd) */ export const ColumnResize = ({ columns = [], isTableResizable = false, onColumnResize, onColumnResizeStart, onColumnResizeEnd, minColumnWidth = MIN_COLUMN_WIDTH, maxColumnWidth, children, }) => { const initializeColumnWidths = () => { if (!isTableResizable) { return null; } // Resizable flow: Parse all widths to numbers, store in mapping return columns.reduce((acc, column) => { const id = column.resizeProps?.id; if (id) { const parsedWidth = parseColumnWidth(column.width); if (typeof parsedWidth === 'number') { acc[id] = parsedWidth; } } return acc; }, {}); }; const [columnWidths, setColumnWidths] = useState(initializeColumnWidths); const getEffectiveColumnWidth = useCallback((column) => { if (isTableResizable && columnWidths) { const id = column.resizeProps?.id?.toString(); if (id && columnWidths[id]) { return columnWidths[id]; } return parseColumnWidth(column.width); } return column.width; }, [isTableResizable, columnWidths]); const getStickyColumnStyle = useCallback((columns, column) => { let left = 0; for (let i = 0; i < columns.length; i++) { const col = columns[i]; if (col === column) { break; } const horizontalPadding = i === 0 ? CELL_EDGE_PADDING + CELL_PADDING : 2 * CELL_PADDING; const effectiveWidth = getEffectiveColumnWidth(col); const widthValue = typeof effectiveWidth === 'string' ? parseInt(effectiveWidth, 10) : effectiveWidth; left += (widthValue ?? MIN_COLUMN_WIDTH) + horizontalPadding; } return { left }; }, [getEffectiveColumnWidth]); const handleColumnResize = useCallback((columnId, newWidth) => { if (!isTableResizable || !columnWidths) { return; } let clampedWidth = newWidth; if (minColumnWidth !== undefined && newWidth < minColumnWidth) { clampedWidth = minColumnWidth; } if (maxColumnWidth !== undefined && newWidth > maxColumnWidth) { clampedWidth = maxColumnWidth; } setColumnWidths(prevState => { if (!prevState) { return prevState; } const updatedColumnWidths = { ...prevState, [columnId]: clampedWidth, }; return updatedColumnWidths; }); if (onColumnResize) { onColumnResize(columnId, clampedWidth); } }, [ isTableResizable, columnWidths, minColumnWidth, maxColumnWidth, onColumnResize, ]); const handleColumnResizeStart = useCallback((columnId, e) => { if (onColumnResizeStart && columnWidths) { onColumnResizeStart(columnId, columnWidths[columnId], e); } }, [onColumnResizeStart, columnWidths]); const handleColumnResizeEnd = useCallback((columnId, e) => { if (onColumnResizeEnd && columnWidths) { onColumnResizeEnd(columnId, columnWidths[columnId], e); } }, [onColumnResizeEnd, columnWidths]); const getTableWidth = useCallback((fallbackWidth) => { if (!isTableResizable) { return fallbackWidth || '100%'; } return 'fit-content'; }, [isTableResizable]); const contextValue = useMemo(() => ({ columnWidths, getEffectiveColumnWidth, getStickyColumnStyle, getTableWidth, resizeColumn: handleColumnResize, startColumnResize: handleColumnResizeStart, endColumnResize: handleColumnResizeEnd, }), [ columnWidths, getEffectiveColumnWidth, getStickyColumnStyle, getTableWidth, handleColumnResize, handleColumnResizeStart, handleColumnResizeEnd, ]); return (React.createElement(ColumnResizeContext.Provider, { value: contextValue }, children)); }; //# sourceMappingURL=ColumnResize.js.map