Conditionally apply single attribute in react? - reactjs

Is there a shorter/inline version of doing this in react, basically applying a single css attribute conditionally?
setStyle () {
const style = {
display: 'flex',
flexDirection: 'column',
height: 485
}
if (this.state.zoom) {
style.position = 'absolute'
}
return style
}
<div ref='container' style={this.setStyle()}>
Something in this context:
style={{
display: 'flex',
flexDirection: 'column',
height: 485
position: absolute // Make this conditional
}}

Using Object.assign
let style = Object.assign({
display: 'flex'
}, this.state.zoom && { position: 'absolute' })
Using spread/rest properties
let style = {
display: 'flex',
...this.state.zoom && { position: 'absolute' }
}
Inline, inline:
<div
style={
Object.assign({
display: 'flex'
}, this.state.zoom && { position: 'absolute' })
}
/>
<div
style={{
display: 'flex',
...this.state.zoom && { position: 'absolute' }
}}
/>

Related

MUI - Change date picker header elements order

Is it possible to change the header elements order? I want the arrows to be in the right and left side of the Month-Year title, and not as it is now. The image shows exactly what I'm trying to achieve:
Codesandbox: https://codesandbox.io/s/stupefied-butterfly-rkss81?file=/src/App.js
Do you have any idea how I can achieve it?
I tried to use
PrivatePickersFadeTransitionGroup and MuiPickersCalendarHeader
class names but it didn't work.
Thank you
Try to put replace your current style with this one:
const dateTimePaperPropsStyles = {
sx: {
".MuiPickersCalendarHeader-root": {
display: "flex",
alignItems: "center",
justifyItems: "center"
},
".MuiPickersCalendarHeader-root:first-child": {
order: 0,
paddingRight: "20px",
paddingLeft: "20px"
},
".MuiPickersArrowSwitcher-root": {
display: "inline-flex"
// visibility: "hidden"
},
".MuiPickersCalendarHeader-label": {
textAlign: "center"
},
".MuiPickersArrowSwitcher-spacer": {
width: "220px"
},
".css-31ca4x-MuiPickersFadeTransitionGroup-root": {
display: "flex",
position: "absolute",
paddingLeft: "80px"
},
".css-9reuh9-MuiPickersArrowSwitcher-root": {
marginLeft: "-2px"
},
".MuiPickersArrowSwitcher-button": {
paddingRight: "7px"
}
}
};
link to sandbox

ReactJS: How do I properly convert from styled-components to MUI?

