Best way to import a custom svg icon and display it - material-ui

I have to import a custom svg icon and use it as a button within my application
What I have been doing it is,
import high from '../img/high.svg';
const styles = theme => ({
icon: {
color: red[800],
height: '15px',
width: '15px',
cursor: 'pointer'
}
});
<IconButton><CardMedia image={high} className={classes.icon}/></IconButton>
But this does not behave like a button and I do not get the hand symbol for onClick. What is the best way to display the icon as a button?

Do a styled component that is styled s a span
interface IconProps {
color: 'blue' | 'red' | 'green';
size: string;
margin: string;
}
export const Icon = styled.span<IconProps>`
color: ${props => props.color || '#000000'};
font-size: ${props => props.size || ''};
margin: ${props => props.margin || null};
cursor: pointer;
`;
You do not have to use props like I have, but this works fine for me. spans are very useful when forcing styling on to things like text and SVGs.
Example
<Icon size="150px" color="green">
<i className="fab fa-fort-awesome-alt"/>
</Icon>
NOTE: I do use typescript. You may not need to use an interface if you dont use props. I just left it there as part of my example I have done.

Related

Is there a way to "inject" pure CSS into MUI v5

I have a custom spinner that is currently using keyframes like so:
import { keyframes } from "#mui/system";
...
const keyframeSpinner = keyframes`
0%{transform:rotate(0deg);}
100%{transform:rotate(360deg);}
`;
...
<Box
sx={{
animation: `${keyframeSpinner} 1s linear infinite`,
}}
/>
...
I don't want to import #mui/system and I don't want to use styled components.
So, I'm trying to find a solution where I can uses pure css or another solution that I'm unaware of.
You can easily apply in-line CSS styles to components using emotion, which is also used by MUI.
For example, here is the css prop from emotion being used to customize background-color and hover on a div. The code you write in the css prop can be pure CSS.
import { css, jsx } from '#emotion/react'
const color = 'darkgreen'
const customCss = css`
background-color: hotpink
&:hover { color: ${color} }
`
render(
<div css = {customCss}>
This div has a hotpink background.
</div>
)

Correct way to set only circle size in Material UI Stepper?

As you can see in this codesandbox, I have used the 'transform' property, based on this answer, also tried changing the font-size on the StepIconProps (commented out code on CSB).
The first option results in the circle resizing while still retaining its centre, and hence its alignment with the line, but the text stays in the same place.
The second option means the circle loses its alignment with the line, but the text stays nicely positioned relative to the circle.
I'm not sure either are entirely the correct way to do it. There is an example in the docs where the icon has been customised, but this involves an implementation a whole new icon, which I'd rather avoid. I am happy with all of the default appearance, with the only exception being the size.
I created a div element using styled components and I passed it as a prop icon at StepLabel from material UI.
import React, { useState, useEffect } from "react";
import { Stepper, Step, StepLabel } from "#material-ui/core";
const stepsOptions = {
0: [0],
1: [0, 1],
2: [0, 1, 2],
};
const StepIcon = styled.div`
background-color: ${({ backgroundColor }) =>
backgroundColor ? "#008a98" : "#DCDCDC"};
color: #fff;
width: 50px;
padding: 2px;
display: flex;
align-items: center;
justify-content: center;
height: 50px;
font-size: 20px;
border-radius: 50%;
margin-top: -13px;
font-weight: 500;
z-index: 1;
`;
const Component = () => {
const [stepsArray, setStepsArray] = useState([]);
useEffect(() => {
setStepsArray(stepsOptions[activeStep]);
}, [activeStep]);
return (
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label, index) => (
<Step key={label}>
<StepLabel
icon={
<StepIcon backgroundColor={stepsArray.includes(index)}>
<p>{index + 1}</p>
</StepIcon>
}
>
<Paragraph>{label}</Paragraph>
</StepLabel>
</Step>
))}
</Stepper>
)}

Material UI > Backdrop > only for some subcomponent of the page

Is there any way how to enhance a backdrop from example in https://material-ui.com/components/backdrop/ to show loading circle only above the single component (in case some page has more component), not above the whole page?
Thanks for reply.
Backdrop are fixed positioned by default, that's why it covers the whole page.
To achieve the result you want, we have to change its position to absolute and contain it inside an element with relative position — this element can be your component. If you're new in CSS positions check this docs from developer.mozilla.org.
Knowing all that, we can come up with the following codes
const useStyles = makeStyles({
parent: {
position: "relative",
width: 200,
height: 200,
backgroundColor: "red",
zIndex: 0,
},
backdrop: {
position: "absolute"
}
});
export default function App() {
const classes = useStyles();
return (
<div className={classes.parent}>
<Backdrop className={classes.backdrop} open={true}>
<CircularProgress color="inherit" />
</Backdrop>
</div>
);
}
Also we have to define z-index on either parent or backdrop element to make it work. Not sure why though.
I created a codesandbox for you to play with.
The Backdrop component of Material UI is set to position: 'fixed' by default, that's why it covers the whole page.
If you want it to reside and position itself like any other component typically on the DOM, all you have to do is to reset its position back to relative, for instance:
<Backdrop open={true} sx={{ position: 'relative' }}>
<CircularProgress color="inherit" />
</Backdrop>
and you don't need to change the parent component since it should be in your case see to relative by default if you're not changing it. But if you have crazy positions going in your app here and there, then you might consider changing that as well.
i have created a custom componenet that i use if i want to block only part of the UI:
"use strict";
/** external libraries */
import React from "react";
import Backdrop from "#mui/material/Backdrop";
import CircularProgress from "#mui/material/CircularProgress";
const BlockUi = ({open, onClose, children}) => {
return (
<div style={{"position": "relative"}}>
<Backdrop
sx={{color: "#FFFFFF", zIndex: (theme) => theme.zIndex.drawer + 1, "position": "absolute"}}
open={open}
onClick={() => onClose()}
>
<CircularProgress color="inherit"/>
</Backdrop>
{children}
</div>
);
}
export default BlockUi;
and i use it like this:
"use strict";
/** external libraries */
import React from "react";
import BlockUi from "./BlockUi";
const JsonForm = ({fields, onSubmit}) => {
const [loading, setLoading] = React.useState(false)
const stopLoading = () => {
setLoading(false)
}
return (
<div>
<BlockUi open={loading} onClose={stopLoading}>
<button type="submit" onClick={() => {
console.log(loading)
setLoading(true)
}}>Submit
</button>
</BlockUi>
</div>
);
}
export default JsonForm;

