skip to Main Content

When a new layer is added after pressing add layer button then new layers are added for the box shadow generator. suppose I added 3 layers (Layer 1, Layer 2, Layer 3) when I delete Layer 2 after deletion the remaining Layers are Layer 1 and Layer 3 but Layer 3 gets renamed to Layer 2. I want Layer 3 name to be as it is. I know that the name are given through index so how can i change it?

import "./boxShadowGenerator.css";
import React, { useState, useRef, useEffect } from "react";

export const BoxShadowGenerator = () => {
  const [boxShadows, setBoxShadows] = useState([]);
  const [selectedLayer, setSelectedLayer] = useState(0);
  const buttonRefs = useRef([]);

  const addBoxShadow = () => {
    const newBoxShadow = {
      hOffset: 0,
      vOffset: 0,
      blurRadius: 0,
      spreadRadius: 0,
      color: "#000",
    };
    const newBoxShadows = [...boxShadows, newBoxShadow];
    setBoxShadows(newBoxShadows);
    setSelectedLayer(newBoxShadows.length - 1); // Select the latest layer
  };

  const removeBoxShadow = (index) => {
    const newBoxShadows = [...boxShadows];
    newBoxShadows.splice(index, 1);
    setBoxShadows(newBoxShadows);
    if (selectedLayer === index && newBoxShadows.length > 0) {
      setSelectedLayer(0);
    }
  };

  const copyToClipboard = () => {
    const boxShadow = boxShadows
      .map(
        ({ hOffset, vOffset, blurRadius, spreadRadius, color }) =>
          `${hOffset}px ${vOffset}px ${blurRadius}px ${spreadRadius}px ${color}`
      )
      .join(", ");
    navigator.clipboard.writeText(`box-shadow:${boxShadow};`);
  };

  useEffect(() => {
    if (buttonRefs.current[selectedLayer]) {
      buttonRefs.current[selectedLayer].focus();
    }
  }, [selectedLayer]);

  return (
    <>
      <div className="BSG-main-container">
        <div className="BSG-control-container">
          <h2>Box Shadow Generator</h2>
          <div
            className="box-preview"
            style={{
              boxShadow: boxShadows
                .map(
                  ({ hOffset, vOffset, blurRadius, spreadRadius, color }) =>
                    `${hOffset}px ${vOffset}px ${blurRadius}px ${spreadRadius}px ${color}`
                )
                .join(", "),
            }}
          ></div>

          {boxShadows.length > 0 && (
            <div>
              <h3>Layer {selectedLayer + 1}</h3>
              <div>
                <label htmlFor={`hOffset${selectedLayer}`}>
                  Horizontal offset:
                </label>
                <input
                  type="range"
                  id={`hOffset${selectedLayer}`}
                  min="-50"
                  max="50"
                  value={boxShadows[selectedLayer].hOffset}
                  onChange={(e) => {
                    const newBoxShadows = [...boxShadows];
                    newBoxShadows[selectedLayer] = {
                      ...newBoxShadows[selectedLayer],
                      hOffset: parseInt(e.target.value),
                    };
                    setBoxShadows(newBoxShadows);
                  }}
                />
              </div>
              <div>
                <label htmlFor={`vOffset${selectedLayer}`}>
                  Vertical offset:
                </label>
                <input
                  type="range"
                  id={`vOffset${selectedLayer}`}
                  min="-50"
                  max="50"
                  value={boxShadows[selectedLayer].vOffset}
                  onChange={(e) => {
                    const newBoxShadows = [...boxShadows];
                    newBoxShadows[selectedLayer] = {
                      ...newBoxShadows[selectedLayer],
                      vOffset: parseInt(e.target.value),
                    };
                    setBoxShadows(newBoxShadows);
                  }}
                />
              </div>
              <div>
                <label htmlFor={`blurRadius${selectedLayer}`}>
                  Blur radius:
                </label>
                <input
                  type="range"
                  id={`blurRadius${selectedLayer}`}
                  min="0"
                  max="50"
                  value={boxShadows[selectedLayer].blurRadius}
                  onChange={(e) => {
                    const newBoxShadows = [...boxShadows];
                    newBoxShadows[selectedLayer] = {
                      ...newBoxShadows[selectedLayer],
                      blurRadius: parseInt(e.target.value),
                    };
                    setBoxShadows(newBoxShadows);
                  }}
                />
              </div>
              <div>
                <label htmlFor={`spreadRadius${selectedLayer}`}>
                  Spread radius:
                </label>
                <input
                  type="range"
                  id={`spreadRadius${selectedLayer}`}
                  min="-50"
                  max="50"
                  value={boxShadows[selectedLayer].spreadRadius}
                  onChange={(e) => {
                    const newBoxShadows = [...boxShadows];
                    newBoxShadows[selectedLayer] = {
                      ...newBoxShadows[selectedLayer],
                      spreadRadius: parseInt(e.target.value),
                    };
                    setBoxShadows(newBoxShadows);
                  }}
                />
              </div>
              <div>
                <label htmlFor={`color${selectedLayer}`}>Color:</label>
                <input
                  type="color"
                  id={`color${selectedLayer}`}
                  value={boxShadows[selectedLayer].color}
                  onChange={(e) => {
                    const newBoxShadows = [...boxShadows];
                    newBoxShadows[selectedLayer] = {
                      ...newBoxShadows[selectedLayer],
                      color: e.target.value,
                    };
                    setBoxShadows(newBoxShadows);
                  }}
                />
              </div>
            </div>
          )}
          <div className="buttons">
            <button onClick={addBoxShadow}>Add Layer</button>
            {boxShadows.length > 0 && (
              <>
                <button onClick={() => removeBoxShadow(selectedLayer)}>
                  Remove Layer
                </button>
                <button onClick={copyToClipboard}>Copy CSS to Clipboard</button>
              </>
            )}
          </div>
        </div>
        {boxShadows.length > 0 && (
          <div className="box-shadow-list-container">
            {boxShadows.map((boxShadow, index) => (
              <button
                ref={(button) => (buttonRefs.current[index] = button)}
                key={index}
                id={index}
                className={`box-shadow-list-item ${
                  selectedLayer === index ? "selected" : ""
                }`}
                onClick={() => setSelectedLayer(index)}
              >
                Layer {index + 1}
              </button>
            ))}
          </div>
        )}
      </div>
    </>
  );
};