So I want to migrate from styled-components to MUI v5xxx, I have some styling work on styled-components but after I convert the code to the MUI some of them don't work properly, for example, I have a container supposed to be hovering an infostyle but nothing happen
Hover Script
const StyledInfo = styled("div")(({ theme }) => ({
opacity: 0,
width: "100%",
height: "100%",
position: "absolute",
backgroundColor: "rgba(0, 0, 0, 0.1)",
top: 0,
left: 0,
zIndex: 3,
display: "flex",
alignItems: "center",
justifyContent: "center",
transition: "all 0.5s ease",
}));
const StyledContainer = styled("div")(({ theme }) => ({
flex: 1,
minWidth: "320px",
height: "400px",
display: "flex",
alignItems: "center",
justifyContent: "center",
backgroundColor: "#F7BB62",
backgroundImage: `url("https://www.transparenttextures.com/patterns/crissxcross.png")`,
color: "#ffffff",
position: "relative",
cursor: "pointer",
"&:hover ${StyledInfo}": {
opacity: 1,
},
}));
as you can see on this "&:hover ${StyledInfo}": {....} doesn't work
Another example, when adding props
const Arrow= styled("img")(({ theme,props }) => ({
left: ${(props) => props.direction === "left" && "10px"},
right: ${(props) => props.direction === "right" && "10px"},
}));
on this case ${(props) => props.direction === "left" && "10px"} doesn't work
What I've tried
Using backtick
I have no clue how to fix this
Are you using emotion? If you are using emotion (highly recommended over styled-components), you can simply use import { styled } from '#mui/material/styles, and it works identically.
If you use emotion, you need to follow https://mui.com/system/styled/#how-to-use-components-selector-api to add the babel plugin, in order to use Child selector
babel config
module.exports = {
...
plugins: [
[
"#emotion",
{
importMap: {
"#mui/system": {
styled: {
canonicalImport: ["#emotion/styled", "default"],
styledBaseImport: ["#mui/system", "styled"]
}
},
"#mui/material/styles": {
styled: {
canonicalImport: ["#emotion/styled", "default"],
styledBaseImport: ["#mui/material/styles", "styled"]
}
}
}
}
]
]
};
With regards to the following code
const Arrow= styled("img")(({ theme,props }) => ({
left: ${(props) => props.direction === "left" && "10px"},
right: ${(props) => props.direction === "right" && "10px"},
}));
Your condition is actually invalid. e.g. if your props.direction, your left property becomes false which is not a valid value.
Probably a better way to write this component would be
const Arrow= styled("img", { shouldForwardProp: (prop) => !['left', 'right'].includes(prop))(({ theme,direction }) => ({
left: ${direction === 'left' ? '10px' : 'auto'},
right: ${direction === 'right' ? '10px' : 'auto'},
}));
Update:
in this code block, you are using " instead of `, which means StyledInfo is being read as plain text.
"&:hover ${StyledInfo}": {
opacity: 1,
},
Try changing to
`&:hover ${StyledInfo}`: {
opacity: 1,
},

Can't resolve "Module not found: Can't resolve : " in React.js

I can't believe that I'm asking an obvious question, but I still get the error in console log.
Console says that it can't find the module in the directory, but I've checked at least 10 times for typos. Anyways, here's the component code.
I want to render MainTemplate in root
import React from 'react';
import MainTemplate from './components/MainTemplate';
const App = () => {
return (
<MainTemplate></MainTemplate>
);
}
export default App;
This is the MainTemplate component
import React from 'react';
import Categories from './components/Categories';
const Maintemplate = () => {
const MainTemplate = {
display: 'flex',
};
const HeaderTemplate = {
backgroundColor: '#0bb286',
color: '#fff',
fontSize: '32px',
padding: '20px',
width: '100%',
};
const CrawlTemplate = {
backgroundColor: '#eeeeee',
width: '750px',
height: '1050px',
margin: '80px',
padding: '40px',
fontSize: '30px',
textAlign: 'center',
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-between',
flex: '1',
marginTop: '60px',
};
const TutoringTemplate = {
backgroundColor: '#eeeeee',
width: '750px',
height: '1050px',
margin: '80px',
padding: '40px',
fontSize: '30px',
textAlign: 'center',
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
flex: '1',
marginTop: '60px',
};
const GroupStudyTemplate = {
backgroundColor: '#eeeeee',
width: '750px',
height: '1050px',
margin: '80px',
padding: '40px',
fontSize: '30px',
textAlign: 'center',
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
flex: '1',
marginTop: '60px',
};
const footerTemplate = {
backgroundColor: '#0bb286',
color: '#fff',
fontSize: '32px',
textAlign : "center",
padding: '20px',
width: '100%',
}
return (
<div>
<div className="HeaderTemplate" style={HeaderTemplate}>
튜터링/학습공동체 및 비교과활동 모음 사이트
</div>
<div className="MainTemplate" style={MainTemplate}>
<div className="CrawlTemplate" style={CrawlTemplate}>
<Categories/>
</div>
<div className="TutoringTemplate" style={TutoringTemplate}>
튜터링 활동신청 part
</div>
<div className="GroupStudyTemplate" style={GroupStudyTemplate}>
학습공동체 활동신청 part
</div>
</div>
<div className="footerTemplate" style={footerTemplate}>
박종준 #copy & right
</div>
</div>
);
};
export default Maintemplate;
This is the Categories component
import React from 'react';
import styled from 'styled-components';
const categories = [
{
name: 'All',
text: '전체'
},
{
name: 'Bachelor',
text: '학사'
},
{
name: 'Scholarship',
text: '장학'
},
{
name: 'Learning/Counseling',
text: '학습/상담'
},
{
name: 'Getjob',
text: '취창업'
}
];
const CategoriesBlock = styled.div`
display: "flex",
padding: "10px",
flexDirection : "row",
margin: "0 auto"
`;
const Category = styled.div`
fontSize : "16px",
cursor : "pointer",
textDecoration: 'none'
& : hover = {
color : #0bb286;
}
& + & {
margin-left : 10px;
}
`;
const Categories = () => {
return (
<CategoriesBlock>
{categories.map(c => (
<Category key={c.name}>{c.text}</Category>
))}
</CategoriesBlock>
);
}
export default Categories;
I've checked at least 10 times that the module is at this location ./src/components/MainTemplate.
Yet, React still throws this error:
./src/components/MainTemplate.js
Module not found: Can't resolve './components/Categories' in '/workspace/web_platform_test/myapp/src/components'
if your MainTemplate.js is located at ./src/components/MainTemplate.js, and your Categories.js is located at ./src/components/Categories.js
Then your import statement should be: import Categories from './Categories';
Looks like you're importing from ./src/components' so update the import to import Categories from './Categories', i.e. remove components from your import.

update a value using useRef and useEffect

I need to get the left position of an element after elements got mounted to show a progress bar. It works on clicking links however when it got mounted the progressWidth is not getting calculated. basically, the useEffect seems running before the component is mounted!!!!
export default ({ task, selectedLocal, selectedScenarioId, taskId, selectedTaskId }: ITaskNavItem) => {
const isActiveNav = (match: any, location: object) => match;
const isBefore = taskId <= selectedTaskId;
const isActive = taskId === selectedTaskId;
const navItemWidth = 100;
const [progressWidth, setProgressWidth] = useState(0);
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
if (ref.current) {
console.log(ref.current.getBoundingClientRect().left);
setProgressWidth(ref.current.getBoundingClientRect().left);
}
});
const theme = getTheme();
const styles = StyleSheet.create({
navLink: {
display: 'flex',
fontSize: '12px',
textDecoration: 'none',
color: theme.palette.neutralPrimary
},
navLinkActive: {
color: theme.palette.neutralPrimary,
fontWeight: 'bold'
},
navTitle: {
width: `${navItemWidth}px`,
textAlign: 'center',
wordBreak: 'break-word',
wordSpacing: `${navItemWidth}px`
},
linkText: {
display: 'flex',
flexFlow: 'column',
'align-items': 'center'
},
navIndicator: {
borderRadius: '50%',
margin: '10px 0 0 0',
backgroundColor: theme.palette.white,
width: '30px',
height: '30px',
border: '2px solid',
borderColor: theme.palette.neutralPrimary,
position: 'relative',
'z-index': '3'
},
innerIndicator: {
position: 'absolute',
borderRadius: '50%',
width: '20px',
height: '20px',
backgroundColor: theme.palette.neutralPrimary,
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
},
activeNavIndicator: { borderColor: theme.palette.themePrimary },
activeInnerIndicator: { backgroundColor: theme.palette.themePrimary },
progress: {
marginTop: '59px',
'z-index': '2',
position: 'fixed',
left: '0',
width: `${progressWidth}px`,
borderBottom: '2px solid',
borderColor: theme.palette.themePrimary
}
});
return (
<div className={css(styles.navLink)}>
<NavLink
exact
isActive={isActiveNav}
className={css(isActive ? [styles.navLink, styles.navLinkActive] : styles.navLink)}
to={`/selectedLocal/${selectedLocal}/scenarios/${selectedScenarioId}/tasks/${taskId}`}
>
<div className={css(styles.linkText)}>
<div className={css(styles.navTitle)}> {task.title}</div>
<div
ref={ref}
className={css(
isBefore ? [styles.navIndicator, styles.activeNavIndicator] : styles.navIndicator
)}
>
<div
className={css(
isBefore ? [styles.innerIndicator, styles.activeInnerIndicator] : styles.innerIndicator
)}
/>
</div>
</div>
</NavLink>
{isActive && <div className={css(styles.progress)} />}
</div>
);
};
So when component is getting loaded I get image 1, when I click on the component I get image 2. What I need to happen is when component is getting loaded it should look like image 2.

