October 27, 2024
Chicago 12, Melborne City, USA
CSS

Facing resizing issues of a nextjs component with react rnd


This is the code for my main page:

This is my Section Element:

// SectionElement.js

import { memo, useEffect } from "react";
import { Rnd } from "react-rnd";

const hexToRgba = (hex, opacity) => {
  hex = hex.replace("#", "");
  if (hex.length === 3) {
    hex = hex
      .split("")
      .map((h) => h + h)
      .join("");
  }
  const bigint = parseInt(hex, 16);
  const r = (bigint >> 16) & 255;
  const g = (bigint >> 8) & 255;
  const b = bigint & 255;
  return `rgba(${r}, ${g}, ${b}, ${opacity})`;
};

const SectionElement = ({
  element,
  updateElement,
  setSelectedElements,
  handleDrag,
  handleDragStop,
  handleResize,
  handleResizeStop,
  isEditor,
  setSelectedCanvas,
  isSelected,
  selectedElements,
  isGroupSelected,
  isSelecting,
  currentBreakpoint,
  computeCanvasHeight,
  canvasWidth,
  children,
  hoveredSectionId,
  aboveSection, 
  belowSection
}) => {
  const elementProperties = element.properties[currentBreakpoint] || {};
  const styles = elementProperties.styles || {};
  const isHovered = element.id === hoveredSectionId;

  const isHeader = element.variant === "header";
  const isFooter = element.variant === "footer";

  // Remove constraints on xPosition and width
  const xPosition = elementProperties.x !== undefined ? elementProperties.x : 0;
  const yPosition = elementProperties.y !== undefined ? elementProperties.y : 0;

  // Use elementProperties.width and elementProperties.height
  // SectionElement.js
  const sectionWidth = parseInt(styles.width) || 600;
  const sectionHeight = parseInt(styles.height) || 600;

  const onDrag = (e, d) => {
    handleDrag(element.id, d.x, d.y, sectionWidth, sectionHeight);
  };

  const onDragStopHandler = (e, d) => {
    handleDragStop(element.id, d.x, d.y, sectionWidth, sectionHeight);
  };

  const enableResizing =
    isSelected && !isGroupSelected && !isSelecting
      ? {
          top: true,
          right: true,
          bottom: true,
          left: true,
          topRight: true,
          topLeft: true,
          bottomRight: true,
          bottomLeft: true,
        }
      : false;

  const getBorderStyle = (width, color) => {
    return width > 0 ? `${width}px solid ${color}` : "none";
  };

    // Adjust background image rendering
    const backgroundImageLayer =
    !isHeader && !isFooter && styles.backgroundImage ? (
      <div
        style={{
          backgroundImage: `url(${styles.backgroundImage})`,
          backgroundSize: styles.backgroundSize || "cover",
          backgroundRepeat: styles.backgroundRepeat || "no-repeat",
          backgroundPosition: styles.backgroundPosition || "center",
          opacity:
            styles.backgroundImageOpacity !== undefined
              ? styles.backgroundImageOpacity
              : 1,
          position: "absolute",
          top: 0,
          left: 0,
          width: "100%",
          height: "100%",
          zIndex: 0,
        }}
      />
    ) : null;

    const canvasHeight = computeCanvasHeight();

    const onResize = (e, direction, ref, delta, position) => {
      let newHeight = parseInt(ref.style.height);
      let newY = position.y;
    
      if (direction.includes("bottom")) {
        // Resizing from the bottom, limit height by the section below or canvas bottom
        if (belowSection) {
          const maxHeight = belowSection.y - yPosition;
          if (newHeight > maxHeight) {
            newHeight = maxHeight;
            ref.style.height = `${newHeight}px`;
          }
        } else {
          const maxHeight = canvasHeight - yPosition;
          if (newHeight > maxHeight) {
            newHeight = maxHeight;
            ref.style.height = `${newHeight}px`;
          }
        }
      }
    
      if (direction.includes("top")) {
        // Resizing from the top, limit by section above or canvas top (opposite logic)
        let minY = aboveSection ? aboveSection.y + aboveSection.height : 0;
    
        if (newY < minY) {
          newY = minY; // Prevent dragging above the section above
        }
    
        // Adjust height based on the new top position
        newHeight = yPosition + sectionHeight - newY;
    
        if (newHeight > sectionHeight) {
          // Ensure the section doesn't shrink below the initial height
          ref.style.height = `${newHeight}px`;
        }
    
        // Update the position to the new Y
        position.y = newY;
      }
    
      handleResize(element.id, direction, ref, delta, position);
    };
    
    
  
    const onResizeStop = (e, direction, ref, delta, position) => {
      onResize(e, direction, ref, delta, position);
      handleResizeStop(element.id, direction, ref, delta, position);
    };

  

  return (
    <Rnd
      size={{
        width: sectionWidth,
        height: sectionHeight,
      }}
      position={{
        x: xPosition,
        y: yPosition,
      }}
      onDrag={onDrag}
      onDragStop={onDragStopHandler}
      onResize={onResize}
      onResizeStop={onResizeStop}
      enableResizing={enableResizing}
      disableDragging={isGroupSelected || isSelecting}
      bounds=".editor-canvas-container"
      style={{
        zIndex: isHovered ? -1 : 0,
        position: "absolute",
        pointerEvents: isGroupSelected ? "none" : "auto",
      }}
      resizeHandleStyles={
        {
          // Optional: Customize resize handle styles
        }
      }
      cancel=".section-content"
      // This tells Rnd not to drag when interacting with elements inside `.section-content`
    >
      <div
        className={`${isSelected ? "ring-2 ring-blue-500" : ""} ${
          isHovered ? "border-4 border-dashed border-green-500" : ""
        }`}
        style={{
          width: "100%",
          height: "100%",
          position: "relative",
          overflow: "visible",
          boxSizing: "border-box",
          backgroundColor: styles.backgroundColor
            ? hexToRgba(
                styles.backgroundColor,
                styles.backgroundOpacity !== undefined 
                  ? styles.backgroundOpacity
                  : 1
              )
            : "transparent",
          borderTop: getBorderStyle(
            styles.borderTopWidth,
            styles.borderTopColor
          ),
          borderRight: getBorderStyle(
            styles.borderRightWidth,
            styles.borderRightColor
          ),
          borderBottom: getBorderStyle(
            styles.borderBottomWidth,
            styles.borderBottomColor
          ),
          borderLeft: getBorderStyle(
            styles.borderLeftWidth,
            styles.borderLeftColor
          ),
          borderRadius: styles.borderRadius || "0px", // Add this line
          zIndex: isSelected ? 20 : isHovered ? 10 : 0,
        }}
        onClick={(e) => {
          e.stopPropagation();
          setSelectedElements([element.id]);
          setSelectedCanvas(false);
        }}
      >
        {/* Background Image Layer */}
        {backgroundImageLayer}

        {/* Content of the section */}
        <div
          className="section-content"
          style={{ position: "relative", zIndex: 1 }}
          onClick={(e) => {
            e.stopPropagation(); // Prevent clicks on children from selecting them
          }}
        >
          {children}
        </div>
        {isHovered && (
  <div
    style={{
      position: "absolute",
      top: 0,
      left: 0,
      width: "100%",
      height: "100%",
      backgroundColor: "rgba(0, 255, 0, 0.1)",
      zIndex: 5,
    }}
  />
)}

      </div>
    </Rnd>
  );
};

