Reputation: 3242
In my project I got a feature where the user can generate some content in a <textarea>
. I take that content and generate individual <text>
elements from that content and display it in a <svg>
so that the user can preview what they typed. Here is a Codesandbox dispaying my problem.
When the user starts typing, I'd like to add a label only once (for example Recipes
) to the preview. When the content in the textarea
is cleared, I also would like for the label to be deleted.
How can I make it so that a label or title can be generated once to display above the user generated content?
Code for Reference:
import "./styles.css";
import { useState } from "react";
export default function App() {
const [dummyText, setDummyText] = useState("");
const updateContent = (e) => {
setDummyText(e.target.value);
};
function calculateWordWidths() {
const words = dummyText.split(/\s+/);
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.style =
"font: 13pt LiberationSans, Helvetica, Arial, sans-serif; white-space: pre;";
svg.appendChild(text);
document.body.appendChild(svg);
const wordsWithComputedWidth = words.map((word) => {
text.textContent = word;
return { word, width: text.getComputedTextLength() };
});
text.textContent = "\u00A0"; // Unicode space
const spaceWidth = text.getComputedTextLength();
document.body.removeChild(svg);
return { wordsWithComputedWidth, spaceWidth };
}
let { wordsWithComputedWidth, spaceWidth } = calculateWordWidths();
const content = [[]];
let xPos = 0;
let yPos = 60;
let page = 1;
let i = 0,
len = wordsWithComputedWidth.length;
while (i < len) {
if (yPos > 97) {
content.push([]);
page++;
xPos = 0;
yPos = 16;
}
//How do I add this label only once and automatically delete it once
//the content in the text area is also deleted? Now it gets added
//everytime a new letter is typed
content[page - 1].push(
<text
x="0"
y="24"
key="1203"
style={{
font: "bold 17pt LiberationSans, Helvetica, Arial, sans-serif",
whiteSpace: "pre"
}}
>
Recipes
</text>
);
//Push new text elements to the content array
content[page - 1].push(
<text
x={xPos}
y={yPos}
key={i}
style={{
font: "13pt LiberationSans, Helvetica, Arial, sans-serif",
whiteSpace: "pre"
}}
>
{wordsWithComputedWidth[i].word}
</text>
);
xPos += wordsWithComputedWidth[i].width + spaceWidth;
if (xPos > 100) {
yPos += 16;
xPos = 0;
}
// console.log("xPos: ", xPos);
// console.log("yPos: ", yPos);
i++;
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<div className="container">
<div className="content">
<div>Content</div>
<textarea
rows="6"
cols="24"
onChange={(e) => updateContent(e)}
style={{ marginTop: "50px" }}
/>
</div>
<div className="preview">
<div>Preview</div>
<>
{content.map((resumePage, idx) => (
<svg
viewBox="0 0 595.28 100.89"
xmlns="http://www.w3.org/2000/svg"
style={{ border: "1px solid #aaa" }}
key={idx}
>
{content[idx]}
</svg>
))}
</>
</div>
</div>
</div>
);
}
Upvotes: 1
Views: 311
Reputation: 202836
You could conditionally push it into the array based on the dummyText
state being populated.
!!dummyText && content[page - 1].push(
<text
x="0"
y="24"
key="1203"
style={{
font: "bold 17pt LiberationSans, Helvetica, Arial, sans-serif",
whiteSpace: "pre"
}}
>
Recipes
</text>
);
Upvotes: 1