How to collapse React MUI Accordion onblur - material-ui

I have a MUI Accordion in my React project, and I would like for it to collapse when the user clicks somewhere else on the page.
I would like to do this via css, as I am doing the following via css:
.focus {
/* border: 2px solid red !important; */
background-color: white !important;
}
<Accordion>
<AccordionSummary
focusVisibleClassName='focus'
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<TextField
style={{ width: 350 }}
id="entityName"
value={entity.entityName}
onChange={(event) => {
setEntity({ ...entity, entityName: event.target.value });
}}
/>
</AccordionSummary>
<AccordionDetails sx={{ borderTop: '1px dashed black', width: 400 }}>
<Typography>
Source
</Typography>
<TextField sx={{ width: 350 }}></TextField>
<Typography>
Classification
</Typography>
<TextField sx={{ width: 350 }}></TextField>
</AccordionDetails>
</Accordion>
I appreciate your assistance.
I have searched on this requirement, and not found any results.

You can implement ClickAwayListener component to detect when a click event happens outside of its child element. And to get the current state of the expended prop you have to add onChange prop to your Accordion component, and finally make use of expanded prop to set its value (true/false). Please take a look at the code below for a better understanding. also, a working example was added as a link.
Import:
import ClickAwayListener from '#mui/material/ClickAwayListener';
And inside your function:
const [open, setOpen] = useState(false);
const handleClickAway = () => {
if(open){
setOpen(false);
}
};
return (
<ClickAwayListener onClickAway={handleClickAway}>
<Accordion expanded={open} onChange={(e,expanded)=>{setOpen(expanded)}}>
<AccordionSummary
focusVisibleClassName='focus'
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<TextField
style={{ width: 350 }}
id="entityName"
value={entity.entityName}
onChange={(event) => {
setEntity({ ...entity, entityName: event.target.value });
}}
/>
</AccordionSummary>
<AccordionDetails sx={{ borderTop: '1px dashed black', width: 400 }}>
<Typography>
Source
</Typography>
<TextField sx={{ width: 350 }}></TextField>
<Typography>
Classification
</Typography>
<TextField sx={{ width: 350 }}></TextField>
</AccordionDetails>
</Accordion>
</ClickAwayListener>
);
https://codesandbox.io/s/mui-accordion-clickoutside-kmg1eb?file=/demo.js

Related

Framer Motion ReOrder behaviour not reordering as expected

I am currently trying to implemented a draggable re-orderable list with Framer Motion. I am trying to reproduce the following behaviour:
https://codesandbox.io/s/framer-motion-5-drag-to-reorder-lists-uonye?from-embed=&file=/src/Icon.tsx:49-54
I have an ingredientList that contains the create_index of the each of the ingredients created in my Formik form, which are accessible as values.ingredients.
The main issue I am having is that the list items are not behaving smoothly as they do in the code example and I'm not sure what I am doing wrong
This is my parent component in which I set the ingredientList
const IngredientTab = ({values}: any) => {
const [ingredientList, setIngredientList] = useState(values.ingredients.map((ingredient) => ingredient.create_index))
return (
<div css={IngredientTabStyles}>
<FieldArray name="ingredients">
{({ insert, remove, push }) => (
<div>
<Reorder.Group axis="y" values={ingredientList} onReorder={setIngredientList}>
<AnimatePresence>
{ingredientList.map((ingredientUniqueValue, index) => {
return (
<Ingredient
key={index}
index={index}
uniqueValue={ingredientUniqueValue}
ingredients={values.ingredients}
order={`${ingredientList.indexOf(ingredientUniqueValue) + 1}`}
/>
)
})}
</AnimatePresence>
</Reorder.Group>
<button
type="button"
className="add-ingredients"
onClick={() => {
setIngredientList([...ingredientList, values.ingredients.length])
push({ name: '', additional_info: '', quantity: '', unit_id: '', create_index: values.ingredients.length})
}}
>
Add Ingredient
</button>
</div>
)}
</FieldArray>
</div>
)
}
export default IngredientTab
const IngredientTabStyles = css`
.ingredient-fields {
margin-bottom: 2rem;
background-color: white;
}
`
And this is the Item component:
const Ingredient = ({ uniqueValue, ingredients, order, ingredient}: any) => {
const y = useMotionValue(0);
const boxShadow = useRaisedShadow(y);
const ingredientIndex = ingredients.findIndex(ingredient => ingredient.create_index==uniqueValue)
return (
<Reorder.Item
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
key={uniqueValue}
value={uniqueValue}
style={{boxShadow,y}}
>
{ingredient}
<div className="ingredient-fields" css={IngredientStyles}>
<div className="order">
<h6>{order}</h6>
</div>
<div className="ingredient-name">
<Field
name={`ingredients.${ingredientIndex}.name`}
type='text'
placeholder="Ingredient"
/>
<Field
name={`ingredients.${ingredientIndex}.additional_info`}
type='text'
placeholder="Description"
/>
</div>
<Field
name={`ingredients.${ingredientIndex}.quantity`}
type='number'
placeholder="Quantity"
/>
</div>
</Reorder.Item>
)
}
export default Ingredient
const IngredientStyles = css`
display: flex;
margin-bottom: 2rem;
.order {
display: flex;
align-items: center;
background-color: ${theme.components.grey};
padding: 1rem 2rem;
margin-right: 2rem;
border-radius: 0.4rem;
}
.ingredient-name {
display: flex;
}
input {
padding-bottom: 1rem;
border: none;
border-bottom: 1px solid ${theme.colors.lightGrey};
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
}
`
I tried to take screenshots of the behaviour that I currently have. If I try to drag the 'bonjour' to the first position, the 1st item 'hello' does not move downwards. Instead what happens onReorder, what you see in the second picture, the bonjour and hello abruptly switch and it looks as though I am dragging the 'hello' item

