MUI v5 migration - replacing withStyles and createStyles with styled utility - material-ui

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

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();
});

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

Slider Feature using flutter

I tried to recreate the sliding image feature on the website superlist.com using html and I found a tutorial that made it work.
HTML
<div id="left-side" class="side">
<h2 class="title">
Sometimes a simple header is
<span class="fancy">better</span>
</h2>
</div>
<div id="right-side" class="side">
<h2 class="title">
Sometimes a simple header is
<span class="fancy">better</span>
</h2>
</div>
<a id="source-link" class="meta-link" href="https://superlist.com" target="_blank">
<i class="fa-solid fa-link"></i>
<span class="roboto-mono">Source</span>
</a>
<a id="yt-link" class="meta-link" href="https://youtu.be/zGKNMm4L-r4" target="_blank">
<i class="fa-brands fa-youtube"></i>
<span>2 min tutorial</span>
</a>
CSS
:root {
--yellow: rgb(253, 216, 53);
--blue: rgb(98, 0, 234);
--dark: rgb(20, 20, 20);
}
body {
background-color: var(--dark);
margin: 0px;
}
.side {
display: grid;
height: 100vh;
overflow: hidden;
place-items: center;
position: absolute;
width: 100%;
}
.side .title {
font-family: "Rubik", sans-serif;
font-size: 8vw;
margin: 0px 10vw;
width: 80vw;
}
.side .fancy {
font-family: "Lobster", cursive;
font-size: 1.3em;
line-height: 0.8em;
}
#left-side {
background-color: var(--blue);
width: 60%;
z-index: 2;
}
#left-side .title {
color: white;
}
#left-side .fancy {
color: var(--yellow);
}
#right-side {
background-color: var(--yellow);
}
#right-side .title {
color: var(--dark);
}
#right-side .fancy {
color: white;
}
/* -- YouTube Link Styles -- */
#source-link {
top: 60px;
}
#source-link > i {
color: rgb(94, 106, 210);
}
#yt-link {
top: 10px;
}
#yt-link > i {
color: rgb(239, 83, 80);
}
.meta-link {
align-items: center;
backdrop-filter: blur(3px);
background-color: rgba(40, 40, 40, 0.9);
border-radius: 6px;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
cursor: pointer;
display: inline-flex;
gap: 5px;
left: 10px;
padding: 10px 20px;
position: fixed;
text-decoration: none;
transition: background-color 350ms, border-color 350ms;
z-index: 10000;
}
.meta-link:hover {
background-color: rgb(40, 40, 40);
}
.meta-link > i, .meta-link > span {
height: 20px;
line-height: 20px;
}
.meta-link > span {
color: white;
font-family: "Rubik", sans-serif;
transition: color 600ms;
}
JS
const left = document.getElementById("left-side");
const handleMove = e => {
left.style.width = `${e.clientX / window.innerWidth * 100}%`;
}
document.onmousemove = e => handleMove(e);
document.ontouchmove = e => handleMove(e.touches[0]);
I used the code and it worked fine but I was wondering whether you could do the same using flutter. I tried searching for specific widgets that allow you to make this kind of slider, but until now I haven't found anything satisfying, so I'm guessing you'd need a custom solution here.
How can I make this feature possible using flutter?
https://drive.google.com/file/d/1_FxXK2Ymo1GLRRIiNzmfIt95-DsYy1O2/view?usp=sharing
you can see a UI example above

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

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