react-grid-layout
Version:
A draggable and resizable grid layout with responsive breakpoints, for React.
568 lines (562 loc) • 16.1 kB
JavaScript
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