sravis
sravis

Reputation: 3680

React grid layout custom resize handle is not working

According to React-Grid-Layout doc

resizeHandle?: ReactElement<any> | ((resizeHandleAxis: ResizeHandleAxis, ref: ReactRef<HTMLElement>) => ReactElement<any>)

can be used to implement custom resize handle for the grid items.

In my case this is not working. It's not even throwing any errors.

Code: https://codesandbox.io/s/react-playground-forked-jwfn3?file=/index.js

Note: If I remove resizeHandle={<BottomRightHandle />} grid items will get default resize handler, Which is working fine.

CustomResizeHandle.js

import React from "react";

const SouthEastArrow = () => (
  <svg
    width="20px"
    height="20px"
    version="1.1"
    viewBox="0 0 100 100"
    xmlns="http://www.w3.org/2000/svg"
  >
    <path d="m70.129 67.086l1.75-36.367c-0.035156-2.6523-2.9414-3.6523-4.8164-1.7773l-8.4531 8.4531-17.578-17.574c-2.3438-2.3438-5.7188-1.5625-8.0586 0.78125l-13.078 13.078c-2.3438 2.3438-2.4141 5.0117-0.074219 7.3516l17.574 17.574-8.4531 8.4531c-1.875 1.875-0.83594 4.8203 1.8164 4.8555l36.258-1.8594c1.6836 0.019531 3.1328-1.2812 3.1133-2.9688z" />
  </svg>
);

const CustomHandle = (props) => (
  <div
    style={{
      background: "#fff",
      borderRadius: "2px",
      border: "1px solid #ddd",
      position: "absolute",
      bottom: 0,
      right: 0,
      padding: 0,
      cursor: "se-resize"
    }}
    {...props}
  />
);

const BottomRightHandle = () => (
  <CustomHandle>
    <SouthEastArrow />
  </CustomHandle>
);

export default BottomRightHandle;

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Grid, Row, Col } from "react-flexbox-grid";

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

import "../../node_modules/react-grid-layout/css/styles.css";
import "../../node_modules/react-resizable/css/styles.css";

import BottomRightHandle from "./CustomResizeHandle";

const ResponsiveGridLayout = WidthProvider(Responsive);

const Layout = (props) => {
  const [items, setItems] = React.useState([
    { i: "a", x: 0, y: 0, w: 2, h: 1 },
    { i: "b", x: 2, y: 0, w: 2, h: 1 }
  ]);

  return (
    <ResponsiveGridLayout
      className="layout"
      layouts={{ lg: items }}
      breakpoints={{ lg: 1200, md: 996, sm: 768 }}
      cols={{ lg: 12, md: 10, sm: 6 }}
      resizeHandles={["se"]}
      resizeHandle={<BottomRightHandle />}
    >
      {items.map((item) => {
        return (
          <div
            key={item.i}
            style={{ backgroundColor: "#ccc" }}
            data-grid={{ x: item.x, y: item.y }}
          >
            {item.i}
          </div>
        );
      })}
    </ResponsiveGridLayout>
  );
};

class App extends React.Component {
  render() {
    return (
      <Grid>
        <Row>
          <Col>
            <Layout />
          </Col>
        </Row>
      </Grid>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));

Upvotes: 3

Views: 12333

Answers (3)

Shamendra
Shamendra

Reputation: 336

Please try to import the below react-grid-layout css files. Then you will see the handles.

import "react-grid-layout/css/styles.css";
import "react-resizable/css/styles.css";

Upvotes: 7

pckben
pckben

Reputation: 917

According to the doc, you have to have the react-resizable-handle and react-resizable-handle-${handleAxis} in your custom handle component, and pass the handleAxis and ref in from the ReactGridLayout's resizeHandle prop.

What worked for me was:

type ResizeHandleAxis = 's' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne';

type ResizeHandleProps = {
  handleAxis: ResizeHandleAxis;
}
const MyHandle = React.forwardRef<HTMLDivElement, ResizeHandleProps>(({ handleAxis }, ref) => {
  return (
    <div ref={ref}
      className={`react-resizable-handle react-resizable-handle-${handleAxis}`}
    >
    </div>
  );
});
    <ReactGridLayout {...}
      resizeHandles={[ "n", "e", "s", "w", "ne", "se", "nw", "sw" ]}
      resizeHandle={(handleAxis: ResizeHandleAxis, ref: React.Ref<HTMLDivElement>) =>
        <MyHandle ref={ref} handleAxis={handleAxis} />
      }
    >
      { children }
    </ReactGridLayout>

Then you can do extra stuff in this new component. But you'll have to use css classes to erase the default styling and customizing the new styles

Erasing default CSS

.react-resizable-handle {
  background-image: none;
  padding: 0;
  background-color: yellow;
}
.react-grid-item > .react-resizable-handle.react-resizable-handle-n,
.react-grid-item > .react-resizable-handle.react-resizable-handle-e,
.react-grid-item > .react-resizable-handle.react-resizable-handle-s,
.react-grid-item > .react-resizable-handle.react-resizable-handle-w,
.react-grid-item > .react-resizable-handle.react-resizable-handle-ne,
.react-grid-item > .react-resizable-handle.react-resizable-handle-nw,
.react-grid-item > .react-resizable-handle.react-resizable-handle-se,
.react-grid-item > .react-resizable-handle.react-resizable-handle-sw
{
  transform: none;
  margin: 0;
}
.react-grid-item > .react-resizable-handle::after {
  border: none;
  content: none;
}

You can also use other classes instead of having to clear the default styling as per the doc, but then it's not super clear and I didn't get to it.

Upvotes: 3

alisasani
alisasani

Reputation: 2968

Well, it seems that this feature is not yet implemented in react-grid-layout although it's been described in the documentation!! And it causes lots of confusion. Any way, I found a workaround to apply customized icon for resizing. First, we need to create our customized component with an absolute position in our desired place (as you have done it by creating BottomRightHandle component). Then, pass your BottomRightHandle inside ResponsiveGridLayout component as below:

 <ResponsiveGridLayout
      className="layout"
      layouts={{ lg: items }}
      breakpoints={{ lg: 1200, md: 996, sm: 768 }}
      cols={{ lg: 12, md: 10, sm: 6 }}
      resizeHandles={["se"]}
      // resizeHandle={<BottomRightHandle />}
    >
      {items.map((item) => {
        return (
          <div
            key={item.i}
            style={{ backgroundColor: "#ccc" }}
            data-grid={{ x: item.x, y: item.y }}
          >
            {item.i}
            <BottomRightHandle />
          </div>
        );
      })}
    </ResponsiveGridLayout>

and then, create a css file in order to remove and disappear the default resize arrow by these styles:

.react-grid-item > .react-resizable-handle::after {
  border-right: 2px solid rgba(0, 0, 0, 0);
  border-bottom: 2px solid rgba(0, 0, 0, 0);
}

.react-resizable-handle {
  background: transparent;
}

Please check the sandbox here

Please keep in mind that the resizeHandles position (in this case se) should be the same as the BottomRightHandle component's absolute position.

Upvotes: 0

Related Questions