reactjsreact-grid-layout

users can drag/drop items within just columns and prevent them from being creating new rows with React-Grid-Layout library


I'm using React-Grid-Layout library (https://github.com/react-grid-layout/react-resizable) and what I want to do is allow users to have just a single row and they should be able to drag/drop items within the just columns.

Currently, when I select and drag an item, the other items move to the bellow row.

It should swap the location instead of other items going to the next row.

there is a demo at the end of the page. That's what I want to do.(https://htmldom.dev/drag-and-drop-table-column/)

Attempts

I set maxRows to 1 but this didn't work.

Also I tried to set y value to 0 if y value is not 0 in handleDragStop function.

Is there a way to do it?

Here is a code sandbox.

import React, { useState, useEffect } from "react";
import { WidthProvider, Responsive } from "react-grid-layout";

const ResponsiveGridLayout = WidthProvider(Responsive);

const MyGridLayout = () => {
  const initialLayouts = {
    lg: [
      { i: "a", x: 0, y: 0, w: 1, h: 1 },
      { i: "b", x: 1, y: 0, w: 1, h: 1 },
      { i: "c", x: 2, y: 0, w: 1, h: 1 },
      { i: "d", x: 3, y: 0, w: 1, h: 1 },
      { i: "e", x: 4, y: 0, w: 1, h: 1 }
    ]
  };

  const [layouts, setLayouts] = useState(initialLayouts);

  useEffect(() => {
    setLayouts(layouts);
    console.log("layouts - useeffect", layouts);
  }, [layouts]);

  const handleDragStop = (layout, oldItem, newItem) => {
    console.log("layout", layout);
    console.log("oldItem", oldItem);
    console.log("newItem", newItem);

    if (newItem.y !== 0) {
      newItem.y = 0;
      const newLayouts = { ...layouts };
      newLayouts.lg = layout.map((item) =>
        item.i === newItem.i ? newItem : item
      );
      setLayouts(newLayouts);
    }
  };

  return (
    <ResponsiveGridLayout
      className="layout"
      layouts={layouts}
      breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
      cols={{ lg: 12, md: 12, sm: 12, xs: 12, xxs: 12 }}
      rowHeight={30}
      margin={[10, 10]}
      containerPadding={[10, 10]}
      onDragStop={handleDragStop}
      compactType={null}
      maxRows={1}
    >
      {layouts.lg.map((item) => (
        <div
          key={item.i}
          data-grid={{ ...item, isBounded: true }}
          style={gridItemStyle}
        >
          <div style={contentStyle}>{item.i.toUpperCase()}</div>
        </div>
      ))}
    </ResponsiveGridLayout>
  );
};

const gridItemStyle = {
  height: "50px",
  background: "#ccc",
  borderRadius: "5px",
  padding: "10px",
  boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
};

const contentStyle = {
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
  height: "100%",
  color: "#333",
  fontWeight: "bold",
  fontSize: "24px"
};

export default MyGridLayout;


Solution

  • you can use the onLayoutChange function to force the elements back to the first row. https://codesandbox.io/s/staging-fog-0epx6p?file=/src/Sample.jsx