How to reduce the height of Autocomplete component of Material UI?

Can anyone help me to reduce the height of Material UI Autocomplete component ? I am trying to use set the height property to 10 or 20 px though the classes property. But it does nothing. Also tried to reduce the height of the Textfield which wrapped by Autocomplete component, but when I tried to reduce the height of the Textfield component through InputProps, then the Items that were to be suggested in Autocomplete area don't display.
I am also customizing the Autocomplete component.
To reduce the height, I used the size attribute and removed the label attribute.
renderInput={(params) => <TextField {...params} variant="standard" size="small" />}
Make sure not to override the params provided by the Autocomplete component on your TextField component, which already include things like InputProps.
You'll probably want to use Autocomplete's CSS API to achieve all the customizations you're looking for. For example,
const useStyles = makeStyles(theme => ({
inputRoot: {
color: theme.palette.primary.contrastText,
},
popupIndicator: {
color: theme.palette.primary.contrastText,
},
root: {
padding: `0 ${theme.spacing(1)}px`,
},
}))
const AutocompleteWrapper = ({
value,
onChange,
options,
}) => {
const classes = useStyles()
return (
<Autocomplete
classes={classes}
options={options}
value={value}
onChange={onChange}
renderInput={(params) => <TextField {...params} variant="standard" size="small" />}
/>
)
}
Try setting the input height via the css
.MuiInputBase-input {
height: 1.5rem;
}
If you have tags inside - you will also need to set their height, otherwise they will increase their container height
I agree with #H.Hattab. For anyone using styled-components here is the example
const AutoComplete = styled(Autocomplete)`
& .MuiInputBase-input {
height: 1.5rem;
}
`;
Use the prop ListboxProps:
Like
<Autocomplete
fullWidth
disableClearable
ListboxProps={{ style: { maxHeight: 150 } }}
...
/>

JSS interrogations

I am using CSS in JS (JSS) with material-ui, it works fine, but i don't get what it's supposed to offer (more than style injection) in terms of features/coding facilities. I feel like i am missing something so i have some specific questions.
With the style injection, i can adapt the style to the context, for instance:
const buttonStyle = {
border: "2px solid black »,
borderRadius: "5px",
padding: "15px",
font-family: "15px",
font-size: "2em",
backbroundColor: "red"
};
if (success) {
buttonStyle.backgroundColor = "green";
}
With JSS, it looks like i need to "pre-build" the whole button style in its different potential colors:
const style = {
buttonSuccess: {
border: "2px solid black »,
borderRadius: "5px",
padding: "15px",
font-family: "15px",
font-size: "2em",
backbroundColor: « green »
},
buttonError: {
border: "2px solid black",
borderRadius: "5px",
padding: "15px",
font-family: "15px",
font-size: "2em",
backbroundColor: "red"
}
};
Is there any way to avoid to re-write the whole style when only one parameter is dynamic?
And another point, with JSS, it looks like we need to inject one class for each html element we need to style.
So if i have a table with 200 cells, am i supposed to add 200 classes into my DOM (when i could declare it only one time with a td selector in pure CSS)?
Is there a way to work with inherit style between parent and children components?
Because there is a dirty pattern i have written several time to merge a style i inject from the parent and the style the children compile by itself:
const styles = theme => ({
root: {
backgroundColor: "blue"
}
});
const childComponent = (props) => (
<div classeName={`${props.parentClass} ${props.classes}`} /> // See parentClass here
);
export default withStyles(styles)(childComponent);
Is there any way to avoid to re-write the whole style when only one parameter is dynamic?
Yes, see function values. http://cssinjs.org/json-api?v=v9.8.1#function-values
So if i have a table with 200 cells, am i supposed to add 200 classes into my DOM (when i could declare it only one time with a td selector in pure CSS)?
You can use '& td' selector, see jss-nested plugin, it is already built in.
http://cssinjs.org/jss-nested?v=v6.0.1
Is there a way to work with inherit style between parent and children components?
JSS doesn't modify inheritance model of CSS. I think you are trying to override a property that is defined by the core. Check out customization documentation https://material-ui.com/customization/overrides/