mui Grid in Box - horizontal and vertical spacing

I want to make a grid of many cards with the same horizontal and vertical spacing. See below my code. I want to keep the different Box elements because other codes will be added. I tried to play with the flexbox options of the mui Box but nothing worked.
import * as React from 'react';
import Box from '#mui/material/Box';
import Paper from '#mui/material/Paper';
import Grid from '#mui/material/Grid';
const list_label = [
'T1 ',
'T2 ',
'T3 ',
'T4 ',
'T5 ',
'T6 ',
'T7 ',
'T8 ',
'T9 ',
'T10 ',
'T11 ',
'T12 ',
'T13 ',
];
export default function TestBasicGrid() {
return (
<Box sx={{
display: 'flex',
flexDirection: 'row',
height:800,
width:'100%',
flexGrow: 1,
alignContent:'flex-start'
}}>
<Box sx={{
display: 'flex',
flexDirection: 'row',
height:'100%',
width:'100%',
alignContent:'flex-start'
}}>
<Box sx={{
display: 'flex',
flexDirection: 'column',
border:'3px solid black',
width:'100%',
height:'100%',
alignContent:'flex-start'
}}>
<Box
sx={{ height: '100%',
display: 'flex',
flexDirection: 'column',
border:'3px solid green',
padding: 2,
paddingTop:10,
paddingLeft:10,
paddingBottom:10,
alignContent:'flex-start'
}}>
<Grid container
rowSpacing={2}
columnSpacing={2}
justifyContent='flex-start'
alignItems='flex-start'
sx={{ flexGrow: 1,
overflowY: '"scroll',
}}>
{list_label.map((label) => (
<Grid item key={label}>
<Paper sx={{
height: 120,
width: 150,
backgroundColor: 'red'}}>{label}</Paper>
</Grid>
))}
</Grid>
</Box>
</Box>
</Box>
</Box>
);
}
The result show different horizontal and vertical spacing.
result
Remove the flexGrow: 1 from the <Grid> conatiner
<Grid
container
rowSpacing={2}
columnSpacing={2}
justifyContent='flex-start'
alignItems='flex-start'
// --- remove this flexGrow --- //
sx={{ flexGrow: 1, overflowY: 'scroll' }}
>
{list_label.map((label) => (
<Grid item key={label}>
<Paper sx={{ height: 120, width: 150, backgroundColor: 'red'}}>
{label}
</Paper>
</Grid>
))}
</Grid>

How to remove focused highlight in React material-ui Tab Component?

