How to fix ButtonGroup bleeding out of Grid container Material UI - reactjs

Here is the code and the output it's pretty self-explanatory: I am trying to build a responsive layout and for some reason the button group will bleed out of the container and even get bigger when the screen size decreases.
<Container className="container">
<Grid container>
<Grid item xs={12} md={12} lg={6}>
<Chessboard
position={tour.fen}
isDraggablePiece={isDraggable}
onPieceDrop={onDrop}
customArrows={arrows}
onSquareClick={dropPiece}
onMouseOverSquare={mouseOver}
onMouseOutSquare={mouseOut}
customSquareStyles={{ ...options }}
customBoardStyle={{
borderRadius: "4px",
boxShadow: "0 5px 15px rgba(0, 0, 0, 0.5)",
}}
customDarkSquareStyle={{ background: "#90a2ad" }}
customLightSquareStyle={{ background: "#dfe3e6" }}
/>
<ButtonGroup variant="contained" className="controls">
{isFirst ? (
<Button onClick={randomStart}>Random Start</Button>
) : null}
{tour.visited.length !== 0 ? (
<Button
disabled={tour.completed !== null}
onClick={finishTour}
>
Complete Tour
</Button>
) : null}
{tour.completed !== null ? (
<Button onClick={visualiseComplete}>
Visualise
</Button>
) : null}
{tour.visited.length !== 0 ? (
<Button
onClick={() =>
setArrows(genArrows(tour.visitedStr))
}
>
Show path
</Button>
) : null}
{tour.visited.length !== 0 ? (
<Button onClick={undo}>Undo</Button>
) : null}
{tour.visited.length !== 0 ? (
<Button onClick={reset}>Reset</Button>
) : null}
</ButtonGroup>
</Grid>
<Grid item xs={12} md={12} lg={6}>
<Moves tour={tour} />
</Grid>
</Grid>
{/* <CompletedPanel tour={tour} impossible={impossible} /> */}
</Container>
Desktop version
Mobile version
I expect the the button group to fit inside the container and become stacked vertically

Perhaps make a responsive size value with useTheme and useMediaQuery from Material UI, and try with one or more of the following approaches.
Simplified live demo: stackblitz
Import the helper hooks:
import { useTheme } from '#mui/material/styles';
import useMediaQuery from '#mui/material/useMediaQuery';
In the component, create responsive condition:
const theme = useTheme();
// 👇 Customize this with preferred breakpoints
const matches = useMediaQuery(theme.breakpoints.up('sm'));
In the output, try one or more of these approaches for responsive values:
<ButtonGroup
// 👇 Make size based on responsive value
size={matches ? "medium" : "small"}
variant="contained"
aria-label="outlined primary button group"
// 👇 Define maxWidth for the group
sx={{ maxWidth: "100%" }}
// 👇 Conditional shorter text
>
<Button>{`${matches ? "complete " : ""}tour`}</Button>
<Button>{`${matches ? "show " : ""}path`}</Button>
<Button>undo</Button>
<Button>reset</Button>
</ButtonGroup>
As an alternative option, perhaps also consider to make the ButtonGroup layout horizontal when in smaller screen size:
<ButtonGroup
size={matches ? "medium" : "small"}
// 👇 Conditional orientation
orientation={matches ? "horizontal" : "vertical"}
variant="contained"
aria-label="outlined primary button group"
sx={{ maxWidth: "100%" }}
>
<Button>complete tour</Button>
<Button>show path</Button>
<Button>undo</Button>
<Button>reset</Button>
</ButtonGroup>

Related

how to increase the size of the stepper in MUI

