UNPKG

react-grid-layout

Version:

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

868 lines (859 loc) 24.4 kB
'use strict'; // src/core/position.ts function setTransform({ top, left, width, height }) { const translate = `translate(${left}px,${top}px)`; return { transform: translate, WebkitTransform: translate, MozTransform: translate, msTransform: translate, OTransform: translate, width: `${width}px`, height: `${height}px`, position: "absolute" }; } function setTopLeft({ top, left, width, height }) { return { top: `${top}px`, left: `${left}px`, width: `${width}px`, height: `${height}px`, position: "absolute" }; } function perc(num) { return num * 100 + "%"; } function constrainWidth(left, currentWidth, newWidth, containerWidth) { return left + newWidth > containerWidth ? currentWidth : newWidth; } function constrainHeight(top, currentHeight, newHeight) { return top < 0 ? currentHeight : newHeight; } function constrainLeft(left) { return Math.max(0, left); } function constrainTop(top) { return Math.max(0, top); } var resizeNorth = (currentSize, newSize, _containerWidth) => { const { left, height, width } = newSize; const top = currentSize.top - (height - currentSize.height); return { left, width, height: constrainHeight(top, currentSize.height, height), top: constrainTop(top) }; }; var resizeEast = (currentSize, newSize, containerWidth) => { const { top, left, height, width } = newSize; return { top, height, width: constrainWidth( currentSize.left, currentSize.width, width, containerWidth ), left: constrainLeft(left) }; }; var resizeWest = (currentSize, newSize, _containerWidth) => { const { top, height, width } = newSize; const left = currentSize.left + currentSize.width - width; if (left < 0) { return { height, width: currentSize.left + currentSize.width, top: constrainTop(top), left: 0 }; } return { height, width, top: constrainTop(top), left }; }; var resizeSouth = (currentSize, newSize, _containerWidth) => { const { top, left, height, width } = newSize; return { width, left, height: constrainHeight(top, currentSize.height, height), top: constrainTop(top) }; }; var resizeNorthEast = (currentSize, newSize, containerWidth) => resizeNorth( currentSize, resizeEast(currentSize, newSize, containerWidth)); var resizeNorthWest = (currentSize, newSize, containerWidth) => resizeNorth( currentSize, resizeWest(currentSize, newSize)); var resizeSouthEast = (currentSize, newSize, containerWidth) => resizeSouth( currentSize, resizeEast(currentSize, newSize, containerWidth)); var resizeSouthWest = (currentSize, newSize, containerWidth) => resizeSouth( currentSize, resizeWest(currentSize, newSize)); var resizeHandlerMap = { n: resizeNorth, ne: resizeNorthEast, e: resizeEast, se: resizeSouthEast, s: resizeSouth, sw: resizeSouthWest, w: resizeWest, nw: resizeNorthWest }; function resizeItemInDirection(direction, currentSize, newSize, containerWidth) { const handler = resizeHandlerMap[direction]; if (!handler) { return newSize; } return handler(currentSize, { ...currentSize, ...newSize }, containerWidth); } var transformStrategy = { type: "transform", scale: 1, calcStyle(pos) { return setTransform(pos); }, calcDragPosition(clientX, clientY, offsetX, offsetY) { return { left: clientX - offsetX, top: clientY - offsetY }; } }; var absoluteStrategy = { type: "absolute", scale: 1, calcStyle(pos) { return setTopLeft(pos); }, calcDragPosition(clientX, clientY, offsetX, offsetY) { return { left: clientX - offsetX, top: clientY - offsetY }; } }; function createScaledStrategy(scale) { return { type: "transform", scale, calcStyle(pos) { return setTransform(pos); }, calcDragPosition(clientX, clientY, offsetX, offsetY) { return { left: (clientX - offsetX) / scale, top: (clientY - offsetY) / scale }; } }; } var defaultPositionStrategy = transformStrategy; // src/core/types.ts var defaultGridConfig = { cols: 12, rowHeight: 150, margin: [10, 10], containerPadding: null, maxRows: Infinity }; var defaultDragConfig = { enabled: true, bounded: false, threshold: 3 }; var defaultResizeConfig = { enabled: true, handles: ["se"] }; var defaultDropConfig = { enabled: false, defaultItem: { w: 1, h: 1 } }; // 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); } 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, 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})` ); } } } // src/core/compact-compat.ts function getStatics2(layout) { return layout.filter((l) => l.static); } var heightWidth = { x: "w", y: "h" }; function resolveCompactionCollision(layout, item, moveToCoord, axis) { const sizeProp = heightWidth[axis]; item[axis] += 1; const itemIndex = layout.findIndex((l) => l.i === item.i); for (let i = itemIndex + 1; i < layout.length; i++) { const otherItem = layout[i]; if (otherItem === void 0) continue; if (otherItem.static) continue; if (otherItem.y > item.y + item.h) break; if (collides(item, otherItem)) { resolveCompactionCollision( layout, otherItem, moveToCoord + item[sizeProp], axis ); } } item[axis] = moveToCoord; } function compactItemInternal(compareWith, l, compactType, cols, fullLayout, allowOverlap, b) { const compactV = compactType === "vertical"; const compactH = compactType === "horizontal"; if (compactV) { if (typeof b === "number") { l.y = Math.min(b, l.y); } else { l.y = Math.min(bottom(compareWith), l.y); } while (l.y > 0 && !getFirstCollision(compareWith, l)) { l.y--; } } else if (compactH) { while (l.x > 0 && !getFirstCollision(compareWith, l)) { l.x--; } } let collision; while ((collision = getFirstCollision(compareWith, l)) !== void 0 && !(compactType === null && allowOverlap)) { if (compactH) { resolveCompactionCollision(fullLayout, l, collision.x + collision.w, "x"); } else { resolveCompactionCollision(fullLayout, l, collision.y + collision.h, "y"); } if (compactH && l.x + l.w > cols) { l.x = cols - l.w; l.y++; while (l.x > 0 && !getFirstCollision(compareWith, l)) { l.x--; } } } l.y = Math.max(l.y, 0); l.x = Math.max(l.x, 0); return l; } function compact(layout, compactType, cols, allowOverlap) { const compareWith = getStatics2(layout); let b = bottom(compareWith); const sorted = sortLayoutItems(layout, compactType); const out = new Array(layout.length); for (let i = 0; i < sorted.length; i++) { const sortedItem = sorted[i]; if (sortedItem === void 0) continue; let l = cloneLayoutItem(sortedItem); if (!l.static) { l = compactItemInternal( compareWith, l, compactType, cols, sorted, allowOverlap, b ); b = Math.max(b, l.y + l.h); compareWith.push(l); } const originalIndex = layout.indexOf(sortedItem); out[originalIndex] = l; l.moved = false; } return out; } function compactItem(compareWith, l, compactType, cols, fullLayout, allowOverlap, maxY) { return compactItemInternal( compareWith, cloneLayoutItem(l), compactType, cols, fullLayout, allowOverlap, maxY ); } // src/core/compactors.ts function resolveCompactionCollision2(layout, item, moveToCoord, axis) { const sizeProp = axis === "x" ? "w" : "h"; item[axis] += 1; const itemIndex = layout.findIndex((l) => l.i === item.i); for (let i = itemIndex + 1; i < layout.length; i++) { const otherItem = layout[i]; if (otherItem === void 0) continue; if (otherItem.static) continue; if (otherItem.y > item.y + item.h) break; if (collides(item, otherItem)) { resolveCompactionCollision2( layout, otherItem, moveToCoord + item[sizeProp], axis ); } } item[axis] = moveToCoord; } function compactItemVertical(compareWith, l, fullLayout, maxY) { l.y = Math.min(maxY, l.y); while (l.y > 0 && !getFirstCollision(compareWith, l)) { l.y--; } let collision; while ((collision = getFirstCollision(compareWith, l)) !== void 0) { resolveCompactionCollision2(fullLayout, l, collision.y + collision.h, "y"); } l.y = Math.max(l.y, 0); return l; } function compactItemHorizontal(compareWith, l, cols, fullLayout) { while (l.x > 0 && !getFirstCollision(compareWith, l)) { l.x--; } let collision; while ((collision = getFirstCollision(compareWith, l)) !== void 0) { resolveCompactionCollision2(fullLayout, l, collision.x + collision.w, "x"); if (l.x + l.w > cols) { l.x = cols - l.w; l.y++; while (l.x > 0 && !getFirstCollision(compareWith, l)) { l.x--; } } } l.x = Math.max(l.x, 0); return l; } var verticalCompactor = { type: "vertical", allowOverlap: false, compact(layout, _cols) { const compareWith = getStatics(layout); let maxY = bottom(compareWith); const sorted = sortLayoutItemsByRowCol(layout); const out = new Array(layout.length); for (let i = 0; i < sorted.length; i++) { const sortedItem = sorted[i]; if (sortedItem === void 0) continue; let l = cloneLayoutItem(sortedItem); if (!l.static) { l = compactItemVertical(compareWith, l, sorted, maxY); maxY = Math.max(maxY, l.y + l.h); compareWith.push(l); } const originalIndex = layout.indexOf(sortedItem); out[originalIndex] = l; l.moved = false; } return out; }, onMove(layout, item, x, y, _cols) { const newLayout = cloneLayout(layout); const movedItem = newLayout.find((l) => l.i === item.i); if (movedItem) { movedItem.x = x; movedItem.y = y; movedItem.moved = true; } return newLayout; } }; var horizontalCompactor = { type: "horizontal", allowOverlap: false, compact(layout, cols) { const compareWith = getStatics(layout); const sorted = sortLayoutItemsByColRow(layout); const out = new Array(layout.length); for (let i = 0; i < sorted.length; i++) { const sortedItem = sorted[i]; if (sortedItem === void 0) continue; let l = cloneLayoutItem(sortedItem); if (!l.static) { l = compactItemHorizontal(compareWith, l, cols, sorted); compareWith.push(l); } const originalIndex = layout.indexOf(sortedItem); out[originalIndex] = l; l.moved = false; } return out; }, onMove(layout, item, x, y, _cols) { const newLayout = cloneLayout(layout); const movedItem = newLayout.find((l) => l.i === item.i); if (movedItem) { movedItem.x = x; movedItem.y = y; movedItem.moved = true; } return newLayout; } }; var noCompactor = { type: null, allowOverlap: false, compact(layout, _cols) { return cloneLayout(layout); }, onMove(layout, item, x, y, _cols) { const newLayout = cloneLayout(layout); const movedItem = newLayout.find((l) => l.i === item.i); if (movedItem) { movedItem.x = x; movedItem.y = y; movedItem.moved = true; } return newLayout; } }; var verticalOverlapCompactor = { ...verticalCompactor, allowOverlap: true, compact(layout, _cols) { return cloneLayout(layout); } }; var horizontalOverlapCompactor = { ...horizontalCompactor, allowOverlap: true, compact(layout, _cols) { return cloneLayout(layout); } }; function getCompactor(compactType, allowOverlap = false, preventCollision = false) { let baseCompactor; if (allowOverlap) { if (compactType === "vertical") baseCompactor = verticalOverlapCompactor; else if (compactType === "horizontal") baseCompactor = horizontalOverlapCompactor; else baseCompactor = noCompactor; } else { if (compactType === "vertical") baseCompactor = verticalCompactor; else if (compactType === "horizontal") baseCompactor = horizontalCompactor; else baseCompactor = noCompactor; } if (preventCollision) { return { ...baseCompactor, preventCollision }; } return baseCompactor; } // src/core/responsive.ts function sortBreakpoints(breakpoints) { const keys = Object.keys(breakpoints); return keys.sort((a, b) => breakpoints[a] - breakpoints[b]); } function getBreakpointFromWidth(breakpoints, width) { const sorted = sortBreakpoints(breakpoints); let matching = sorted[0]; if (matching === void 0) { throw new Error("No breakpoints defined"); } for (let i = 1; i < sorted.length; i++) { const breakpointName = sorted[i]; if (breakpointName === void 0) continue; const breakpointWidth = breakpoints[breakpointName]; if (width > breakpointWidth) { matching = breakpointName; } } return matching; } function getColsFromBreakpoint(breakpoint, cols) { const colCount = cols[breakpoint]; if (colCount === void 0) { throw new Error( `ResponsiveReactGridLayout: \`cols\` entry for breakpoint ${String(breakpoint)} is missing!` ); } return colCount; } function findOrGenerateResponsiveLayout(layouts, breakpoints, breakpoint, lastBreakpoint, cols, compactType) { const existingLayout = layouts[breakpoint]; if (existingLayout) { return cloneLayout(existingLayout); } let layout = layouts[lastBreakpoint]; const breakpointsSorted = sortBreakpoints(breakpoints); const breakpointsAbove = breakpointsSorted.slice( breakpointsSorted.indexOf(breakpoint) ); for (let i = 0; i < breakpointsAbove.length; i++) { const b = breakpointsAbove[i]; if (b === void 0) continue; const layoutForBreakpoint = layouts[b]; if (layoutForBreakpoint) { layout = layoutForBreakpoint; break; } } const clonedLayout = cloneLayout(layout || []); return compact(correctBounds(clonedLayout, { cols }), compactType, cols); } function getIndentationValue(value, breakpoint) { if (Array.isArray(value)) { return value; } const breakpointMap = value; const breakpointValue = breakpointMap[breakpoint]; if (breakpointValue !== void 0) { return breakpointValue; } const keys = Object.keys(breakpointMap); for (const key of keys) { const v = breakpointMap[key]; if (v !== void 0) { return v; } } return [10, 10]; } exports.absoluteStrategy = absoluteStrategy; exports.bottom = bottom; exports.cloneLayout = cloneLayout; exports.cloneLayoutItem = cloneLayoutItem; exports.collides = collides; exports.compact = compact; exports.compactItem = compactItem; exports.compactItemHorizontal = compactItemHorizontal; exports.compactItemVertical = compactItemVertical; exports.correctBounds = correctBounds; exports.createScaledStrategy = createScaledStrategy; exports.defaultDragConfig = defaultDragConfig; exports.defaultDropConfig = defaultDropConfig; exports.defaultGridConfig = defaultGridConfig; exports.defaultPositionStrategy = defaultPositionStrategy; exports.defaultResizeConfig = defaultResizeConfig; exports.findOrGenerateResponsiveLayout = findOrGenerateResponsiveLayout; exports.getAllCollisions = getAllCollisions; exports.getBreakpointFromWidth = getBreakpointFromWidth; exports.getColsFromBreakpoint = getColsFromBreakpoint; exports.getCompactor = getCompactor; exports.getFirstCollision = getFirstCollision; exports.getIndentationValue = getIndentationValue; exports.getLayoutItem = getLayoutItem; exports.getStatics = getStatics; exports.horizontalCompactor = horizontalCompactor; exports.horizontalOverlapCompactor = horizontalOverlapCompactor; exports.modifyLayout = modifyLayout; exports.moveElement = moveElement; exports.moveElementAwayFromCollision = moveElementAwayFromCollision; exports.noCompactor = noCompactor; exports.perc = perc; exports.resizeItemInDirection = resizeItemInDirection; exports.resolveCompactionCollision = resolveCompactionCollision2; exports.setTopLeft = setTopLeft; exports.setTransform = setTransform; exports.sortBreakpoints = sortBreakpoints; exports.sortLayoutItems = sortLayoutItems; exports.sortLayoutItemsByColRow = sortLayoutItemsByColRow; exports.sortLayoutItemsByRowCol = sortLayoutItemsByRowCol; exports.transformStrategy = transformStrategy; exports.validateLayout = validateLayout; exports.verticalCompactor = verticalCompactor; exports.verticalOverlapCompactor = verticalOverlapCompactor; exports.withLayoutItem = withLayoutItem; //# sourceMappingURL=chunk-3WO4SAYB.js.map //# sourceMappingURL=chunk-3WO4SAYB.js.map