Space child components along full height of a fixed-height parent component - reactjs

I am developing an app with a page that displays an overlay over a map. I want the view on this overlay to be scaled to a percentage of screen height (30%). I want the contents of this view to be flex elements that span its entire height.
This is my current implementation:
function MyOverlay () {
return (
<Overlay isVisible={true}>
<View id='container' style={{height: '30%', alignItems: 'stretch'}}>
<Text id='title' style={{flex: 1}, styles.titleText}>Menu</Text>
<View id='options' style={{flex: 3}}>
<Button containerStyle={{borderWidth: 2, flex: 1}}>
Option 1
</Button>
<Button containerStyle={{borderWidth: 2, flex: 1}}>
Option 2
</Button>
<Button containerStyle={{borderWidth: 2, flex: 1}}>
Option 3
</Button>
</View>
</View>
</Overlay>
);
};
In this implementation, container has height=30%, which is reflected in the screenshot below. I want the title and options child components to fill the entire parent height. After reading other answers, I added alignItems: 'stretch' to container. This isn't working as intended, as seen in the screenshot.
Any idea how I could get the behavior that I want?

I recreated your example in my own markup, and abstracted away the styles for readability. Most of the styles you can ignore, but the important stuff is:
On the parent container:
display: flex;
flex-direction: column;
On the option wrapper:
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
And that's it! No need to add any flex properties to the children.
.container {
border: 1px solid black;
height: 80%;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
}
.wrapper {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
<div class="container">
<h1>Menu</h1>
<div class="wrapper">
<button>Option 1</button>
<button>Option 2</button>
<button>Option 3</button>
</div>
</div>

Related

Padding in Sass making Material UI icon disappear

I am creating an image slider in React. I'm using Material UI arrow icons as the left and right buttons.
Everything is working fine until I try and add padding.
Before adding the padding, I can see two white circles with my arrows. As soon as I add the padding, the white circles get bigger but the arrows inside disappear.
return (
<div className="container">
<div
className="slider"
style={{ transform: `translateX(-${currentSlide * 100}vw)` }}
>
<img src={images[0]} alt="" />
<img src={images[1]} alt="" />
<img src={images[2]} alt="" />
<img src={images[3]} alt="" />
</div>
<div className="arrows">
<KeyboardArrowLeftOutlinedIcon className="arrow" onClick={prevSlide} />
<KeyboardArrowRightOutlinedIcon className="arrow" onClick={nextSlide} />
</div>
</div>
)
And this is the sass file:
.container {
width: 100vw;
height: 60vh;
overflow: hidden;
position: relative;
.slider {
width: 400vw;
height: 100%;
display: flex;
transition: all 1s ease;
img {
width: 100vw;
height: 100%;
object-fit: cover;
}
}
.arrows {
position: absolute;
height: 100%;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
gap: 80%;
top: 0;
.arrow {
cursor: pointer;
background-color: white;
border-radius: 2em;
padding: 1em;
}
}
}
It seems that a possible solution could be wrap the arrow icons with div, and style the wrapper.
Minimized demo of below example on: stackblitz (without functionality, and uses plain CSS)
Example:
<div className="arrows">
<div className="arrow">
<KeyboardArrowLeftOutlinedIcon />
</div>
<div className="arrow">
<KeyboardArrowRightOutlinedIcon />
</div>
</div>
Also some changes in Sass would be needed to match it, such as:
.arrows {
position: absolute;
inset: 0;
display: flex;
justify-content: space-between;
align-items: center;
.arrow {
cursor: pointer;
background-color: white;
border-radius: 2em;
margin: 0.75em;
padding: 0.5em;
display: flex;
justify-content: center;
align-items: center;
}
}

How to add a label to a border in mui?

I would like to have a list wrapped in a border which looks and behaves the same as a textfield border:
Example textfield and list which should have both same border.
In the image, the border around the list looks similar than the one around the textfield but most notably, the label is missing. How can I add the label and how would I set up the focus listeners to get the same hover and selection behaviour?
The typescript code for the list:
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600'}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I am also open for alternative approaches. Thanks for the help.
Here is my answer using React and Mui (only for icon).
It relies on flex.
We have a main container that only draws its left, bottom and right borders.
Then we have a header container in charge of drawing the top border in two parts (before and after) and a section with an icon and title.
You can either pass an icon and a title, just a title, just an icon, or nothing at all.
borderedSection.js:
import React from "react";
import SvgIcon from "#mui/material/SvgIcon";
import styles from "./borderedSection.module.scss";
function BorderedSection({ icon, title, children }) {
return (
<div className={styles.mainContainer}>
<div className={styles.header}>
<div className={styles.headerBorderBefore}></div>
{(icon || title) && (
<div className={styles.headerTitle}>
{icon && <SvgIcon component={icon} />}
{title && <span className={styles.title}>{title}</span>}
</div>
)}
<div className={styles.headerBorderAfter}></div>
</div>
<div className={styles.childrenContainer}>{children}</div>
</div>
);
}
export default BorderedSection;
borderedSection.module.scss:
$border-color: #b2b2b2;
.mainContainer {
display: flex;
flex-direction: column;
max-width: 100%;
border-left: 1px solid $border-color;
border-bottom: 1px solid $border-color;
border-right: 1px solid $border-color;
border-radius: 5px;
margin: 1em;
.childrenContainer {
padding: 1em;
}
.header {
display: flex;
flex-direction: row;
width: 100% !important;
.headerBorderBefore {
border-top: 1px solid $border-color;
width: 1em;
border-top-left-radius: 5px;
}
.headerTitle {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
gap: 0.25em;
width: fit-content;
height: 2em;
margin: -1em 0.5em 0em 0.5em;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1em;
font-weight: 600;
}
.headerBorderAfter {
border-top: 1px solid $border-color;
width: 1em;
flex-grow: 2;
border-top-right-radius: 5px;
}
}
}
usage:
import React from "react";
import BorderedSection from "./borderedSection";
import InfoIcon from "#mui/icons-material/Info";
function Example() {
return (
<div style={{ padding: "2em" }}>
<BorderedSection icon={InfoIcon} title="Icon and title">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection title="Title only">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection icon={InfoIcon} >
<div>Icon only</div>
<div>a second child with quite a long text</div>
</BorderedSection>
<BorderedSection >
<div>No icon and no title</div>
<div>a second child with quite a long text</div>
</BorderedSection>
</div>
);
}
Here is how it looks:
I hope it helps
I now managed to hack a solution which looks the same. I do still hope though that there is a clean way to do this: result.
<FormLabel style={{marginLeft: "0.71em", marginTop: "-0.71em", paddingLeft: "0.44em", zIndex: 2, width: "4.2em", backgroundColor: "#383838", position: "absolute", fontSize: "0.75em"}}>Damage</FormLabel>
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600', "&:hover": { borderColor: 'grey.200' }}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I needed the same thing. As I was poking around I noticed that MUI accomplished this by using the fieldset tag. I created a quick and dirty component (OutlinedBox) to get this effect:
import React from "react";
import {Box, FormLabel} from "#mui/material";
const OutlinedBox = (props) => {
const {
label,
children
} = props;
return (
<Box>
<FormLabel
sx={{
marginLeft: "0.71em",
marginTop: "-0.71em",
paddingLeft: "0.44em",
paddingRight: '0.44em',
zIndex: 2,
backgroundColor: (theme) => theme.palette.background.default,
position: "absolute",
fontSize: "0.75em",
width: 'auto',
}}>{label}</FormLabel>
<Box
sx={{
position: 'relative',
borderRadius: theme => theme.shape.borderRadius + 'px',
fontSize: '0.875rem',
}}
>
<Box
sx={{
padding: (theme) => theme.spacing(1),
display: 'flex',
gap: (theme) => theme.spacing(1),
flexWrap: 'wrap',
overflow: 'auto'
}}
>
{children}
</Box>
<fieldset aria-hidden={"true"} style={{
textAlign: 'left',
position: 'absolute',
bottom: 0,
right: 0,
top: '-5px',
left: 0,
margin: 0,
padding: '0 8px',
pointerEvents: 'none',
borderRadius: 'inherit',
borderStyle: 'solid',
borderWidth: '1px',
overflow: 'hidden',
minWidth: '0%',
borderColor: 'rgba(255, 255, 255, 0.23)',
}}
>
<legend style={{
float: 'unset',
overflow: 'hidden',
display: 'block',
width: 'auto',
padding: 0,
height: '11px',
fontSize: '0.75em',
visibility: 'hidden',
maxWidth: '100%',
'-webkit-transition': 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
transition: 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
whiteSpace: 'nowrap',
}}><span>{label}</span></legend>
</fieldset>
</Box>
</Box>
);
}
export { OutlinedBox };
// Example usage: <OutlinedBox label="Test">Some content here</OutlinedBox>
I figured I'd post it here in case anyone needs the same thing and comes across this question. All the styling stuff was copied from the styles MUI was using. There may be a better way to read some of this off of the theme, so if anyone decides to use this you may want to tweak it some.

Does React Emotion support ::before/ ::after selectors?

I am trying to use React Emotion to set up a horizontal rule with text in the middle. It would look like this:
----------------------SOME TEXT----------------------------------
I found examples on StackOverflow on how to do this with CSS, but it's not working for me.
Here is my DIV that I'm using, but it's not working.
Is this possible to set up with react Emotion? What am I missing?
<div
css={{
display: 'flex',
lineHeight:'1em',
color:'gray',
'&:before, &:after': {
content:'',
display:'inline-block',
flexGrow:'1px',
marginTop:'0.5em',
backgroundColor:'gray',
height:'1px',
marginRight:'10px',
marginLeft:'10px'
}
}}
>
SOME TEXT
</div>
Your code is right about the ::before and ::after syntax,
However, when trying to replicate I found two errors:
The flexGrow shouldn't have a px unit, just 1: flexGrow:'1
The content should have double quotes content:'""'
<div
css={{
display: 'flex',
lineHeight:'1em',
color:'gray',
'&:before, &:after': {
content:'""',
display:'inline-block',
flexGrow:'1',
marginTop:'0.5em',
backgroundColor:'gray',
height:'1px',
marginRight:'10px',
marginLeft:'10px'
}
}}
>
You need pass style object in css function from emotion/css or emotion/react.
You forgot to wrap your styled object in a function from emotion.
If you use an object and not a string, then wrap content in double quotes
// First way, use css from #emotion/css, pass as object
import { css } from '#emotion/css'
<div
className={css({
display: 'flex',
lineHeight: '1em',
color: 'gray',
':before, :after': {
content: '""',
flexGrow: '1',
marginTop: '0.5em',
backgroundColor: 'gray',
height: '1px',
marginRight: '10px',
marginLeft: '10px'
}
})}
>
SOME TEXT
</div>
// Second way, use css from #emotion/css, pass as string
import { css } from '#emotion/css'
<div
className={css`
display: flex;
line-height: 1em;
color: gray;
:before, :after: {
content: '';
flex-grow: 1;
margin-top: 0.5em;
background-color: gray;
height: 1px;
margin-right: 10px;
margin-left: 10px;
}
`}
>
SOME TEXT
</div>
// Third way, use css from #emotion/react
import { css } from '#emotion/react'
<div
css={css`
display: flex;
line-height: 1em;
color: gray;
:before, :after: {
content: '';
flex-grow: 1;
margin-top: 0.5em;
background-color: gray;
height: 1px;
margin-right: 10px;
margin-left: 10px;
}
`}
>
SOME TEXT
</div>
For string interpolation passed for css function you can use it like
let highlight = css`
border: 1px solid grey;
&:after {
position: absolute;
}`;

Adjusting toolbar height for material-table

The blue marked area takes up a lot of space. How can I adjust the height of the Toolbar?
Can you show by example?
Or how can I create a css file and import it into the toolbar. I need to change the height, I couldn't change whatever I did. please can you help with this?
There is almost no method I have not tried.
In short, I want to adjust the height of the Mtabletoolbar field marked in blue.
<MaterialTable
Toolbar: props => (
<div style={{ backgroundColor: 'blue', }}>
<MTableToolbar {...props} classes={{ customizeToolbar: "15px" }} />
</div>
),
/>
`
const styles = {
customizeToolbar: {
minHeight: "100px"
}
}
`
I have been trying for 2 days, please can you help with the subject?
I need to change the style structure below. especially I have to change the min-height
.MuiToolbar-regular {
min-height: 64px;
}
`
.MuiToolbar-root {
display: flex;
position: relative;
align-items: center;
}
.MuiToolbar-regular {
min-height: 56px;
}
#media (min-width:0px) and (orientation: landscape) {
.MuiToolbar-regular {
min-height: 48px;
}
}
#media (min-width:600px) {
.MuiToolbar-regular {
min-height: 64px;
}
}
.MuiToolbar-dense {
min-height: 48px;
}
`
Simply adjust the style of the element where blue appears,
and make the child vertical center as below:
<div
style={{
backgroundColor: "lightblue",
height: "200px",
display: "flex",
alignItems: "center"
}}
>
<MTableToolbar {...props} />
</div>

How to set image and paragraph in the middle in table row / Material UI

I made a table using material UI. I added images and paragraph in the same row. The problem is that both of them do not align in the same height.
They should be shown in the middle of row.
Current view is like below.
The height of Logo of master card and 'Master card' do not match..
Here is my code for table.
<TableRow className="tableRow">
<TableRowColumn className="tableOne">{this.props.payment=="PayPal"?
<div className="failSample"> <img src={Fail} alt="Fail" className="Fail"/></div> : <div className="checkSample"><img src={Check} alt="Check" className="Check"/></div> }</TableRowColumn>
<TableRowColumn className="tableTwo">{this.props.date}
</TableRowColumn>
<TableRowColumn className="tableThree">{this.props.payment=="Visa" ? <div><div className="visaSample"><img src={Visa} alt="Visa" className="Visa"/></div> </div>: (this.props.payment=="PayPal" ? <div className="paypalSample"><img src={Paypal} alt="Paypal" className="Master"/></div> : <div className="masterSample"> <img src={Master} alt="Master" className="Master"/></div>)}
{this.props.payment}</TableRowColumn>
<TableRowColumn className="tableFour">{this.props.narrative}</TableRowColumn>
<TableRowColumn className="tableFive">{this.props.amount}</TableRowColumn>
<TableRowColumn className="tableSix"><div className="dotmenuSample"><img src={Dotmenu} alt="Dotmenu" className="Dotmenu" onClick={this.handleTouchTap} /> </div></TableRowColumn>
CSS
.Master, .Visa, .Paypal {
height: auto;
width: 100%;
float: left;
}
.visaSample {
padding-top: 40px;
height: 20px;
width: 20px;
display: table-cell;
}
.masterSample {
padding-top: 20px;
height: 30px;
width: 30px;
}
.paypalSample {
padding-top: 20px;
height: 30px;
width: 20px;
}
Try using flexbox will solve your problem
.flex-container {
display: flex;
flex-wrap: nowrap;
align-items: center;
}
.flex-container > div {
margin: 0 10px;
text-align: center;
}
<div class="flex-container">
<div>img</div>
<div>text</div>
</div>
Try this inside your <TableRowColumn

Resources