I want to increase the size of the stepper . also want to add a horizontal line before the initial step content. how it would be possible here I am attaching my code . I have done adding width and height properties. but Its not worked. just stuck with this. how the customization is possible on this stepper component. need help. I am new to react.js and MUI.
<Stepper activeStep={activeStep} orientation="vertical">
{steps.map((step, index) => (
<Step key={step.label}>
<StepLabel
optional={
index === 2 ? (
<Typography variant="caption">Last step</Typography>
) : null
}
>
{step.label}
</StepLabel>
<StepContent>
<Box sx={{ mb: 2 }}>
<div>
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 1, mr: 1 }}
>
{index === steps.length - 1 ? 'Finish' : 'Continue'}
</Button>
<Button
disabled={index === 0}
onClick={handleBack}
sx={{ mt: 1, mr: 1 }}
>
Back
</Button>
</div>
</Box>
</StepContent>
</Step>
))}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} sx={{ p: 3 }}>
<Typography>All steps completed - you&apos;re finished</Typography>
<Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
Reset
</Button>
</Paper>
)}
</Box> ```
Perhaps you could add a custom css to your webpage :
.MuiStepLabel-labelContainer span {
font-size: xx-large;
}
You can adjust to your desired font size by changing the "font-size" value.
You can use a Theme.
Like so:
import { createTheme } from "#mui/material";
const theme = createTheme({typography: {fontSize: 20}});
function App(){
...
return (
<>
<ThemeProvider theme={theme}>
<Stepper ...
</Stepper>
</ThemeProvider>
...
</>
}
The lines in between are a bit of. I could not find a way to prevent this.

Change color of Icon in Material UI?

I want to change the color of my thumbs up button in Material UI. I'd like to change it to white, but right now it's blue. This is my code:
<div className={styles.like_dislike}>
<IconButton
size="medium"
sx={{ ml: 2 }}
>
{likeStatus === 1
? <ThumbUpIcon onClick={handleLike} color='primary'/>
: <ThumbUpOffAltIcon onClick={handleLike} color="primary" />
}
</IconButton>
<IconButton
size="medium"
sx={{ ml: 2 }}
>
{likeStatus === -1
? <ThumbDownIcon onClick={handleDislike} />
: <ThumbDownOffAltIcon onClick={handleDislike} />
}
</IconButton>
</div>
I have a section in my CSS file modifying MuiIcon-colorPrimary, as that is what MUI specifies to modify for icons using the primary color:
.like_dislike.MuiIcon-colorPrimary {
color: #fafafa
}
Am I doing something wrong?

Search button to activate autocomplete googl maps places (React.js)

I am using AutoComplete button from material/ui for searching Google Maps Places. Everything is working properly so when user clicks on the one offered field in autocomplete it leads him to next page.
My question is: is it possible to add search button to active autocomplete if user clicks on button?
Here is code for autocomplete and I have added button but still nothing happens if someone clicks on it.
<div className="search">
<Autocomplete
id="google-map-demo"
key={reset}
ListboxProps={{ style: { maxHeight: 400, overflow: 'auto',fontSize:'0.7rem' } }}
getOptionLabel={(option) =>
typeof option === "string" ? option : option.description
}
filterOptions={(x) => x}
options={options}
onChange={(e, l) => {
customer.setMyaddress(l.description);
getMyDestination(l.place_id);
}}
renderInput={(params) => (
<TextField
{...params}
className={classes.root}
variant="standard"
fullWidth
onChange={(e, v) => {
setInputValue(e.target.value);
}}
/>
)}
renderOption={(option) => {
const matches =
option.structured_formatting.main_text_matched_substrings;
const parts = parse(
option.structured_formatting.main_text,
matches.map((match) => [
match.offset,
match.offset + match.length,
])
);
return (
<Grid container alignItems="center">
<Grid item>
<LocationOnIcon className={classes.icon} />
</Grid>
<Grid item xs>
{parts.map((part, index) => (
<span
key={index}
style={{ fontWeight: part.highlight ? 700 : 400 }}
>
{part.text}
</span>
))}
<Typography variant="body2" color="red" className={classes.noOptions} >
{option.structured_formatting.secondary_text}
</Typography>
</Grid>
</Grid>
);
}}
/>
<button className="btn btn-primary" style={{position: "absolute",
right: "0"}}
onClick={(e, v) => {
setInputValue(e.target.value);
}}>Find</button>
</div>
Anyone has idea how to fix this so when clicked on button I got same result as clicked on autocomplete field?
Thank you
you use the open prop which is in the Autocomplete , i've forked the Autocomplete example from material-ui check it out:
https://codesandbox.io/s/material-demo-forked-3n5lw?file=/demo.js

how to prevent duplicate onChange values within map loop

I'm trying to prevent onChange values from duplicating within each item.
for example
onChange method for comments
handleCommentChange = (e) => {
this.setState({
comment_body: e.target.value
})
}
I'm assuming i would have to loop through keys or something within the onChange method. I'm not sure how i would go about doing this.
something like
Pseudo Attempt
Object.keys(this.state.items).forEach(key){
this.setState({
comment_body: e.target.value[key]
})
}
Or is there a better way ? not sure.
map iteration code
{this.state.images.length > 0 ? (
this.state.images.map( (img, i) => (
<Grid item sm={12} md={12} key={img.id} style={{ margin: '30px 0px'}}>
<Paper style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick ={() => this.writeComment(img.id)} variant="outlined" component="span" color="primary">
{this.state.isComment === img.id ? "Close" : "Write A Comment"}
</Button>
{/* here were prevent comments being selected for all items in the array, renders the comment form you clicked on. */}
{this.state.isComment === img.id ?
<Comment onSubmit={this.commentSubmit}
commentBody={this.state.comment_body }
commentChange={this.handleCommentChange}/>
: null}
{/* hide delete button when user enters comment */}
{!this.state.isComment ? <Button style={{margin: '0px 20px'}} onClick={() => this.deleteImg(img.id)} variant="outlined" component="span" color="primary">
Delete
</Button> : null}
</Paper>
</Grid>
))
) : (
<div>
<Grid item md={8}>
<Typography>No Images yet</Typography>
</Grid>
</div>
)}
The problem is that all your comments refer to the same value in your component-state. I wanted to touch upon this in your earlier question.
What you should be doing is separating your Grid markup into its own component like this:
ImageContainer.js
import React, { Component } from "react";
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
import Divider from '#material-ui/core/Divider';
import Image from './Image';
import moment from 'moment';
import Comment from './Comment';
class ImageContainer extends React.Component{
state = {
isComment: false,
comment_body: ""
}
handleCommentChange = (e) => {
this.setState({
comment_body: e.target.value
})
}
writeComment = (id) => {
this.setState({
isComment: this.state.isComment ? '' : id // check if you state is filled to toggle on/off comment
})
}
commentSubmit = (e) => {
e.preventDefault();
console.log(this.state.comment_body);
// Axios.post('/images/newComment', this.state.comment_body).then( (response )=> {
// const newComment = { ...response.data};
// console.log(newComment);
// this.setState({
// comment_body: ''
// })
// })
}
render(){
const { img } = this.props
return(
<Grid item sm={12} md={12} key={img.id} style={{ margin: '30px 0px'}}>
<Paper style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick ={() => this.writeComment(img.id)} variant="outlined" component="span" color="primary">
{this.state.isComment === img.id ? "Close" : "Write A Comment"}
</Button>
{/* here were prevent comments being selected for all items in the array, renders the comment form you clicked on. */}
{this.state.isComment === img.id ?
<Comment onSubmit={this.commentSubmit}
commentBody={this.state.comment_body }
commentChange={this.handleCommentChange}/>
: null}
{/* hide delete button when user enters comment */}
{!this.state.isComment ? <Button style={{margin: '0px 20px'}} onClick={() => this.deleteImg(img.id)} variant="outlined" component="span" color="primary">
Delete
</Button> : null}
</Paper>
</Grid>
)
}
}
export default ImageContainer
Now each ImageContainer has its own state-values to keep track of and update. So there is no duplicates.
Then in your Dashboard component, simply import ImageContainer.
import ImageContainer from "./ImageContainer"
Now for each image in our .map(), we will create a unique instance of that component, and pass the image as a prop to ImageContainer.
{this.state.images.length > 0 ? (
this.state.images.map( (img, i) => (
<ImageContainer img={img}/>
))
) : (
<div>
<Grid item md={8}>
<Typography>No Images yet</Typography>
</Grid>
</div>
)}
Also remember to hook up your event-handlers to your Comment component. At the minimum it needs to use the props you passed in.
Comment.js
import React from "react";
const Comment = props => {
return (
<form onSubmit={props.onSubmit}>
<input
onChange={props.commentChange}
value={props.commentBody}
/>
</form>
);
};
export default Comment;
Here's a sandbox too, I dont have your Comment component code so it wont have the same styling: https://codesandbox.io/s/young-pine-zmpvr

How do I close a card when onclick on a button in react?

I have a material-ui card in which it contains image, input field, check-box and a submit button. In which card is displaying onclick on some other option which is not mentioned in the below code. I want to close a card when I click on submit. How can I achieve this?
<Card
className="details-card"
style={{ paddingTop: "0px" }}
color="primary"
>
<CardHeader
style={{
paddingBottom: 0,
paddingTop: 0
}}
title="Image"
/>
<img src="https://unsplash.it/200/?random" />
<CardContent className="details-card-body">
<TextField label="Name" fullWidth />
<Grid container>
<Grid item xs={4}>
<Typography>
New User
<Checkbox
checked={this.state.addNew}
name="addNew"
onChange={this.handleCheckBox("addNew")}
value="new user"
inputProps={{ "aria-label": "Checkbox B" }}
/>
</Typography>
</Grid>
</Grid>
<Button variant="contained" color="primary">
Click to Tag
</Button>
</CardContent>
</Card>
Here below is my code on CodeSandbox
https://codesandbox.io/embed/lppzx48r0m
There are multiple ways to achieve what you want to do
you'll need a flag to conditionally hide or show the card.
For example lets take flag variable in state, and change state variable flag based on submit button and on the basis of this.state.flag you can do
{this.state.flag ?
(<Card
className="details-card"
style={{ paddingTop: "0px" }}
color="primary"
>
//Card content
</Card>)
:
null
}
You can also provide conditional css based on this.state.flag
<Card
className="details-card"
style={{ paddingTop: "0px", display: this.state.flag ? block : 'none'}}
color="primary"
>
//Card content
</Card>
P.S.: The second approach is not recommended because we are rendering element even if it is not needed.

Resources