Managing quick mouse movements while resizing an element during a mousemove event

I'm seeking to implement a resizable modal that only adjusts its height. I've written some code, but when I attempt to extend it downwards quickly, it exceeds the element boundaries without any effect. I've come across codes that work properly, such as this one, so I'm unsure what I might be overlooking.

Additionally, I have a question: Is this the correct approach to creating resizable components in React? I attempted to use states, but encountered issues with unexpected growth.

import React, { FC, useCallback, useMemo, useRef } from "react";

import { PrimitivesT } from "../Table/Table";
interface ModalProps {
  children: JSX.Element | PrimitivesT;
  display: boolean;
  width: string;
  height: string;
  x?: number;
  y?: number;
  boxShadow?: boolean;
}

const Modal: FC<ModalProps> = ({
  children,
  display = false,
  // initial height
  height = "0",
  width = "0",
  x,
  y,
  boxShadow = true,
}) => {

  const ref = useRef<HTMLDivElement>(null);
  const styles = useMemo<React.CSSProperties>(
    () => ({
      display: display ? "block" : "none",
      height: height,
      width,
      minHeight: "15px",
      position: "absolute",
      left: x,
      top: y,
      boxShadow: boxShadow ? "1px 1px 10px 5px var(--gray)" : undefined,
      borderRadius: "5px",
      backgroundColor: "white",
      zIndex: 900,
    }),
    [display, height, width, x, y, boxShadow]
  );

  const bottomStyle = useMemo<React.CSSProperties>(
    () => ({
      cursor: "row-resize",
      width: "100%",
      position: "absolute",
      bottom: "0",
      left: "0",
      height: "5px",
    }),
    []
  );

  const onMouseDown =
    useCallback((): React.MouseEventHandler<HTMLDivElement> => {
      let y = 0;
      let h = 60;

      const onMouseMove = (e: MouseEvent) => {
        const YDir = e.clientY - y;
        if (ref.current) ref.current.style.height = `${h + YDir}px`;
      };

      const onMouseUp = () => {
        try {
          ref.current?.removeEventListener("mousemove", onMouseMove);
          ref.current?.removeEventListener("mouseup", onMouseUp);
        } catch (err) {
          console.error(err);
        }
      };

      return e => {
        e.stopPropagation();
        const bounding = ref.current?.getBoundingClientRect();
        if (bounding?.height) h = bounding?.height;
        y = e.clientY;
        ref.current?.addEventListener("mousemove", onMouseMove);
        ref.current?.addEventListener("mouseup", onMouseUp);
      };
    }, []);

    return (
        <div
            ref={ref}
            style={styles}
            data-testid="Modal"
            onMouseDown={e => e.stopPropagation()}>
            {children}
            <div style={bottomStyle} onMouseDown={onMouseDown()}></div>
        </div>
  );
};

export default Modal;

Answer №1

The reason it didn't work as expected is because of the modal nature of the element. To fix this, I made a change by attaching event listeners to a different element instead of the resizable target. In this case, I utilized the document object.

  const onMouseDown =
    useCallback((): React.MouseEventHandler<HTMLDivElement> => {
      let y = 0;
      let h = 60;

      const onMouseMove = (e: MouseEvent) => {
        const YDir = e.clientY - y;
        if (ref.current) ref.current.style.height = `${h + YDir}px`;
      };

      const onMouseUp = () => {
        try {
          document.removeEventListener("mousemove", onMouseMove);
          document.removeEventListener("mouseup", onMouseUp);
        } catch (err) {
          console.error(err);
        }
      };

      return e => {
        e.stopPropagation();
        const bounding = ref.current?.getBoundingClientRect();
        if (bounding?.height) h = bounding?.height;
        y = e.clientY;
        document.addEventListener("mousemove", onMouseMove);
        document.addEventListener("mouseup", onMouseUp);
      };
    }, []);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Understanding how to sum the values of two separate dropdown selections using jQuery

Is it possible to combine and total up two different selections to display on the "Total" button below? I have added calculations to each selection. When a user selects a quantity, it should automatically sum up and display on the "Total" button, but I am ...

Unable to display the string following a space in the value attribute of an hbs file

<input type="text" class="form-control" id="exampleInputEmail2" name="productName" value={{product.productName}} > When I input 'Smart Phones' into product.produc ...

Concerns regarding the efficiency of JavaScript (Odin Project, Etch-a-Sketch) are arising

Currently, I am delving into Javascript on the Odin Project, tackling the Etch-a-Sketch exercise. This involves creating a board where you can draw with your cursor. As part of the exercise, there's a requirement to add a resize button that allows use ...