I want Layer 3 name to be as it is. I know that the name are given through index so how can i change it?

2

Answers


  1. Add another state variable called index.
    Add a key named id to the newBoxShadow object.

    The value of the key should be the state variable index.

    Now we need to increment the value of index every time the user clicks on add layer. Now use this index for displaying the layer name.

    This way, even if the user deletes a layer, the index and layer name won’t change.

    Code:

    import "./boxShadowGenerator.css";
    import React, { useState, useRef, useEffect } from "react";
    
    export const BoxShadowGenerator = () => {
     const [boxShadows, setBoxShadows] = useState([]);
      const [selectedLayer, setSelectedLayer] = useState(0);
      const [index, setIndex] = useState(1);
      const buttonRefs = useRef([]);
      const addBoxShadow = () => {
      
        setIndex(index + 1);
        const newBoxShadow = {
          id: index,
          hOffset: 0,
          vOffset: 0,
          blurRadius: 0,
          spreadRadius: 0,
          color: "#000",
        };
        const newBoxShadows = [...boxShadows, newBoxShadow];
        setBoxShadows(newBoxShadows);
        setSelectedLayer(newBoxShadows.length - 1); // Select the latest layer
      };
    
      const removeBoxShadow = (index) => {
        const newBoxShadows = [...boxShadows];
        newBoxShadows.splice(index, 1);
        setBoxShadows(newBoxShadows);
        if (selectedLayer === index && newBoxShadows.length > 0) {
          setSelectedLayer(0);
        }
      };
    
      const copyToClipboard = () => {
        const boxShadow = boxShadows
          .map(
            ({ hOffset, vOffset, blurRadius, spreadRadius, color }) =>
              `${hOffset}px ${vOffset}px ${blurRadius}px ${spreadRadius}px ${color}`
          )
          .join(", ");
        navigator.clipboard.writeText(`box-shadow:${boxShadow};`);
      };
    
      useEffect(() => {
        if (buttonRefs.current[selectedLayer]) {
          buttonRefs.current[selectedLayer].focus();
        }
      }, [selectedLayer]);
    
      return (
        <>
          <div className="BSG-main-container">
            <div className="BSG-control-container">
              <h2>Box Shadow Generator</h2>
              <div
                className="box-preview"
                style={{
                  boxShadow: boxShadows
                    .map(
                      ({ hOffset, vOffset, blurRadius, spreadRadius, color }) =>
                        `${hOffset}px ${vOffset}px ${blurRadius}px ${spreadRadius}px ${color}`
                    )
                    .join(", "),
                }}
              ></div>
    
              {boxShadows.length > 0 && (
                <div>
                  <h3>Layer {selectedLayer + 1}</h3>
                  <div>
                    <label htmlFor={`hOffset${selectedLayer}`}>
                      Horizontal offset:
                    </label>
                    <input
                      type="range"
                      id={`hOffset${selectedLayer}`}
                      min="-50"
                      max="50"
                      value={boxShadows[selectedLayer].hOffset}
                      onChange={(e) => {
                        const newBoxShadows = [...boxShadows];
                        newBoxShadows[selectedLayer] = {
                          ...newBoxShadows[selectedLayer],
                          hOffset: parseInt(e.target.value),
                        };
                        setBoxShadows(newBoxShadows);
                      }}
                    />
                  </div>
                  <div>
                    <label htmlFor={`vOffset${selectedLayer}`}>
                      Vertical offset:
                    </label>
                    <input
                      type="range"
                      id={`vOffset${selectedLayer}`}
                      min="-50"
                      max="50"
                      value={boxShadows[selectedLayer].vOffset}
                      onChange={(e) => {
                        const newBoxShadows = [...boxShadows];
                        newBoxShadows[selectedLayer] = {
                          ...newBoxShadows[selectedLayer],
                          vOffset: parseInt(e.target.value),
                        };
                        setBoxShadows(newBoxShadows);
                      }}
                    />
                  </div>
                  <div>
                    <label htmlFor={`blurRadius${selectedLayer}`}>
                      Blur radius:
                    </label>
                    <input
                      type="range"
                      id={`blurRadius${selectedLayer}`}
                      min="0"
                      max="50"
                      value={boxShadows[selectedLayer].blurRadius}
                      onChange={(e) => {
                        const newBoxShadows = [...boxShadows];
                        newBoxShadows[selectedLayer] = {
                          ...newBoxShadows[selectedLayer],
                          blurRadius: parseInt(e.target.value),
                        };
                        setBoxShadows(newBoxShadows);
                      }}
                    />
                  </div>
                  <div>
                    <label htmlFor={`spreadRadius${selectedLayer}`}>
                      Spread radius:
                    </label>
                    <input
                      type="range"
                      id={`spreadRadius${selectedLayer}`}
                      min="-50"
                      max="50"
                      value={boxShadows[selectedLayer].spreadRadius}
                      onChange={(e) => {
                        const newBoxShadows = [...boxShadows];
                        newBoxShadows[selectedLayer] = {
                          ...newBoxShadows[selectedLayer],
                          spreadRadius: parseInt(e.target.value),
                        };
                        setBoxShadows(newBoxShadows);
                      }}
                    />
                  </div>
                  <div>
                    <label htmlFor={`color${selectedLayer}`}>Color:</label>
                    <input
                      type="color"
                      id={`color${selectedLayer}`}
                      value={boxShadows[selectedLayer].color}
                      onChange={(e) => {
                        const newBoxShadows = [...boxShadows];
                        newBoxShadows[selectedLayer] = {
                          ...newBoxShadows[selectedLayer],
                          color: e.target.value,
                        };
                        setBoxShadows(newBoxShadows);
                      }}
                    />
                  </div>
                </div>
              )}
              <div className="buttons">
                <button onClick={addBoxShadow}>Add Layer</button>
                {boxShadows.length > 0 && (
                  <>
                    <button onClick={() => removeBoxShadow(selectedLayer)}>
                      Remove Layer
                    </button>
                    <button onClick={copyToClipboard}>Copy CSS to Clipboard</button>
                  </>
                )}
              </div>
            </div>
            {boxShadows.length > 0 && (
              <div className="box-shadow-list-container">
                {boxShadows.map((boxShadow, index) => (
                  <button
                    ref={(button) => (buttonRefs.current[index] = button)}
                    key={index}
                    id={index}
                    className={`box-shadow-list-item ${
                      selectedLayer === index ? "selected" : ""
                    }`}
                    onClick={() => setSelectedLayer(index)}
                  >
                    Layer {boxShadow.id}
                  </button>
                ))}
              </div>
            )}
          </div>
        </>
      );
    };
    
    Login or Signup to reply.
  2. Sorry, there is a lot of text and logic to understand, but i think your problem is that u are using newBoxShadows.splice(index, 1); for deletion from array. Is is correct way but thats why u are losing indexes. Try delete newBoxShadows[index]. But be careful, because delete will not decrease length of array.

    I can’t understand what u mean by "Layer 3 gets renamed to Layer 2", cause your layers didn’t have "names". But maybe these descisions will help:

    1. save in selectedLayer not index but box shadow object by itself.
    2. add in box shadow object id property. You will need an id counter for it.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search