UNPKG

react-grid-layout

Version:

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

568 lines (562 loc) 16.1 kB
import { getStatics, collides, getFirstCollision, bottom, sortLayoutItemsByRowCol, cloneLayoutItem, sortLayoutItemsByColRow, cloneLayout, correctBounds } from './chunk-AWM66AWF.mjs'; // src/core/constraints.ts function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } var gridBounds = { name: "gridBounds", constrainPosition(item, x, y, { cols, maxRows }) { return { x: clamp(x, 0, Math.max(0, cols - item.w)), y: clamp(y, 0, Math.max(0, maxRows - item.h)) }; }, constrainSize(item, w, h, handle, { cols, maxRows }) { const maxW = handle === "w" || handle === "nw" || handle === "sw" ? item.x + item.w : cols - item.x; const maxH = handle === "n" || handle === "nw" || handle === "ne" ? item.y + item.h : maxRows - item.y; return { w: clamp(w, 1, Math.max(1, maxW)), h: clamp(h, 1, Math.max(1, maxH)) }; } }; var minMaxSize = { name: "minMaxSize", constrainSize(item, w, h) { return { w: clamp(w, item.minW ?? 1, item.maxW ?? Infinity), h: clamp(h, item.minH ?? 1, item.maxH ?? Infinity) }; } }; var containerBounds = { name: "containerBounds", constrainPosition(item, x, y, { cols, maxRows, containerHeight, rowHeight, margin }) { const visibleRows = containerHeight > 0 ? Math.floor((containerHeight + margin[1]) / (rowHeight + margin[1])) : maxRows; return { x: clamp(x, 0, Math.max(0, cols - item.w)), y: clamp(y, 0, Math.max(0, visibleRows - item.h)) }; } }; var boundedX = { name: "boundedX", constrainPosition(item, x, y, { cols }) { return { x: clamp(x, 0, Math.max(0, cols - item.w)), y }; } }; var boundedY = { name: "boundedY", constrainPosition(item, x, y, { maxRows }) { return { x, y: clamp(y, 0, Math.max(0, maxRows - item.h)) }; } }; function aspectRatio(ratio) { return { name: `aspectRatio(${ratio})`, constrainSize(_item, w, _h, _handle, context) { const { cols, containerWidth, rowHeight, margin } = context; const colWidth = (containerWidth - margin[0] * (cols - 1)) / cols; const pixelWidth = colWidth * w + margin[0] * Math.max(0, w - 1); const pixelHeight = pixelWidth / ratio; const h = Math.max( 1, Math.round((pixelHeight + margin[1]) / (rowHeight + margin[1])) ); return { w, h }; } }; } function snapToGrid(stepX, stepY = stepX) { if (stepX <= 0 || stepY <= 0) { throw new Error( `snapToGrid: step values must be positive (got stepX=${stepX}, stepY=${stepY})` ); } return { name: `snapToGrid(${stepX}, ${stepY})`, constrainPosition(_item, x, y) { return { x: Math.round(x / stepX) * stepX, y: Math.round(y / stepY) * stepY }; } }; } function minSize(minW, minH) { return { name: `minSize(${minW}, ${minH})`, constrainSize(_item, w, h) { return { w: Math.max(minW, w), h: Math.max(minH, h) }; } }; } function maxSize(maxW, maxH) { return { name: `maxSize(${maxW}, ${maxH})`, constrainSize(_item, w, h) { return { w: Math.min(maxW, w), h: Math.min(maxH, h) }; } }; } var defaultConstraints = [gridBounds, minMaxSize]; function applyPositionConstraints(constraints, item, x, y, context) { let result = { x, y }; for (const constraint of constraints) { if (constraint.constrainPosition) { result = constraint.constrainPosition(item, result.x, result.y, context); } } if (item.constraints) { for (const constraint of item.constraints) { if (constraint.constrainPosition) { result = constraint.constrainPosition( item, result.x, result.y, context ); } } } return result; } function applySizeConstraints(constraints, item, w, h, handle, context) { let result = { w, h }; for (const constraint of constraints) { if (constraint.constrainSize) { result = constraint.constrainSize( item, result.w, result.h, handle, context ); } } if (item.constraints) { for (const constraint of item.constraints) { if (constraint.constrainSize) { result = constraint.constrainSize( item, result.w, result.h, handle, context ); } } } return result; } // 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); } }; var absoluteStrategy = { type: "absolute", scale: 1, calcStyle(pos) { return setTopLeft(pos); } }; 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/compactors.ts function resolveCompactionCollision(layout, item, moveToCoord, axis, hasStatics) { const sizeProp = axis === "x" ? "w" : "h"; item[axis] += 1; const itemIndex = layout.findIndex((l) => l.i === item.i); const layoutHasStatics = hasStatics ?? getStatics(layout).length > 0; for (let i = itemIndex + 1; i < layout.length; i++) { const otherItem = layout[i]; if (otherItem === void 0) continue; if (otherItem.static) continue; if (!layoutHasStatics && otherItem.y > item.y + item.h) break; if (collides(item, otherItem)) { resolveCompactionCollision( layout, otherItem, moveToCoord + item[sizeProp], axis, layoutHasStatics ); } } item[axis] = moveToCoord; } function compactItemVertical(compareWith, l, fullLayout, maxY) { l.x = Math.max(l.x, 0); l.y = Math.max(l.y, 0); 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) { resolveCompactionCollision(fullLayout, l, collision.y + collision.h, "y"); } l.y = Math.max(l.y, 0); return l; } function compactItemHorizontal(compareWith, l, cols, fullLayout) { l.x = Math.max(l.x, 0); l.y = Math.max(l.y, 0); while (l.x > 0 && !getFirstCollision(compareWith, l)) { l.x--; } let collision; while ((collision = getFirstCollision(compareWith, l)) !== void 0) { resolveCompactionCollision(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; } }; 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; } }; var noCompactor = { type: null, allowOverlap: false, compact(layout, _cols) { return cloneLayout(layout); } }; var verticalOverlapCompactor = { ...verticalCompactor, allowOverlap: true, compact(layout, _cols) { return cloneLayout(layout); } }; var horizontalOverlapCompactor = { ...horizontalCompactor, allowOverlap: true, compact(layout, _cols) { return cloneLayout(layout); } }; var noOverlapCompactor = { ...noCompactor, allowOverlap: true }; function getCompactor(compactType, allowOverlap = false, preventCollision = false) { let baseCompactor; if (allowOverlap) { if (compactType === "vertical") baseCompactor = verticalOverlapCompactor; else if (compactType === "horizontal") baseCompactor = horizontalOverlapCompactor; else baseCompactor = noOverlapCompactor; } 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, compactTypeOrCompactor) { 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 || []); const corrected = correctBounds(clonedLayout, { cols }); const compactor = typeof compactTypeOrCompactor === "object" && compactTypeOrCompactor !== null ? compactTypeOrCompactor : getCompactor(compactTypeOrCompactor); return compactor.compact(corrected, 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]; } export { absoluteStrategy, applyPositionConstraints, applySizeConstraints, aspectRatio, boundedX, boundedY, compactItemHorizontal, compactItemVertical, containerBounds, createScaledStrategy, defaultConstraints, defaultDragConfig, defaultDropConfig, defaultGridConfig, defaultPositionStrategy, defaultResizeConfig, findOrGenerateResponsiveLayout, getBreakpointFromWidth, getColsFromBreakpoint, getCompactor, getIndentationValue, gridBounds, horizontalCompactor, horizontalOverlapCompactor, maxSize, minMaxSize, minSize, noCompactor, noOverlapCompactor, perc, resizeItemInDirection, resolveCompactionCollision, setTopLeft, setTransform, snapToGrid, sortBreakpoints, transformStrategy, verticalCompactor, verticalOverlapCompactor }; //# sourceMappingURL=chunk-XYPIYYYQ.mjs.map //# sourceMappingURL=chunk-XYPIYYYQ.mjs.map