Best practices for efficiently updating state in React components

Currently, I am in the process of learning React and trying to grasp its concepts by practicing. One exercise I decided to tackle involves deleting an element from an array when a user clicks on it in the UI. Below is the code snippet that I have been work ...

Learn how to use the CSS transform-scale() function to scale text independently from its container while maintaining proper alignment

I am currently working on adjusting font sizes to match another one, but I am facing an issue where the container's size is also being affected, resulting in misalignments. I have experimented with different display types (block, inline) and even trie ...

Acquiring information through RTK-query Redux

My Redux setup looks like this: import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; const baseUrl = 'http://localhost:6969/api/coins'; const createRequest = (url) => ({ url }); export const coinApi = createApi ...

Using AJAX, FLASK, and JavaScript to send an existing array to an endpoint

Having trouble POSTing the array songFiles generated by the getTableData() function (inside an ajax request) to the /api/fileNames endpoint, and then handling it in the postFileNames() callback function. Any assistance or alternative approaches would be gr ...

I am facing an issue with my middleware setup. It functions correctly when I include it in my app.js file, but for some reason, it does not work when I add it to my server.js file

Displayed below is my App.js information: const express = require("express"); const dotenv = require("dotenv"); const movieRouter = require("./routes/movieRoutes"); const userRouter = require("./routes/userRoutes"); ...

CSS: Creative ways to switch up background hues within a grid layout

Im working on a project with a similar layout to this https://i.sstatic.net/okRL1.png I am trying to achieve a chessboard effect in my grid layout, where the last element of one row has the same background color as the first element of the next row. I h ...

In Django, I am assigning the URL as the category but encountering an error that is expecting a semicolon in JavaScript

I am currently trying to set the category as the URL in Django but I am running into an error that states '; expected.javascript' {% for category in all_categories %} <div onclick="location.href='{% url 'category' categ ...

Adjusting the transparency of the background color seamlessly without the need for an image

After creating a div element with a green background color, I am looking to progressively change the opacity of the color from top (darkest green) to bottom (lightest, white). Is there a CSS-based way to achieve this effect without resorting to using an ...

The refined search parameters do not appear on the OpenCart theme

Recently, while managing my online shop using the opencart cms, I decided to enhance the search functionality by adding filters to my products. I followed a tutorial that guided me through the process: link to tutorial After implementing two filters for s ...

Tips for accessing the selected button in notification.confirm() within a PhoneGap app

Recently, I implemented the Phonegap notification.confirm in this way: navigator.notification.confirm( 'Do you wish to proceed?', function() { console.log("Function Called"); }, 'Game Over', 'Continu ...

Issue with Vue js variable not functioning properly when the page is in operation

Trying to integrate vue.json into my asp.net mvc project by downloading vue.js from the nuget package and dragging it into the layout. After running the project, I encountered the following output: Code output https://i.sstatic.net/ZGRpN.png or this http ...

Error encountered while running npm build: Typescript issue within plotly.js/index.d.ts

Trying to implement this code snippet: import createPlotlyComponent from 'react-plotly.js/factory'; const Plot = createPlotlyComponent(window.Plotly); https://i.sstatic.net/2rI0a.png in my React project implemented in TypeScript. Encountered a ...

Assistance needed to identify CSS issue specifically in FireFox browser

Working on a new webpage and encountered an issue with the HTML markup: <!DOCTYPE html> <html lang="en> <head> <meta charset="utf-8"> <title>TileTabs</title> <link rel="stylesheet" href="css/style.css" t ...

Trigger the react-native-side-menu to open when the button is clicked

Currently developing a react native app for iOS and utilizing the react-native-side-menu library for implementing a side menu. Looking for assistance on how to open it when a button is clicked on the screen, rather than scrolling from the left end. Any su ...

What is causing the error message "generator function required" to appear on my screen?

I recently installed the npm module called "koa-cache-control" and inserted the following code lines into my index.js file. const cacheControl = require('koa-cache-control'); After that... app.use(cacheControl({ noCache: true })); Upon sta ...

How can I reverse the names displayed in ng-repeat when I click?

When utilizing the orderby filter in angularjs, I want to be able to sort the data only when the button is clicked. If the button is not clicked, the sorting order should not be displayed. <tr ng-repeat="tools in toolsfilter | orderBy:orderByField:reve ...

Utilizing a mathematical equation stored in JSON within a JavaScript environment

I'm in the process of creating a conversion calculator and I want to save the formulas and references in JSON format. Unfortunately, I'm uncertain on how to interpret the variable as a mathematical operation. JSON var JSON = { "conversio ...