Typography in React Material-UI - reactjs

I've this textbox:
<Typography component="p" className={classes.text}>
{this.props.post.text}
</Typography>
I'd like to be able to include paragraphs but all text entered into it gets printed on one line.
The documentation suggests that paragraph is defaulted to false so I must set it to `true.
I've tried the following:
<Typography component="p" className={classes.text} paragraph="true">
I also tried:
<Typography component="p" className={classes.text} paragraph={true}>
Neither work so all my text still gets printed to one line.
How do I get the paragraphs to show?
Additional info:
As I now understand, the paragraph={true} attribute in Typography just adds a bottom-margin to the whole text. I.E. my one block of text is a paragraph. If I want another paragraph I would have to add another Typography. Something like:
<Typography component="p" className={classes.text} paragraph={true}>
{this.props.post.text}
</Typography>
<Typography component="p" className={classes.text} paragraph={true}>
{this.props.post.text2}
</Typography>
This is not exactly what I want. Perhaps what I should be aiming for is to have the return characters in my input text recognised. Is this correct and if so, how is it done?
I tried this:
<pre>
<Typography component="p" className={classes.text}>
{this.props.post.text}
</Typography>
</pre>
The tag preservers the whitespace and line breaks inside the tags as is.
This is not suitable though. If I have long line the text does not wrap at the Card width. Instead anything beyond the width of the card becomes truncated. Clearly I want it all. I want my text to wrap in the card and also for it to support new lines and paragraphs. How is this done?

A better way is to use power of css:
white-space: pre-line
"New line" character will be respected if you use this css property.
Edit: Help from Ionut-Alexandru Baltariu
<Typography id="modal-description" sx={{ whiteSpace: 'pre-line'}}>

For new paragraphs
<Typography>
{this.props.text.split("\n").map((i, key) => {
return <p key={key}>{i}</p>;
})}
</Typography>
For just new lines
<Typography>
{this.props.text.split("\n").map((i, key) => {
return <div key={key}>{i}</div>;
})}
</Typography>

I tried your answer and it worked perfectly as needed. However, the console returns a minor error
Warning: validateDOMNesting(...): <p> cannot appear as a descendant
of <p>.
I improved on your answer slightly by replacing the <p> tags in your .map() with <Typography> and wrapping it all in a <div> instead, like so:
<div className={classes.text}>
{this.props.post.text.split('\n').map((i, key) => {
return <Typography key={key} paragraph variant="body1">{i}</Typography>;
})}
</div>
(you can replace body1 with whichever variant you want!)
This seems to get rid of the warning for me and I hope works as you intended.

I've come up with this:
<Typography component="p" className={classes.text}>
{this.props.post.text.split("\n").map((i, key) => {
return <p key={key}>{i}</p>;
})}
</Typography>
If there is a better way to do this I'd be keen to hear it.

This really is a strange behavior. From what I can tell, you are doing everything correctly. p is by itself displayed as block element so it should be by default displayed the way you want it to be. But, it could be that you are overriding that in your .text css class. Try to see if there is you problem. If not, you can always use variant property variant="headline" in order to put them on new lines.

If I get this right, you could simply leverage the power of HTML and add <br />-elements, to insert line-breaks.

This worked for me:
<Typography component="pre">
{this.props.post.text}
</Typography>

Starting in Material UI V5 you can now access many CSS utilities as props. For whitespace, you can now do:
<Typography whiteSpace="pre-line">{this.props.post.text}</Typography>

Related

What is the best way to print this text with i18n?

Basically what I am trying to display is I am Python, Javascript and Flutter developer. string. But it looks this way:
With the following component in react:
<Typography gutterBottom variant="h6">
I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.
</Typography>
With HL component I basically am applying a few stylings to texts, how would I go translating that with next-translate? My best try is:
<Typography gutterBottom variant="h6">
{t("introduction2", {
langs: [
<HL>Python</HL>,
<HL>JavaScript</HL>,
<HL>Flutter</HL>,
]
})}
</Typography>
With:
{
...
"introduction2": "I am {{langs[0]}}, {{langs[1]}} and {{langs[2]}} developer.",
...
}
Also tried with:
{
...
"introduction2": "I am {{langs.0}}, {{langs.1}} and {{langs.2}} developer.",
...
}
And also tried with renderToString on HL components but it does not behave how you may expect as I use Next.JS to render the page, it messes up theme settings provided by mui.
EDIT
Solved it by using Trans component mentioned by #adrai, but the solution differed a bit so here is the last form:
import Trans from "next-translate/Trans";
...
<Typography gutterBottom variant="h6">
<Trans i18nKey="common:introduction2" components={[<HL />]}>
I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.
</Trans>
</Typography>
With:
{
...
"introduction2": "I am <0>Python</0>, <0>Javascript</0> and <0>Flutter</0> developer.",
...
}
Use the Trans Component: https://react.i18next.com/latest/trans-component
<Typography gutterBottom variant="h6">
<Trans i18nKey="myKey">I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.</Trans>
</Typography>
And in the translation string use the <1>Python</1> tagsā€¦
"myKey": "I am <1>Python</1>, <3>Javascript</3> and <5>Flutter</5> developer."

Material-UI CardContent not rendering the jump lines

I have a component that renders a Material-UI Card, it receives a string like this:
'This
is
a
test'
But it renders 'This is a test' in one single line. I tried this:
<Card>
<CardContent>
<Typography noWrap>{value}</Typography>
</CardContent>
</Card>
and
<Card>
<CardContent>
{value}
</CardContent>
</Card>
both of them renders the value in a single line, however, if I console.log(value); then it shows the message as expected on the console.
How to overcome this?
You can use white-space: pre to force the text to go to the next line on newline character:
<Typography whiteSpace="pre">

using Link from react-router-dom with button

I am using react-bootstrap Cards on my project. I have great view with that. I have horizontal search button on it. I would like to use this button for routing.
I set my settings on my app.js class. Actually, I can change route with <Link> but my search button looks bad with it. I would like to use Search button while keeping visual design.
Sorry for my explanation, It's hard to explain without any visual support. if it is not clear please leave comment and I would try to clarify with onether way.
Here is my codes;
<Card bg="dark" text="white" style={{ width: "18rem" }}>
<Card.Header>SWITCH</Card.Header>
<Card.Body>
<Card.Title>Dark Card Title</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up
the bulk of the card's content.
</Card.Text>
</Card.Body>
<Button variant="secondary">SEARCH</Button>
</Card>
I can do routing with wit this code;
<Card bg="dark" text="white" style={{ width: "18rem" }}>
<Card.Header>SWITCH</Card.Header>
<Card.Body>
<Card.Title>Dark Card Title</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up
the bulk of the card's content.
</Card.Text>
</Card.Body>
<Link to={"/route which I defined in app.js"}>
<Button variant="secondary">SEARCH</Button></Link>
</Card>
But this time, search button's size decrease. Are there any way to stretch it? Or should I change usage of <Link> ?
You can use a package called react-router-bootstrap from npm and use it. It's very simple and for your use case find the below snippet.
<Link to={"/route which I defined in app.js"}><Button]>Foo</Button></Link>
becomes
import { LinkContainer } from 'react-router-bootstrap'
<LinkContainer to={"/route which I defined in app.js"}>
<Button>Foo</Button>
</LinkContainer>
find more on react-router-bootstrap
You probably will need to do some custom css styling still. You can open up your elements browser by clicking inspect in chrome and find the class of the link, then you can overwrite that class to match your styling needs.
Also try wrapping the link with the button
<Button variant="secondary"><Link>SEARCH</Link></Button>
NOTE: Even though it's not recommended and you should normally avoid it, you might need to use !important in your css when overwriting bootstrap.
you can try,
<Button as={Link} to="/your_destination">Foo</Button>

semantic ui react reveal interact with hidden form

Using Semantic ui React's Reveal with two different Cards. The visible one and then the hidden one. But the hidden one has a form and button that I need to interact with. Is there an easy way to make the form accessible? Or is the really only way to do so find the item with JS and then remove the attribute to interact with? Please someone give me some advice. Here is my current code for the Reveal.And yes I know code is sloppy right now. It's temporary.
<Reveal animated='fade' instant key={i}>
<Reveal.Content visible>
<Card
centered={true}
key={i}
raised={true}
style={{'backgroundColor':'blue', color:'white'}}
>
<Card.Header textAlign='center' as='h1'>
{Object.keys(each).toString()}
</Card.Header>
<Card.Header textAlign='center' as='h3'>
No peeking on other players wagers!
</Card.Header>
<Card.Header as='h1'></Card.Header>
<Card.Header as='h1'></Card.Header>
<Card.Header as='h2'></Card.Header>
</Card>
</Reveal.Content>
<Reveal.Content hidden>
<Card
centered={true}
key={i}
raised={true}
>
<Card.Header textAlign='center' as='h1'>
{Object.keys(each).toString()}
</Card.Header>
<Card.Header textAlign='center' as='h3'>
Please make your wager!
</Card.Header>
<Card.Content>
<Form
as='form'
>
<Form.Field>
<Label>Place your Wager</Label>
<Input icon='money' iconPosition='right' focus placeholder='Wager' />
</Form.Field>
<Button
type='submit'
size='large'
color='blue'
>
Submit
</Button>
</Form>
</Card.Content>
</Card>
</Reveal.Content>
</Reveal>
Technically your top content in your Reveal is covering the form below. Only the opacity is changing. It's still in the DOM with a higher z-index.
There are a number of ways you could solve this.
1) When the animation ends, set a display: none on the top "visible" Reveal. That means you'd have to listen to the animation end. And when the mouse leaves you would need to add display: block back so you can see the animation. Probably more work than you need.
2) Change the z-index to a lower value when the animation ends. Same issue as above.
3) Set pointer-events: none on the top "visible" reveal. This effectively makes the user's click events pass through the transparent Reveal and hit the form below instead. This is important to know, in case you intend to use the Reveal at some point to actually block the form. <Reveal.Content visible style={{pointerEvents: 'none'}}>

How do I set multiple lines to my tooltip text for Material UI IconButton?

I want to use material UI's IconButton component with a tooltip attribute. However, my tooltip value is a long string. How do I set my string to read on multiple lines instead of just one line for the tooltip pop up text?
const longSentenceForToolTop = "this is a really long tip and I would like to set it to multiple lines so I do not have one really long line as my tip going across my view because that would be obnoxious"
<IconButton
tooltip={longSentenceForToolTop}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
Update:
My code looks like the following:
const toolTipText = (text) => (
<div style={{lineHeight: 15px, whiteSpace: pre}}>
</div>
);
<IconButton
tooltip={tipText(text)}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
Now the text is broken up on its different lines but floats over the icon and not above it. I'm trying to use CSS to position the text above the icon, and I am not succeed. Does anyone know how to manipulate the position of an element with position: relative set?
You can put any element you want inside of tooltip, not just text:
<IconButton
tooltip={<div>First Line<br />Second Line</div>}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
If you're not sure how long the tooltip will be and you want to force line breaks, you can use set the width of the div and force word wrapping (you can also force text align to the left in you don't want it centered):
<IconButton
tooltip={
<div style={{ width: 100, whiteSpace: 'normal', textAlign: 'left' }}>This is a very long tooltip</div>
}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
For a one (or two) off, here is an inline style.
Separate your info with \n and put it inside a div with the white-space property set to pre-line.
const infoItems = ["line one", "line two"]
const tip = infoItems.join('\n')
<Tooltip
title={
<div style={{ whiteSpace: 'pre-line' }}>{tip}</div>
}
>
<IconButton/>
</Tooltip>
You can create a new class like line-break and then add the css property white-space: pre-line so that \n is interpreted as a line break.
Here is a quick example:
https://codepen.io/yowakita/pen/VPNxBV
In your specific case, you can inline the whiteSpace into the style property of the IconButton.
const text = 'Hello, this is line one \n and this is line 2';
return
<IconButton
style={{whiteSpace: 'pre-line'}}
tooltip={text}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
Edit: Seems like this didn't work for you- try placing the string into a div with the inline styling and then passsing it as a node to the tooltip property of IconButton.
const text = <div style={{whiteSpace: 'pre-line'}}>{'Hello, this is line one \n and this is line 2'}</div>;
return
<IconButton
tooltip={text}
tooltipPosition="top-center">
<FontIcon
className="material-icons">
info_outline
</FontIcon>
</IconButton>
Note that the tooltip property for the IconButton in material-ui is a node type, so it can take in numbers, strings, elements or an array (or fragment) containing these types.
So instead of passing in a long string you could also pass in another component/element, such as a set of divs that split up that long string of text:
const longSentenceForToolTop =
<div>
<div>this is a really long tip and I would like to set it</div>
<div>to multiple lines so I do not have one really long</div>
<div>line as my tip going across my view because that would</div>
<div>be obnoxious</div>
</div>

Resources