Style card component from material-ui - 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

Related

Testing for existence of react-modal using React Testing Library with findByRole

I am trying to test for the existence of my modal using React Testing Library with findByRole. I keep getting an error saying: Unable to find role="dialog" even though I can see clearly see it printed out in the console of the test.
Here is my test:
import React from "react";
import {
render,
screen,
within,
fireEvent, cleanup, waitFor
} from '#testing-library/react';
import '#testing-library/jest-dom';
import "#testing-library/react/dont-cleanup-after-each";
import Modal from 'react-modal';
import PackagerModal from './PackagerModal';
const mockedEmptyFn = jest.fn();
const mockBaseProps = {
openPackager: true,
setOpenPackager: mockedEmptyFn,
activeOrder: {
// ... // lots of irrelevant properties here
]
},
setOrders: mockedEmptyFn,
customStyles: {
content: {
backgroundColor: "var(--color-primary)",
border: "1px solid #ccc",
boxShadow: "-2rem 2rem 2rem rgba(0, 0, 0, 0.5)",
color: "rgba(var(--RGB-text), 0.8)",
filter: "blur(0)",
fontSize: "1.1em",
fontWeight: "bold",
margin: "50px auto",
opacity: 1,
outline: 0,
position: "relative",
visibility: "visible",
width: "500px"
},
overlay: {
backgroundColor: "rgba(255, 255, 255, 0.9)"
}
},
readOnly: false,
setReadOnly: mockedEmptyFn,
};
Modal.setAppElement('body');
const Component = (props) => <PackagerModal {...mockBaseProps} {...props} />
describe('Packager Modal tests with editable inputs', () => {
afterAll(() => {
cleanup();
});
test('Should show packager modal', async () => {
render(
<Component/>
);
// screen.debug();
const modalWindow = await screen.findByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});
});
And here is my modal:
import ReactModal from 'react-modal';
import React, { useEffect, useRef, useState } from 'react';
import CloseButton from './CloseButton';
import PropTypes from 'prop-types';
const PackagerModal = (props) => {
const {
openPackager,
setOpenPackager,
activeOrder,
setOrders,
customStyles,
readOnly,
setReadOnly,
} = props;
const cleanUpModal = () => {
setReadOnly(false);
setUserInput(initialState);
};
return (
<ReactModal
isOpen={openPackager}
style={customStyles}
className={'order-details-modal'}
closeTimeoutMS={1000}
onAfterClose={cleanUpModal}
>
<CloseButton setOpenModal={setOpenPackager} />
<h2 className={'title'}>Packager Order Checklist</h2>
</ReactModal>
);
};
PackagerModal.propTypes = {
openPackager: PropTypes.bool.isRequired,
setOpenPackager: PropTypes.func.isRequired,
customStyles: PropTypes.object.isRequired,
activeOrder: PropTypes.object.isRequired,
setOrders: PropTypes.func.isRequired,
readOnly: PropTypes.bool.isRequired,
setReadOnly: PropTypes.func.isRequired,
};
export default PackagerModal;
And finally, here is some of the output I see in the console from the test:
● Packager Modal tests with editable inputs › Should show packager modal
Unable to find role="dialog"
Ignored nodes: comments, script, style
<body
aria-hidden="true"
class="ReactModal__Body--open"
>
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div />
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div
class="ReactModalPortal"
>
<div
class="ReactModal__Overlay ReactModal__Overlay--after-open"
style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; background-color: rgba(255, 255, 255, 0.9);"
>
<div
aria-modal="true"
class="ReactModal__Content ReactModal__Content--after-open order-details-modal"
role="dialog"
style="border: 1px solid #ccc; box-shadow: -2rem 2rem 2rem rgba(0, 0, 0, 0.5); filter: blur(0); font-size: 1.1em; font-weight: bold; margin: 50px auto; opacity: 1; outline: 0; position: relative; visibility: visible; width: 500px;"
tabindex="-1"
>
...
Looks like the body of your test is set to hidden - aria-hidden="true" (not sure why as I'm not familiar with the package). React Testing Library is heavily accessibility oriented, so by default it ignores any elements that are not accessible.
Try querying your element with the { hidden: true } option
const myModal = getByRole('dialog', { hidden: true });
Though Avi's answer works, it technically isn't the best for testing. I was having the same issue and have realised we also have the same issue with our code so here is what is happening.
The issue is that you are saying Modal.setAppElement('body'); in your test file.
If you read the docs for react-modal, they say you need to tell the modal where your apps content is so that when the modal is open, everything within that element will have aria-hidden: true so that screen readers don't pick up any of the other content other than whats inside the modal since that gets rendered via a portal appended to the end of your body. So you setting setAppElement to body is making everything inside that hidden to screen readers, including your modal.
So to solve this you need to set that to something else, I personally have my own render function that has things like providers so I just added a new div in there. But in your case you could add it to your Component
const Component = (props) => <div id="root"><PackagerModal {...mockBaseProps} {...props} /></div>
Then you can chance the line setAppElement line to
Modal.setAppElement('root');
This will mean that you don't have to add the { hidden: true } option to your queries.
You also dont have to use findBy since there isn't any async changes happening in your test so far
test('Should show packager modal', () => {
render(<Component/>);
const modalWindow = screen.getByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});

How to collapse React MUI Accordion onblur

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

MUI v5 migration - replacing withStyles and createStyles with styled utility

I am trying to migrate my MUI v4 to v5
Trying to replace all those utilities e.g. withStyles, createStyles and makeStyles
my existing code is as below:
export const DrawerThumbnail = withStyles(() =>
createStyles({
drawerPaper: {
width: '200px',
top: 112,
backgroundColor: Color.White,
border: 'none',
marginTop: '2px',
padding: '0px 5px 0px 5px',
},
})
)(({ classes, ...props }: any) => {
return (
<Drawer
variant="permanent"
classes={{
paper: classes.drawerPaper,
}}
anchor="left"
{...props}
/>
);
});
Trying to use styled utility from #mui/system
The new code looks like this but obviously it doesn't work as I don't know how to transform the above using styled utility.
export const DrawerThumbnail2 = styled((props: any) =>
<Drawer
variant="permanent"
anchor="left"
{...props}
/>
)`
width: '200px';
top: 112;
background-color: ${Color.White};
border: 'none';
margin-top: '2px';
padding: 0px 5px 0px 5px;
`;
Please help

Material-UI TextField: Control border color

emphasized textHow to control the border color for a MUI TextField?
<DarkTextField
variant="outlined"
margin="dense"
inputRef={input => (this.input = input)}
onKeyPress={this.onKeyPressed}
type="text"
placeholder="Name"
/>
I've tried a few combinations like below:
const styles = {
border: {
"&::before": {
border: "1px solid #90caf9"
},
"&:hover:not(.Mui-disabled):before": {
border: "2px solid #90caf9"
},
"&::after": {
border: "2px solid #90caf9"
}
}
};
const DarkTextField = withStyles(styles)(props => {
const { classes, ...other } = props;
return <TextField InputProps={{ className: classes.border }} {...other} />;
});
I don't know how to specify the border.
Also, I want to control the color of the placeholder text.

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" />