I am using a Tab component from the react Material-ui library. The tab appears with this weird outline on the left and right borders when the Tab element is in focus.
Is there any way to remove this active / focus outline?
Below is an image of the weird focus styling in question
My code is below:
import { Fragment } from 'react';
import styled from 'styled-components'
import Card from 'components/Elements/Card';
import CardItem from 'components/Elements/CardItem';
import CreateAccountForm from 'components/Forms/CreateAccount/container';
import { withTheme } from 'styled-components';
import { Container, Row, Col } from 'styled-bootstrap-grid';
import { pure } from 'recompact';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import { withStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import OpenModalButton from 'components/Modal/OpenModalButton/container';
const styles = theme => ({
indicator: {
backgroundColor: "red",
border: '5px solid blue !important',
'&:active': {
outline: 'none',
},
'&:focus': {
outline: 'none',
}
},
selected: {
backgroundColor: 'blue',
},
wrapper: {
border: '5px solid blue',
}
});
import { LogoElement } from 'components/Elements/Icons';
const StyledCard = styled(withTheme(Card))`
border: 15px solid ${ props => props.theme.colors.blue[3]};
text-align: left;
border-radius: 3px;
padding-top: ${ props => props.theme.spacer[2]};
padding-bottom: ${ props => props.theme.spacer[2]};
position: relative;
width: 98%;
max-width: 1250px;
min-height: 600px;
display: flex;
align-items: flex-start;
h5 {
color: ${ ({ theme }) => theme.colors.orange[3]};
}
`;
const CloseButton = styled.a`
transform: rotate(45deg);
font-size: 50px !important;
border: none !important;
position: absolute;
top: -20px;
right: 5px;
color: ${ props => props.theme.colors.blue[3]} !important;
font-weight: 200 !important;
&:hover{
text-decoration: none;
}
`;
const LogoContainer = styled.div`
position: absolute;
top: 10px;
left: 15px;
width: 45px;
height: 100%;
svg, path, g, polygon, rect {
fill: ${ props => props.theme.colors.orange[1]} !important;
}
`;
const Renderer = ({ handleClose, className, classes, handleTabChangeClick }) => {
return (
<StyledCard>
<CloseButton href="#" onClick={handleClose}>+</CloseButton>
<CardItem>
<Container>
<Row>
<Col>
<Tabs
variant="fullWidth"
onChange={handleTabChangeClick}
>
<Tab label="Profile" />
<Tab label="Activity" />
<Tab label="Score" />
<Tab label="Edit" />
</Tabs>
</Col>
</Row>
</Container>
</CardItem>
</StyledCard>
);
};
export default withStyles(styles)(Renderer);
I had the same problem. Try changing:
'&:active': {
outline: 'none',
},
To:
'&:hover': {
outline: 'none',
},
I use styled-components to override material-ui styling, so my setup is a little different, but the solution should be the same.
You have to override Mui-selected class.
'&.Mui-selected': {
outline: 'none',
}
See https://material-ui.com/api/tab/#css for classes defined for tab.
This solved my issue.
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example">
<Tab sx={{
'&.Mui-selected': {
outline: 'none',
}
}}
label="Item One" />
<Tab sx={{
'&.Mui-selected': {
outline: 'none',
}
}} label="Item Two" />
<Tab sx={{
'&.Mui-selected': {
outline: 'none',
}
}}
label="Item Three" />
</Tabs>
If you are facing the issue in a textarea in MUI, add the following to the inline style:
--Textarea-focusedHighlight":"none"
For instance,
<Textarea maxRows={10} style={{"--Textarea-focusedHighlight":"none"}} placeholder="Write your answers here" />

Check boxes overlap in scrollable table with sticky table head

I am creating a scrollable table with fixed table header and checkboxes. The table worked fine(no overlap of table head and body) without the checkbox. With the checkboxes, all rows scrolls just fine except that checkbox in table body would overlap with checkbox (or show up) in table head.
I tried setting backgrounds to white but won't work.
Issue Demo: https://codesandbox.io/s/vm6l0p1vly
<div
style={{
height: "500px",
width: "100%",
overflow: "auto",
borderStyle: "solid",
borderWidth: 1,
borderColor: "lightGray"
}}
>
<Table>
<TableHead>
<TableRow>
<TableCell
padding="checkbox"
style={{ position: "sticky", top: 0, backgroundColor: "white" }}
>
<Checkbox />
</TableCell>
<TableCell
style={{ position: "sticky", top: 0, backgroundColor: "white" }}
>
id
</TableCell>
<TableCell
style={{ position: "sticky", top: 0, backgroundColor: "white" }}
>
name
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map(row => (
<TableRow key={row.id} hover>
<TableCell padding="checkbox">
<Checkbox />
</TableCell>
<TableCell>{row.id}</TableCell>
<TableCell>{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
I expect the checkboxes to not overlap.
I don't have enough points to comment, but the answer is to set the z-index: 1 for the header containing the checkbox.

Style card component from material-ui

By default Card component has a box-shadow style.
I would like to change the box-shadow color if the item is clicked. However I can't even change box-shadow color using styles (no click event).
Card Component render a Paper element, and this element define the styles like this:
function getStyles(props, context) {
const {
circle,
rounded,
transitionEnabled,
zDepth,
} = props;
const {
baseTheme,
paper,
} = context.muiTheme;
return {
root: {
color: paper.color,
backgroundColor: paper.backgroundColor,
transition: transitionEnabled && transitions.easeOut(),
boxSizing: 'border-box',
fontFamily: baseTheme.fontFamily,
WebkitTapHighlightColor: 'rgba(0,0,0,0)', // Remove mobile color flashing (deprecated)
boxShadow: paper.zDepthShadows[zDepth - 1], // No shadow for 0 depth papers
borderRadius: circle ? '50%' : rounded ? '2px' : '0px',
},
};
}
As paper is render using also styles sent as parameter:
<div {...other} style={prepareStyles(Object.assign(styles.root, style))}>
I try to send boxShadow as a parameter:
card: {
position: 'relative',
width: '350px',
color: 'red',
boxShadow: 'rgba(255, 0, 0, 0.117647) 0px 1px 6px, rgba(255, 0, 0, 0.117647) 0px 1px 4px'
},
but nothing happens. My Card component should change shadow value onHover and this effect stops working:
import React, {Component, PropTypes} from 'react'
import {Card, CardActions, CardHeader, CardMedia, CardText} from 'material-ui/Card'
import FlatButton from 'material-ui/FlatButton'
import PictogramMenu from './PictogramMenu'
const styles = {
card: {
position: 'relative',
width: '350px',
color: 'red'
//borderStyle: 'solid',
//borderColor: 'yellowgreen'
//boxShadow: 'rgba(255, 0, 0, 0.117647) 0px 1px 6px, rgba(255, 0, 0, 0.117647) 0px 1px 4px'
},
menu: {
position: 'absolute',
right: '10px',
top: '15px'
},
cardHeader: {
paddingBottom: '40px'
}
}
export default class PictogramCard extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
img: PropTypes.string.isRequired
}
constructor(props) {
super(props)
this.state = {shadow: 1}
}
onMouseOver = () => this.setState({shadow: 3})
onMouseOut = () => this.setState({shadow: 1})
render() {
return (
<Card style={styles.card} containerStyle={{width: 300}} zDepth={this.state.shadow}
onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut}>
<CardHeader />
<PictogramMenu style={styles.menu} />
<CardMedia>
<img src={this.props.img} />
</CardMedia>
<CardText>
{this.props.title}
</CardText>
<CardActions>
<FlatButton label='Tag1' />
<FlatButton label='Tag2' />
</CardActions>
</Card>
)
}
}
Any hint?
Even if the question is dated, I will try to answer it.
It's necessary to override the classes of the component card. These classes are used for theming.
how?
Add classes={{ root: classes.card }} to Card element:
<Card classes={{ root: classes.card }}>
<CardActionArea>
<Grid direction="row" item xs={12} sm={6}>
<CardContent>
<Typography noWrap gutterUp>
{title}
</Typography>
<Typography noWrap variant="body3" color="textPrimary" component="p">
{date} by {author}
</Typography>
<Typography variant="body3" color="textPrimary" component="p">
{body}
</Typography>
</CardContent>
</Grid>
</CardActionArea>
</Card>
Next add styling to your makeStyles like this:
const useStyles = makeStyles({
card: {
borderRadius: 0,
backgroundColor: theme.palette.primary.light,
color: theme.palette.primary.contrastText,
boxShadow: "none"
}
});
And that's it. For more details: go