How to style the active link childs using CSS in JS and React Router?

I am using React ROuter and CSS in JS for style.
I'd like to change the background color and border color for the active links child divs (navIndicator and innerIndicator)
import { css, StyleSheet } from 'aphrodite/no-important';
export default ({ task, selectedLocal, selectedScenarioId, taskId }: ITaskNavItem) => {
const isActiveNav = (match: any, location: object) => match;
const theme = getTheme();
const styles = StyleSheet.create({
navLink: {
display: 'flex',
fontSize: '12px',
textDecoration: 'none',
color: theme.palette.neutralPrimary
},
navLinkActive: {
color: theme.palette.neutralPrimary,
fontWeight: 'bold',
'.navIndicator': {
borderColor: theme.palette.themePrimary
},
'.innerIndicator': {
backgroundColor: theme.palette.themePrimary
}
},
navTitle: {
width: '100px',
textAlign: 'center',
wordBreak: 'break-word',
wordSpacing: '100px'
},
linkText: {
display: 'flex',
flexFlow: 'column',
'align-items': 'center'
},
navIndicator: {
borderRadius: '50%',
margin: '10px 0 0 0',
backgroundColor: theme.palette.white,
width: '30px',
height: '30px',
border: '2px solid',
borderColor: theme.palette.neutralPrimary,
position: 'relative'
},
innerIndicator: {
position: 'absolute',
borderRadius: '50%',
width: '20px',
height: '20px',
backgroundColor: theme.palette.neutralPrimary,
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)'
}
});
return (
<div className={css(styles.navLink)}>
<NavLink
exact
isActive={isActiveNav}
className={css(styles.navLink)}
activeClassName={css(styles.navLinkActive)}
to={`/selectedLocal/${selectedLocal}/scenarios/${selectedScenarioId}/tasks/${taskId}`}
>
<div className={css(styles.linkText)}>
<div className={css(styles.navTitle)}> {task.title}</div>
<div className={css(styles.navIndicator)}>
<div className={css(styles.innerIndicator)} />
</div>
</div>
</NavLink>
</div>
);
};
However, the navIndicator and innerIndicator colors doesn't change when nav link is active.
Wondering how to get the style working for active link?
NavLink element does not indicate to its children if it active. So I may suggest to get currecnt route from BrowserRouter component (your component should be child of BrowserRouter so NavLink works), compare path and set local isActive variable to indicate if specific route is active.
For example (not tested, just sample):
const StyledLinks: React.FunctionComponent<RouteComponentProps & ITaskNavItem> = ({ task, selectedLocal, selectedScenarioId, taskId, location }) => {
const to = '/selectedLocal/${selectedLocal}/scenarios/${selectedScenarioId}/tasks/${taskId}';
const isActive = to === location.pathname;
const styles = StyleSheet.create({
// ...
navIndicatorActive: {
borderColor: theme.palette.themePrimary
},
// ...
return (
<div className={css(styles.navLink)}>
<NavLink
exact
className={css(styles.navLink)}
activeClassName={css(styles.navLinkActive)}
to={to}
>
<div className={css(styles.linkText)}>
<div className={css(styles.navTitle)}> {task.title}</div>
<div className={isActive ? css([styles.navIndicator, styles.navIndicatorActive]) : css(styles.navIndicator)}>
<div className={css(styles.innerIndicator)} />
</div>
</div>
</NavLink>
</div>
);
}
// Wrap your component withRouter to get location prop
export default withRouter(StyledLinks);

Resources