React hide textarea but writable - reactjs

I'm making text editor from bottom up.
I want to give the illusion that users are using textarea directly.
So I think that in one big <div/> put <textarea> and <p> and hide textarea and show value of <textarea> in <p>.
When user click word in <p>, Put cursor in appropriate textarea and write word
in textarea (<p> is used just to show result)
But when i give display: hidden for this, I cannot type anything in textarea.
How can i show illusion to user use textarea directly but not really.
class CodeEditor extends Component {
constructor(props) {
super(props);
this.state = {
textValue: ''
}
}
underline = () => {
let textVal = this.editor;
let Start = textVal.selectionStart;
let End = textVal.selectionEnd;
const oldState = this.state.textValue;
if (oldState.substring(Start,End) !== '') {
this.setState({textValue : oldState.substr(0,Start) + `<p style={{text-decoration-line:underline}}>` + oldState.substring(Start, End) + `</p>` + oldState.substr(End)})
}
};
render() {
const content = this.state.textValue;
return (
<div className={cx('text-editor')} onClick={() =>
this.editor.focus()}>
<textarea
className={cx('text-input')}
ref={ref => this.editor = ref}
value={this.state.textValue}
style={{display:'hidden'}}
onChange={(event) => {
this.setState({
textValue:event.target.value
});
}} />
<div className={cx('editor-buttons')}>
<button onClick={this.underline}> Underline </button>
</div>
<p dangerouslySetInnerHTML={{ __html: content }} />
</div>
)};
}
export default CodeEditor;

You could utilize contenteditable html5 feature:
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable

For you all looking for an answer for this, here's an approach you can take:
1) Textarea/input has a border, so hide it with border-style: none and hide when focus with textarea:focus, input:focus { outline: none; }.
2) Change the background color to be the same as parent component.
3) Done :)

Related

How to change style of input tag based on checkbox?

