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
Add another state variable called
index
.Add a key named
id
to thenewBoxShadow
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:
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. Trydelete newBoxShadows[index]
. But be careful, becausedelete
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:
selectedLayer
not index but box shadow object by itself.id
property. You will need an id counter for it.