UNPKG

react-grid-layout

Version:

A draggable and resizable grid layout with responsive breakpoints, for React.

449 lines (444 loc) 13.5 kB
'use strict'; // src/core/calculate.ts function calcGridColWidth(positionParams) { const { margin, containerPadding, containerWidth, cols } = positionParams; return (containerWidth - margin[0] * (cols - 1) - containerPadding[0] * 2) / cols; } function calcGridItemWHPx(gridUnits, colOrRowSize, marginPx) { if (!Number.isFinite(gridUnits)) return gridUnits; return Math.round( colOrRowSize * gridUnits + Math.max(0, gridUnits - 1) * marginPx ); } function calcGridItemPosition(positionParams, x, y, w, h, dragPosition, resizePosition) { const { margin, containerPadding, rowHeight } = positionParams; const colWidth = calcGridColWidth(positionParams); let width; let height; let top; let left; if (resizePosition) { width = Math.round(resizePosition.width); height = Math.round(resizePosition.height); } else { width = calcGridItemWHPx(w, colWidth, margin[0]); height = calcGridItemWHPx(h, rowHeight, margin[1]); } if (dragPosition) { top = Math.round(dragPosition.top); left = Math.round(dragPosition.left); } else if (resizePosition) { top = Math.round(resizePosition.top); left = Math.round(resizePosition.left); } else { top = Math.round((rowHeight + margin[1]) * y + containerPadding[1]); left = Math.round((colWidth + margin[0]) * x + containerPadding[0]); } if (!dragPosition && !resizePosition) { if (Number.isFinite(w)) { const siblingLeft = Math.round( (colWidth + margin[0]) * (x + w) + containerPadding[0] ); const actualMarginRight = siblingLeft - left - width; if (actualMarginRight !== margin[0]) { width += actualMarginRight - margin[0]; } } if (Number.isFinite(h)) { const siblingTop = Math.round( (rowHeight + margin[1]) * (y + h) + containerPadding[1] ); const actualMarginBottom = siblingTop - top - height; if (actualMarginBottom !== margin[1]) { height += actualMarginBottom - margin[1]; } } } return { top, left, width, height }; } function calcXY(positionParams, top, left, w, h) { const { margin, containerPadding, cols, rowHeight, maxRows } = positionParams; const colWidth = calcGridColWidth(positionParams); let x = Math.round((left - containerPadding[0]) / (colWidth + margin[0])); let y = Math.round((top - containerPadding[1]) / (rowHeight + margin[1])); x = clamp(x, 0, cols - w); y = clamp(y, 0, maxRows - h); return { x, y }; } function calcXYRaw(positionParams, top, left) { const { margin, containerPadding, rowHeight } = positionParams; const colWidth = calcGridColWidth(positionParams); const x = Math.round((left - containerPadding[0]) / (colWidth + margin[0])); const y = Math.round((top - containerPadding[1]) / (rowHeight + margin[1])); return { x, y }; } function calcWH(positionParams, width, height, x, y, handle) { const { margin, maxRows, cols, rowHeight } = positionParams; const colWidth = calcGridColWidth(positionParams); const w = Math.round((width + margin[0]) / (colWidth + margin[0])); const h = Math.round((height + margin[1]) / (rowHeight + margin[1])); let _w = clamp(w, 0, cols - x); let _h = clamp(h, 0, maxRows - y); if (handle === "sw" || handle === "w" || handle === "nw") { _w = clamp(w, 0, cols); } if (handle === "nw" || handle === "n" || handle === "ne") { _h = clamp(h, 0, maxRows); } return { w: _w, h: _h }; } function calcWHRaw(positionParams, width, height) { const { margin, rowHeight } = positionParams; const colWidth = calcGridColWidth(positionParams); const w = Math.max( 1, Math.round((width + margin[0]) / (colWidth + margin[0])) ); const h = Math.max( 1, Math.round((height + margin[1]) / (rowHeight + margin[1])) ); return { w, h }; } function clamp(num, lowerBound, upperBound) { return Math.max(Math.min(num, upperBound), lowerBound); } function calcGridCellDimensions(config) { const { width, cols, rowHeight, margin = [10, 10], containerPadding } = config; const padding = containerPadding ?? margin; const cellWidth = (width - padding[0] * 2 - margin[0] * (cols - 1)) / cols; const cellHeight = rowHeight; return { cellWidth, cellHeight, offsetX: padding[0], offsetY: padding[1], gapX: margin[0], gapY: margin[1], cols, containerWidth: width }; } // src/core/collision.ts function collides(l1, l2) { if (l1.i === l2.i) return false; if (l1.x + l1.w <= l2.x) return false; if (l1.x >= l2.x + l2.w) return false; if (l1.y + l1.h <= l2.y) return false; if (l1.y >= l2.y + l2.h) return false; return true; } function getFirstCollision(layout, layoutItem) { for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item !== void 0 && collides(item, layoutItem)) { return item; } } return void 0; } function getAllCollisions(layout, layoutItem) { return layout.filter((l) => collides(l, layoutItem)); } // src/core/sort.ts function sortLayoutItems(layout, compactType) { if (compactType === "horizontal") { return sortLayoutItemsByColRow(layout); } if (compactType === "vertical") { return sortLayoutItemsByRowCol(layout); } if (compactType === "wrap") { return sortLayoutItemsByRowCol(layout); } return [...layout]; } function sortLayoutItemsByRowCol(layout) { return [...layout].sort((a, b) => { if (a.y !== b.y) { return a.y - b.y; } return a.x - b.x; }); } function sortLayoutItemsByColRow(layout) { return [...layout].sort((a, b) => { if (a.x !== b.x) { return a.x - b.x; } return a.y - b.y; }); } // src/core/layout.ts function bottom(layout) { let max = 0; for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item !== void 0) { const bottomY = item.y + item.h; if (bottomY > max) max = bottomY; } } return max; } function getLayoutItem(layout, id) { for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item !== void 0 && item.i === id) { return item; } } return void 0; } function getStatics(layout) { return layout.filter((l) => l.static === true); } function cloneLayoutItem(layoutItem) { return { i: layoutItem.i, x: layoutItem.x, y: layoutItem.y, w: layoutItem.w, h: layoutItem.h, minW: layoutItem.minW, maxW: layoutItem.maxW, minH: layoutItem.minH, maxH: layoutItem.maxH, moved: Boolean(layoutItem.moved), static: Boolean(layoutItem.static), isDraggable: layoutItem.isDraggable, isResizable: layoutItem.isResizable, resizeHandles: layoutItem.resizeHandles, constraints: layoutItem.constraints, isBounded: layoutItem.isBounded }; } function cloneLayout(layout) { const newLayout = new Array(layout.length); for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item !== void 0) { newLayout[i] = cloneLayoutItem(item); } } return newLayout; } function modifyLayout(layout, layoutItem) { const newLayout = new Array(layout.length); for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item !== void 0) { if (layoutItem.i === item.i) { newLayout[i] = layoutItem; } else { newLayout[i] = item; } } } return newLayout; } function withLayoutItem(layout, itemKey, cb) { let item = getLayoutItem(layout, itemKey); if (!item) { return [[...layout], null]; } item = cb(cloneLayoutItem(item)); const newLayout = modifyLayout(layout, item); return [newLayout, item]; } function correctBounds(layout, bounds) { const collidesWith = getStatics(layout); for (let i = 0; i < layout.length; i++) { const l = layout[i]; if (l === void 0) continue; if (l.x + l.w > bounds.cols) { l.x = bounds.cols - l.w; } if (l.x < 0) { l.x = 0; l.w = bounds.cols; } if (!l.static) { collidesWith.push(l); } else { while (getFirstCollision(collidesWith, l)) { l.y++; } } } return layout; } function moveElement(layout, l, x, y, isUserAction, preventCollision, compactType, cols, allowOverlap) { if (l.static && l.isDraggable !== true) { return [...layout]; } if (l.y === y && l.x === x) { return [...layout]; } const oldX = l.x; const oldY = l.y; if (typeof x === "number") l.x = x; if (typeof y === "number") l.y = y; l.moved = true; let sorted = sortLayoutItems(layout, compactType); const movingUp = compactType === "vertical" && typeof y === "number" ? oldY >= y : compactType === "horizontal" && typeof x === "number" ? oldX >= x : false; if (movingUp) { sorted = sorted.reverse(); } const collisions = getAllCollisions(sorted, l); const hasCollisions = collisions.length > 0; if (hasCollisions && allowOverlap) { return cloneLayout(layout); } if (hasCollisions && preventCollision) { l.x = oldX; l.y = oldY; l.moved = false; return layout; } let resultLayout = [...layout]; for (let i = 0; i < collisions.length; i++) { const collision = collisions[i]; if (collision === void 0) continue; if (collision.moved) continue; if (collision.static) { resultLayout = moveElementAwayFromCollision( resultLayout, collision, l, isUserAction, compactType); } else { resultLayout = moveElementAwayFromCollision( resultLayout, l, collision, isUserAction, compactType); } } return resultLayout; } function moveElementAwayFromCollision(layout, collidesWith, itemToMove, isUserAction, compactType, cols) { const compactH = compactType === "horizontal"; const compactV = compactType === "vertical"; const preventCollision = collidesWith.static; if (isUserAction) { isUserAction = false; const fakeItem = { x: compactH ? Math.max(collidesWith.x - itemToMove.w, 0) : itemToMove.x, y: compactV ? Math.max(collidesWith.y - itemToMove.h, 0) : itemToMove.y, w: itemToMove.w, h: itemToMove.h, i: "-1" }; const firstCollision = getFirstCollision(layout, fakeItem); const collisionNorth = firstCollision !== void 0 && firstCollision.y + firstCollision.h > collidesWith.y; const collisionWest = firstCollision !== void 0 && collidesWith.x + collidesWith.w > firstCollision.x; if (!firstCollision) { return moveElement( layout, itemToMove, compactH ? fakeItem.x : void 0, compactV ? fakeItem.y : void 0, isUserAction, preventCollision, compactType); } if (collisionNorth && compactV) { return moveElement( layout, itemToMove, void 0, itemToMove.y + 1, isUserAction, preventCollision, compactType); } if (collisionNorth && compactType === null) { collidesWith.y = itemToMove.y; itemToMove.y = itemToMove.y + itemToMove.h; return [...layout]; } if (collisionWest && compactH) { return moveElement( layout, collidesWith, itemToMove.x, void 0, isUserAction, preventCollision, compactType); } } const newX = compactH ? itemToMove.x + 1 : void 0; const newY = compactV ? itemToMove.y + 1 : void 0; if (newX === void 0 && newY === void 0) { return [...layout]; } return moveElement( layout, itemToMove, newX, newY, isUserAction, preventCollision, compactType); } function validateLayout(layout, contextName = "Layout") { const requiredProps = ["x", "y", "w", "h"]; if (!Array.isArray(layout)) { throw new Error(`${contextName} must be an array!`); } for (let i = 0; i < layout.length; i++) { const item = layout[i]; if (item === void 0) continue; for (const key of requiredProps) { const value = item[key]; if (typeof value !== "number" || Number.isNaN(value)) { throw new Error( `ReactGridLayout: ${contextName}[${i}].${key} must be a number! Received: ${String(value)} (${typeof value})` ); } } if (item.i !== void 0 && typeof item.i !== "string") { throw new Error( `ReactGridLayout: ${contextName}[${i}].i must be a string! Received: ${String(item.i)} (${typeof item.i})` ); } } } exports.bottom = bottom; exports.calcGridCellDimensions = calcGridCellDimensions; exports.calcGridColWidth = calcGridColWidth; exports.calcGridItemPosition = calcGridItemPosition; exports.calcGridItemWHPx = calcGridItemWHPx; exports.calcWH = calcWH; exports.calcWHRaw = calcWHRaw; exports.calcXY = calcXY; exports.calcXYRaw = calcXYRaw; exports.clamp = clamp; exports.cloneLayout = cloneLayout; exports.cloneLayoutItem = cloneLayoutItem; exports.collides = collides; exports.correctBounds = correctBounds; exports.getAllCollisions = getAllCollisions; exports.getFirstCollision = getFirstCollision; exports.getLayoutItem = getLayoutItem; exports.getStatics = getStatics; exports.modifyLayout = modifyLayout; exports.moveElement = moveElement; exports.moveElementAwayFromCollision = moveElementAwayFromCollision; exports.sortLayoutItems = sortLayoutItems; exports.sortLayoutItemsByColRow = sortLayoutItemsByColRow; exports.sortLayoutItemsByRowCol = sortLayoutItemsByRowCol; exports.validateLayout = validateLayout; exports.withLayoutItem = withLayoutItem; //# sourceMappingURL=chunk-BJFPTW5Q.js.map //# sourceMappingURL=chunk-BJFPTW5Q.js.map