I have input form and input tag as a button.
Before I was able to make a button which changed styling according to clicking on it but now i try to make this input gray until user check the checkbox. I tried to use <Show> and when property but i cant use when on <Show> tag. Then I tried to use onChange property and it seem to not give me any errors. I just don't understand how can I change styling inside class=" and then connect it to checkbox function? My checkbox is made by using createSignal
Any ideas?
<input
onChange={functionForStyling}
name="submit"
type={"submit"}
value={"Sign up"}
class=""
/>
Assigning a class to a checkbox element is not different than assigning it to any html element.
Here is how you can assign a class to an html element conditionally.
import { createSignal, JSX } from 'solid-js';
import { render } from 'solid-js/web';
const App = () => {
const [isChecked, setIsChecked] = createSignal(true);
const toggle = () => setIsChecked(c => !c);
const handleChange: JSX.EventHandler<HTMLInputElement, Event> = (event) => {
setIsChecked(event.currentTarget.checked);
};
return (
<div>
<style>{`
input.checked {
transform: rotate(45deg);
}
input.unchecked {
transform: rotate(45deg);
}
`}</style>
<input
type='checkbox'
class={isChecked() ? 'checked' : 'unchecked'}
checked={isChecked()}
onChange={handleChange}
/>
{` `}
<button onclick={toggle}>Toggle</button>
</div>
);
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/163ffec6-1293-4702-9ef6-0425461328c3
Please keep in mind that styling a checkbox is not that straightforward. You need to use pseudo selectors etc.

Why is my SVG not appearing when passed as prop?

I've looked through some of the other, similar questions on here, but none of the solutions seem to work for me.
I have a class component that represents a cell on a grid, and for each cell, I want there to be a specific background image that is revealed with the cell is hovered. The default component looks like this:
const Home = () => {
return (
<div id="main">
<Box title='About' svg={ BG1 } />
<Box title='Work' svg={ BG2 } />
<Box title='Portfolio' svg={ BG3 } />
<Box title='Resume' svg={ BG4 } />
</div>
);
};
I want to pass SVG components as background images, but can't seem to figure it out. I've imported each background image like this:
import { ReactComponent as BG1 } from './bg1.svg';
In the Box component, I've added state to handle some of the child elements, and the title prop seems to work out well, but the svg prop doesn't seem to work for me:
class Box extends React.Component {
constructor(props) {
super(props);
this.state = {
hovered: false,
};
}
hoverOn = e => {
this.setState({ hovered: true });
};
hoverOff = e => {
this.setState({ hovered: false });
};
render() {
const { hovered } = this.state;
const style = hovered ? { transform: 'translateY(-20%)', opacity: '.05' } : {};
return(
<section onMouseEnter={this.hoverOn} onMouseLeave={this.hoverOff}>
<a>
<div className="overlay" style={ style }></div>
<div className="bg" style={{ backgroundImage: `url(${this.props.svg})` }} ></div>
<div className="innerContent">
<h2>
{this.props.title}
</h2>
</div>
</a>
</section>
);
};
};
Whenever I inspect my developmental site, I just see <div class='bg'></div>. Any suggestions?
It's not working because BG1 is being set to the SVG file contents; not a link to the SVG file. I think you can just reference the filename in url("./bg1.svg") and it will expand it at build time. However, that probably won't work when you just pass in the filename as a prop. So - you could put the SVGs into the public folder and do something like this: {process.env.PUBLIC_URL + '/img/logo.png'}. Escape hatch doc.
With Vite you can do this: import modelGLB from './static/model.glb?url' to get the URL, but I forget the create-react-app equivalent.

How add width div with React?

Add a div and a button. When you click - increase the width of the div by 3 px. Add a Reset button that allows you to reset the state to the initial width.
const three = (e) => {
let value = e.target.value;
this.setState({ three: value });
}
We need to define a state variable to toggle and based on its status we can toggle width as well, so our code would be something like this -:
Working demo -> https://stackblitz.com/edit/react-576vo5?file=index.js
In js file -:
render() {
return (
<div>
<div className={`flexible-width ${this.state.increaseWidth ? "long-width" : "short-width"}`} onClick={() => this.setState({increaseWidth: !this.state.increaseWidth})}></div>
</div>
);
}
In css file -:
.flexible-width{
background: red;
height: 50px;
}
.long-width{
width: 150px;
}
.short-width{
width: 50px;
}
For a simple width style do it like this. If you want to do extensive styling, shift to using CSS classes and changing classes at runtime.
import React from 'react';
class Component extends React.Component {
state = {
clicked: false
}
render() {
return ( <div>
<div style = {{ width: this.state.clicked ? "100px" : "103px" }>
//div content here
</div>
<button onClick = {() => this.setState({clicked: !this.state.clcked})}>
{ clicked ? "Reset" : "Increase Width"}
</button>
</div>)
}
}
export default Component;

styled component computing style but not applying it

Dear genius StackOverflowians,
I am trying to write an app where users can configure questions and answers, along with defining help text for each question. I'm writing this in typescript React - which is handy when you want to define types of answers for questions.
I want to have a button next to the question that shows/hides a styled document. The button looks and works great, but the document that is hidden/shown doesn't get the generated style class that ought to be associated with it.
Here is the functional component to display the help document:
let HelpTextBody = function(props: { helpDocument: DocumentationStore }) {
return (
<div>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};
tok comes from a custom class DocumentationStore that is pretty much a wrapper around markdown-it, a handy js library for working with md files, which I would like my users to write their helptext in (and store it that way).
So I do this (in a different module for DocumentationStore class):
toReallySimple(): MdJson[] {
let bigParsed = this.md_.parse(this.Text, null).filter(
t => return t.type == "inline" || t.type.indexOf("open") > 0
});
Later on, I style HelpTextBody with:
const StyledHelpDocument = styled(HelpTextBody)`
background-color: lightslategray;
`;
Keeping it simple now so I can just see if it's working...
I then include it in a component with the button that I export:
class HelpText extends React.Component<helpProps, helpState> {
constructor(props: helpProps) {
super(props);
this.state = {
hidden: true
};
}
swapHidden() {
this.setState({
hidden: !this.state.hidden
});
}
render() {
if (this.state.hidden) {
return (
<span>
<StyledButton
itemScope={this.state.hidden}
onClick={() => this.swapHidden()}
>
Need Help?
</StyledButton>
</span>
);
} else {
return (
<span>
<StyledButton onClick={() => this.swapHidden()}>
Hide Help
</StyledButton>
<StyledHelpDocument helpDocument={this.props.helpDocument} />
</span>
);
}
}
So I webpack it all and get stuff into the browser, and what I get back is this style tag (after clicking the button), which looks right:
<style data-styled-components="">
/* sc-component-id: sc-bdVaJa */
.sc-bdVaJa {} .gscXTZ{background:red;color:white;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}.iwtdKP{background:white;color:red;font-size:1em;margin:1em;padding:0.25em 1em;border:2px solid red;border-radius:3px;}
/* sc-component-id: sc-bwzfXH */
.sc-bwzfXH {} .hAvMqj{background-color:lightslategray;}</style>
But my html for the document is missing the reference to the class (.hAvMqj I guess?)
<span>
<button class="sc-bdVaJa iwtdKP">Hide Help</button>
<div><p>Here the text is grey</p></div>
<!-- ^This^ is the StyledHelpDocument... no class!-->
</span>
So where am I going wrong? I don't understand why it generates the style, and the component's HTML renders... but the class isn't applied to the component! What do you think?
Your styled-components class isn't being applied because you're styling a custom component, but you haven't included className as a prop. Add className as an optional prop in the component you're styling, and also be sure to apply className somewhere in the render method for that component. For your case, it should be added like so:
let HelpTextBody = function(props: { helpDocument: DocumentationStore, className: string }) {
return (
<div className={props.className}>
{props.helpDocument.toReallySimple().map(tok => {
return React.createElement(tok.tag, null, tok.content);
})}
</div>
);
};

How to create a show more/less button with ReactJS to adjust the size of a div?

I have a div with many <p> and <span> inside, is there any example of how to create a show more/less button with ReactJS to adjust the size of a div?
I have tried to install npm read more and npm truncate, but it seems not to solve my problem. Because I have to adjust the size of a div and the text in the button on click in React.
Thanks!
With React you can easily adapt the rendering of your component depending on the state. You can have a boolean in the state (isOpen for example) and toggle the value when you click on the more/less button.
After that, you have just to render X items and change the button text depending on the boolean value.
I made an exemple with datas stored inside an array, but you could easily adapt to your case.
const MAX_ITEMS = 3;
class MoreLessExample extends React.Component{
componentWillMount() {
this.state = {
isOpen: false,
};
this.items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
'Item 6',
];
}
toggle = () => {
this.setState({ isOpen: !this.state.isOpen });
}
getRenderedItems() {
if (this.state.isOpen) {
return this.items;
}
return this.items.slice(0, MAX_ITEMS);
}
render() {
return(
<div>
{this.getRenderedItems().map((item, id) => (
<div key={id}>{item}</div>
))}
<button onClick={this.toggle}>
{this.state.isOpen ? 'less' : 'more'}
</button>
</div>
);
}
}
ReactDOM.render(<MoreLessExample />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
You may want to use react-bootstrap on that. Wrap your div in Collapse component like this...
constructor(){
super();
this.state = { showText: false };
}
render(){
return(
<div>
<p>Some text here...</p>
<a onClick={() => this.setState({ showText: !this.state.showText })>See more</a>
<Collapse in={this.state.showText}>
<div>
<span>
Some more texts here...
</span>
</div>
</Collapse>
</div>
);
}
Check this out https://react-bootstrap.github.io/utilities/transitions/
Here's a Material UI answer:
import { Button, makeStyles } from "#material-ui/core";
import React, { useState } from "react";
const useStyles = makeStyles((theme) => ({
hidden: {
display: "-webkit-box",
WebkitLineClamp: 4,
overflow: "hidden",
WebkitBoxOrient: "vertical"
}
}));
function ReadMore({ children }) {
const classes = useStyles();
const [isHidden, setIsHidden] = useState(true);
return (
<>
<div className={isHidden ? classes.hidden : null}>{children}</div>
<Button size="small" onClick={() => setIsHidden(!isHidden)}>
{isHidden ? "⬇ More" : "⬆ Less"}
</Button>
</>
);
}
export default ReadMore;
And Implement it like this:
<ReadMore>
<Typography>
Hey World, what's up
</Typography>
</ReadMore>
I know this question is a bit old but I figured I would throw in my solution for a simple show more text using functional components which should help get anyone who stumbles across this going in the right direction.
const [showMore, setShowMore] = useState<boolean>(false);
const text = 'CaPay is a super application that includes 68 high qualityscreens to help you launch digital wallet application projects and speed up your design process. Designed on 2 leading platforms Sketch & Figma makes it easy to customize to create impressive projects weee I am longer show more please CaPay is a super application that includes 68 high qualityscreens to help you launch digital wallet application projects and speed up your design process. Designed on 2 leading platforms Sketch & Figma makes it easy to customize to create impressive projects weee I am longer show more please';
const getText = () => {
// For Text that is shorter than desired length
if (text.length <= 258) return text;
// If text is longer than desired length & showMore is true
if (text.length > 258 && showMore) {
return (
<>
<p>{text}</p>
<button
onClick={() => setShowMore(false)}>
Show Less
</button>
</>
);
}
// If text is longer than desired length & showMore is false
if (text.length > 258) {
return (
<>
<p>{text.slice(0, 258)}</p>
<button
onClick={() => setShowMore(true)}>
Show Full Description
</button>
</>
);
}
};
//Then just call in component
<p>{getText()}</p>

Resources