export default memo(SectionElement);

This is my EditoCanvas:

// components/EditorCanvas.js

import { useState, useRef, useEffect } from "react";
import TextElement from "./TextElement";
import ImageElement from "./ImageElement";
import ButtonElement from "./ButtonElement";
import SectionElement from "./SectionElement";
import FormElement from './FormElement'; 
import MenuElement from "./MenuElement";
import { Rnd } from "react-rnd";
import useElementInteractions from "../hooks/useElementInteractions";
import { toast } from "react-toastify";
import AnchorElement from './AnchorElement';


function hexToRGBA(hex, opacity) {
  let r = 0,
    g = 0,
    b = 0;
  if (hex.length === 4) {
    r = "0x" + hex[1] + hex[1];
    g = "0x" + hex[2] + hex[2];
    b = "0x" + hex[3] + hex[3];
  } else if (hex.length === 7) {
    r = "0x" + hex[1] + hex[2];
    g = "0x" + hex[3] + hex[4];
    b = "0x" + hex[5] + hex[6];
  }
  return `rgba(${+r},${+g},${+b},${opacity})`;
}

const EditorCanvas = ({
  elements,
  setElements,
  selectedElements,
  updateElement,
  setSelectedElements,
  setSelectedCanvas,
  canvasBackgroundColor,
  canvasBackgroundImage,
  canvasBackgroundSize,
  canvasBackgroundRepeat,
  canvasBackgroundPosition,
  canvasBackgroundOpacity,
  canvasBackgroundImageOpacity,
  pushToHistory,
  currentBreakpoint,
  canvasHeightAdjustment
}) => {
  const [isCanvasSelected, setIsCanvasSelected] = useState(false);
  const canvasContainerRef = useRef(null);

  const [selectionBox, setSelectionBox] = useState(null);
  const [isSelecting, setIsSelecting] = useState(false);
  const selectionStart = useRef(null);

  const handleParentChange = (elementId, oldParentId, newParentId) => {
    const oldParent = elements.find((el) => el.id === oldParentId);
    const newParent = elements.find((el) => el.id === newParentId);
  
    const getParentName = (parent) => {
      if (!parent) return "canvas";
      if (parent.variant === "header") return "header";
      if (parent.variant === "footer") return "footer";
      if (parent.type === "section") return "section";
      return parent.type;
    };
  
    const oldParentName = getParentName(oldParent);
    const newParentName = getParentName(newParent);
  
    if (newParentId && !oldParentId) {
      toast.success(`Element added to ${newParentName}`);
    } else if (!newParentId && oldParentId) {
      toast.success(`Element removed from ${oldParentName}`);
    } else if (newParentId !== oldParentId) {
      toast.success(`Element moved from ${oldParentName} to ${newParentName}`);
    }
  };
  

  const canvasWidths = {
    desktop: 1200,
    tablet: 800,
    mobile: 375,
  };

  // In EditorCanvas.js
  const computeCanvasHeight = () => {
    const baseHeight = 800; // Default base canvas height
    const headerHeight = elements.some(el => el.variant === "header") ? 80 : 0; // Adjust header height
    return baseHeight + canvasHeightAdjustment + headerHeight; // Adjusted height with header
  };
  

  const {
    helperLines,
    handleDrag,
    handleDragStop,
    handleResize,
    handleDragStart,
    handleResizeStop,
    groupBoundingBox,
    handleGroupDragStart,
    handleGroupDrag,
    handleGroupDragStop,
    handleGroupResizeStart,
    handleGroupResize,
    handleGroupResizeStop,
    hoveredSectionId,
    isDraggingElement,
    draggingElementId,
  } = useElementInteractions(
    elements,
    setElements,
    selectedElements,
    setSelectedElements,
    updateElement,
    pushToHistory,
    canvasContainerRef,
    currentBreakpoint,
    handleParentChange
  );

  const handleOuterContainerClick = (e) => {
    const isInsideModal = e.target.closest("[data-modal]");
    if (!canvasContainerRef.current?.contains(e.target) && !isInsideModal) {
      setSelectedElements([]);
      setSelectedCanvas(false);
    }
  };

  useEffect(() => {
    // Load all unique fonts used in elements
    const uniqueFonts = Array.from(
      new Set(elements.map((el) => el.styles?.fontFamily).filter(Boolean))
    );
    if (uniqueFonts.length > 0 && typeof window !== "undefined") {
      import("webfontloader").then((WebFont) => {
        WebFont.load({
          google: {
            families: uniqueFonts,
          },
        });
      });
    }
  }, [elements]);

  useEffect(() => {
    document.addEventListener("mousedown", handleOuterContainerClick);
    return () => {
      document.removeEventListener("mousedown", handleOuterContainerClick);
    };
  }, []);

  const handleCanvasClick = (e) => {
    e.stopPropagation();
    setSelectedCanvas(true);
    setSelectedElements([]);
  };

  const [isDraggingSelection, setIsDraggingSelection] = useState(false);
  const dragStart = useRef(null);

  useEffect(() => {
    const disableTextSelection = (e) => {
      if (isSelecting) {
        e.preventDefault();
      }
    };

    document.addEventListener("selectstart", disableTextSelection);

    return () => {
      document.removeEventListener("selectstart", disableTextSelection);
    };
  }, [isSelecting]);

  const handleMouseDown = (e) => {
    if (e.button !== 0) return;
    if (e.target !== canvasContainerRef.current) return;

    dragStart.current = { x: e.clientX, y: e.clientY };
    setIsDraggingSelection(false);

    setSelectedCanvas(true);
    setSelectedElements([]);

    document.body.style.userSelect = "none";
  };

  const handleMouseMove = (e) => {
    if (dragStart.current === null) return;

    const dx = e.clientX - dragStart.current.x;
    const dy = e.clientY - dragStart.current.y;

    if (!isDraggingSelection && (Math.abs(dx) > 5 || Math.abs(dy) > 5)) {
      setIsDraggingSelection(true);
      setIsSelecting(true);
      setSelectedCanvas(false);

      const rect = canvasContainerRef.current.getBoundingClientRect();
      const x = dragStart.current.x - rect.left;
      const y = dragStart.current.y - rect.top;
      selectionStart.current = { x, y };
      setSelectionBox({ x, y, width: 0, height: 0 });
    }

    if (isDraggingSelection) {
      e.preventDefault();
      const rect = canvasContainerRef.current.getBoundingClientRect();
      const currentX = e.clientX - rect.left;
      const currentY = e.clientY - rect.top;
      const startX = selectionStart.current.x;
      const startY = selectionStart.current.y;

      const x = Math.min(currentX, startX);
      const y = Math.min(currentY, startY);
      const width = Math.abs(currentX - startX);
      const height = Math.abs(currentY - startY);

      setSelectionBox({ x, y, width, height });
    }
  };

  const handleMouseUp = (e) => {
    if (isDraggingSelection) {
      e.preventDefault();
      setIsSelecting(false);
      setIsDraggingSelection(false);
      dragStart.current = null;

      const selectedIds = elements
        .filter((el) => {
          const breakpointProps = el.properties[currentBreakpoint] || {};
          const elX = breakpointProps.x || 0;
          const elY = breakpointProps.y || 0;
          const elWidth = parseInt(breakpointProps.styles?.width) || 0;
          const elHeight = parseInt(breakpointProps.styles?.height) || 0;

          return (
            elX < selectionBox.x + selectionBox.width &&
            elX + elWidth > selectionBox.x &&
            elY < selectionBox.y + selectionBox.height &&
            elY + elHeight > selectionBox.y
          );
        })
        .map((el) => el.id);

      if (e.shiftKey) {
        setSelectedElements([
          ...new Set([...selectedElements, ...selectedIds]),
        ]);
      } else {
        setSelectedElements(selectedIds);
      }
      setSelectionBox(null);
    } else {
      dragStart.current = null;
    }

    document.body.style.userSelect = "";
  };

  useEffect(() => {
    const handleWindowMouseMove = (e) => {
      handleMouseMove(e);
    };

    const handleWindowMouseUp = (e) => {
      handleMouseUp(e);
    };

    window.addEventListener("mousemove", handleWindowMouseMove);
    window.addEventListener("mouseup", handleWindowMouseUp);

    return () => {
      window.removeEventListener("mousemove", handleWindowMouseMove);
      window.removeEventListener("mouseup", handleWindowMouseUp);
    };
  }, [isDraggingSelection, isSelecting, selectionBox, selectedElements]);

  const canvasWidth = canvasWidths[currentBreakpoint];

  const buildElementTree = (elements) => {
    const elementsById = {};
    const rootElements = [];

    // Initialize elementsById with an empty children array
    elements.forEach((el) => {
      elementsById[el.id] = { ...el, children: [] };
    });

    // Build the tree
    elements.forEach((el) => {
      if (el.parentId) {
        const parent = elementsById[el.parentId];
        if (parent) {
          parent.children.push(elementsById[el.id]);
        } else {
          rootElements.push(elementsById[el.id]);
        }
      } else {
        rootElements.push(elementsById[el.id]);
      }
    });

    return rootElements;
  };

    // Compute positions of all sections
    const sections = elements
    .filter((el) => el.type === "section")
    .map((section) => {
      const properties = section.properties[currentBreakpoint] || {};
      const x = properties.x || 0;
      const y = properties.y || 0;
      const styles = properties.styles || {};
      const width = parseInt(styles.width) || 600;
      const height = parseInt(styles.height) || 600;
      return { id: section.id, x, y, width, height };
    });

  // Sort sections by their y position
  sections.sort((a, b) => a.y - b.y);

  // Map section IDs to their index in the sorted array
  const sectionIndexMap = {};
  sections.forEach((section, index) => {
    sectionIndexMap[section.id] = index;
  });

  const renderElement = (element) => {
    const isSelected = selectedElements.includes(element.id);

    const boundHandleResize = (e, direction, ref, delta, position) =>
      handleResize(element.id, direction, ref, delta, position);

    const boundHandleResizeStop = (e, direction, ref, delta, position) =>
      handleResizeStop(element.id, direction, ref, delta, position);

    const commonProps = {
      key: element.id,
      element: element,
      updateElement: updateElement,
      setSelectedElements: setSelectedElements,
      handleDrag: handleDrag,
      handleDragStop: handleDragStop,
      handleResize: boundHandleResize,
      handleResizeStop: boundHandleResizeStop,
      isSelected: isSelected,
      setSelectedCanvas: setSelectedCanvas,
      selectedElements: selectedElements,
      isSelecting: isSelecting, // Pass isSelecting
      isGroupSelected: groupBoundingBox !== null,
      currentBreakpoint: currentBreakpoint,
      canvasWidth: canvasWidth,
      hoveredSectionId,
      isDraggingElement,
      draggingElementId,
      handleDragStart,
      canvasContainerRef
    };

    let elementComponent;
    switch (element.type) {
      case "text":
        elementComponent = <TextElement {...commonProps} isEditor={true} />;
        break;
      case "image":
        elementComponent = <ImageElement {...commonProps} isEditor={true} />;
        break;
      case "button":
        elementComponent = <ButtonElement {...commonProps} isEditor={true} />;
        break;
      case "section":
        const index = sectionIndexMap[element.id];
        const aboveSection = index > 0 ? sections[index - 1] : null;
        const belowSection = index < sections.length - 1 ? sections[index + 1] : null;
  
        elementComponent = (
          <SectionElement
            {...commonProps}
            isEditor={true}
            computeCanvasHeight={computeCanvasHeight}
            aboveSection={aboveSection}
            belowSection={belowSection}
          >
            {element.children.map((child) => renderElement(child))}
          </SectionElement>
        );
        break;
      case 'menu':
        elementComponent = <MenuElement {...commonProps} isEditor={true} />;
        break;
      case 'form':
        elementComponent = (
          <FormElement
            {...commonProps}
            isEditor={true}
            canvasWidth={canvasWidth}
          />
        );
        break;
      case 'anchor':
        elementComponent = (
          <AnchorElement
            {...commonProps}
            handleDragStart={handleDragStart}
            canvasContainerRef={canvasContainerRef}
            canvasWidth={canvasWidth} // Pass canvasWidth here
          />
        );
        break;      
      default:
        return null;
    }

    return elementComponent;
  };

  // In the render method
  const rootElements = buildElementTree(elements);

  return (
    <div className="flex-1 bg-white relative overflow-auto p-4">
      <div
        ref={canvasContainerRef}
        className={`editor-canvas-container relative ${
          isCanvasSelected ? "outline outline-blue-500" : "outline outline-gray-300"
        } rounded-lg mx-auto`}
        onClick={handleCanvasClick}
        onMouseDown={handleMouseDown}
        style={{ 
          boxSizing: "border-box",
          backgroundColor: "transparent",
          width: `${canvasWidth}px`,
          height: `${computeCanvasHeight()}px`,
          zIndex: 10,
        }}
      >
        {/* Background Color Layer */}
        <div
          className="absolute inset-0"
          style={{
            backgroundColor: hexToRGBA(
              canvasBackgroundColor,
              canvasBackgroundOpacity
            ),
            zIndex: 0,
            pointerEvents: "none",
          }}
        ></div>

        {/* Background Image Layer */}
        {canvasBackgroundImage && (
          <div
            className="absolute inset-0"
            style={{
              backgroundImage: `url(${canvasBackgroundImage})`,
              backgroundSize: canvasBackgroundSize,
              backgroundRepeat: canvasBackgroundRepeat,
              backgroundPosition: canvasBackgroundPosition,
              opacity:
                canvasBackgroundImageOpacity !== undefined
                  ? canvasBackgroundImageOpacity
                  : 1,
              zIndex: 0,
              pointerEvents: "none",
            }}
          ></div>
        )}

        {/* Render Elements */}
        {rootElements.map((element) => renderElement(element))}

        {/* Render Helper Lines */}
        {helperLines.map((line, index) => {
          if (line.type === "spacing") {
            if (line.orientation === "vertical") {
              return (
                <div
                  key={`spacing-${index}`}
                  className="absolute flex items-center justify-center text-blue-500"
                  style={{
                    left: line.x - 1,
                    top: line.y1,
                    height: line.y2 - line.y1,
                    width: 2,
                    pointerEvents: "none",
                    zIndex: 1000,
                  }}
                >
                  <div
                    style={{
                      position: "absolute",
                      top: 0,
                      left: -5,
                      width: 10,
                      height: 1,
                      backgroundColor: "blue",
                    }}
                  />
                  <div
                    style={{
                      position: "absolute",
                      bottom: 0,
                      left: -5,
                      width: 10,
                      height: 1,
                      backgroundColor: "blue",
                    }}
                  />
                </div>
              );
            } else if (line.orientation === "horizontal") {
              return (
                <div
                  key={`spacing-${index}`}
                  className="absolute flex items-center justify-center text-blue-500"
                  style={{
                    top: line.y - 1,
                    left: line.x1,
                    width: line.x2 - line.x1,
                    height: 2,
                    pointerEvents: "none",
                    zIndex: 1000,
                  }}
                >
                  <div
                    style={{
                      position: "absolute",
                      top: -5,
                      left: 0,
                      width: 1,
                      height: 10,
                      backgroundColor: "blue",
                    }}
                  />
                  <div
                    style={{
                      position: "absolute",
                      top: -5,
                      right: 0,
                      width: 1,
                      height: 10,
                      backgroundColor: "blue",
                    }}
                  />
                </div>
              );
            }
          } else {
            // Existing alignment lines
            const lineColor = line.color || 'blue'; // default to blue
            const lineThickness = line.thickness || 1; // Use the thickness property, default to 1px
        
            const isVertical = line.orientation === "vertical";
            const halfThickness = lineThickness / 2;
        
            return (
              <div
                key={`helper-${index}`}
                className="absolute"
                style={{
                  backgroundColor: lineColor,
                  [isVertical ? "left" : "top"]: line.position - halfThickness,
                  [isVertical ? "top" : "left"]: 0,
                  [isVertical ? "width" : "height"]: `${lineThickness}px`,
                  [isVertical ? "height" : "width"]: "100%",
                  pointerEvents: "none",
                  zIndex: 1000,
                }}
              />
            );
          }
        })}

        {/* Selection Overlay */}
        {isSelecting && (
          <div
            className="absolute top-0 left-0 w-full h-full"
            style={{ zIndex: 9999 }}
          >
            {/* Render Selection Rectangle */}
            {selectionBox && (
              <div
                className="absolute border border-blue-500 bg-blue-100 opacity-50"
                style={{
                  left: selectionBox.x,
                  top: selectionBox.y,
                  width: selectionBox.width,
                  height: selectionBox.height,
                  pointerEvents: "none",
                }}
              />
            )}
          </div>
        )}

        {groupBoundingBox && (
          <Rnd
            size={{
              width: groupBoundingBox.width,
              height: groupBoundingBox.height,
            }}
            position={{ x: groupBoundingBox.x, y: groupBoundingBox.y }}
            onDragStart={handleGroupDragStart}
            onDrag={(e, d) => handleGroupDrag(e, d)}
            onDragStop={(e, d) => handleGroupDragStop(e, d)}
            onResizeStart={handleGroupResizeStart}
            onResize={(e, direction, ref, delta, position) =>
              handleGroupResize(e, direction, ref, delta, position)
            }
            onResizeStop={(e, direction, ref, delta, position) =>
              handleGroupResizeStop(e, direction, ref, delta, position)
            }
            bounds="parent"
            style={{ zIndex: 1000 }}
          >
            <div
              className="group-selection-box"
              style={{
                width: "100%",
                height: "100%",
                border: "2px dashed blue",
                backgroundColor: "rgba(0, 0, 255, 0.1)",
              }}
              onClick={(e) => {
                e.stopPropagation();
                // Do not deselect when clicking on the group selection box
              }}
            ></div>
          </Rnd>
        )}
      </div>
    </div>
  );
};

export default EditorCanvas;

When I resize a secton from up to down, it stops (as expected) when it encounters another section. However, when resizing a section from down to up, it just continues and doesn’t stop.

What can I do to get it to stop when resizing from down to up as well?

Thank you!



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video