Screen turns black while using antd modal - reactjs

I have a list of rows in a table. This only happens when i have more rows in a table. I am using modal of antd.
This is my code:
import {Modal,Button} from "antd";
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
const handleOk = (id) => {
store.dispatch(deleteProductList(id));
setIsDeleteModalVisible(false);
};
const handleCancel = () => {
setIsDeleteModalVisible(false);
};
<Button
icon={<DeleteFilled />}
style={{
backgroundColor: "#D15B47",
color: "#ffffff",
}}
onClick={showDeleteModal}
>
Delete
</Button>
<Modal
title="Confirm Delete"
visible={isDeleteModalVisible}
onOk={() => handleOk(record.id)}
onCancel={handleCancel}
>
<p>Are you sure you want to delete this vehicle?</p>
</Modal>

Not much to go on from the content in the question. But I assume that the backdrop has full opacity or a color that has an alpha of 1? Try to inspect the backdrop and see if the color is correct.

Related

Material UI - closing modal leaves focus state on button that opened it

Let's say I have a button that opens a Dialog component. The button has custom theming/styling to specify various states, one of them being the :focus state:
const useStyles = makeStyles({
root: {
"&:focus": {
backgroundColor: "#3A7DA9"
}
}
});
export default function App() {
const [open, setOpen] = useState(false);
const classes = useStyles();
return (
<div className="App">
<Button
id="button-that-opens-modal"
className={classes.root}
onClick={() => setOpen(true)}
>
Open the modal
</Button>
<Dialog open={open}>
<h3>This is the modal</h3>
<Button onClick={() => setOpen(false)}>
Close
</Button>
</Dialog>
</div>
);
}
What I've noticed is that every time I have this pattern, (where a button opens a dialog modal), when the modal is closed, the #button-that-opens-modal is left with a :focus state, which looks bad in terms of styling. Here's a quick gif:
Codesandbox demonstrating the issue
Is this a known issue? I don't see why the :focus should be automatically applied to the button when the modal closes. How can I stop this?
I tried this:
I can add a ref to the button, and make sure to manually unfocus the button in various places. Adding it in the onExited method of the Dialog works, but flashes the focus state for a second:
export default function App() {
const [open, setOpen] = useState(false);
const buttonRef = useRef();
const classes = useStyles();
return (
<div className="App">
<Button
ref={buttonRef}
className={classes.root}
onClick={() => setOpen(true)}
>
Open the modal
</Button>
<Dialog
open={open}
TransitionProps={{
onExited: () => {
buttonRef.current?.blur(); // helps but creates a flash
}
}}
>
<h3>This is the modal</h3>
<Button onClick={() => {setOpen(false)}}>
Close
</Button>
</Dialog>
</div>
);
}
sandbox showing this very imperfect solution
And even if I found exactly the right event handler to blur the button such the styling looks correct, this is not something I want to do for every Dialog in an app that has many Button - Dialog pairs. Is there a Material-UI prop I can use to disable this 'auto-focus' back on the button, rather than having to create a ref and manually .blur it for every Dialog?
This is for accessibilty purpose. You can disable it by adding prop disableRestoreFocus on your Dialog :)

Fix date picker inside modal window in react js

I have this component:
const App = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
</Modal>
</>
);
};
When i open the modal i get the calendar outside it. How to put the calendar inside the modal window, not outside like now?
demo: https://codesandbox.io/s/basic-antd494-forked-6lkqg?file=/index.js:269-1303
This is, IMO, incredibly hackish, but was the only way I could get the date picker's popup to behave a bit more nicely nested in a modal.
Use the getPopupContainer prop to specify what the parent should be, it defaults to "body". We can create our own element to append the date popup to.
Use the popupStyle prop to override and set the position CSS rule. It is position: absolute by default, we wan't relative positioning.
Add an empty div after DatePicker for the popup to attach to.
HACK ALERT: DatePicker inserts a div between the one we created and the popup, so CSS rule cascading & inheritance gets fubar'd, it has position: absolute as well. We need to override this to also use relative positioning.
Code:
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
getPopupContainer={() => document.getElementById("date-popup")}
popupStyle={{
position: "relative"
}}
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
<div id="date-popup" />
</Modal>
</>
CSS
#date-popup > div {
position: relative !important;
}
The main reason this is hackish is because the use of !important should generally be avoided and instead you should strive to increase a selector's specificity. I was unable to bump it enough to override the style. (I believe this is because that div is also using some inline style prop/attribute)
DatePicker itself is also a kind of Modal so it can't be embedded inside Modal. You can simply check this by inspecting both Modal and DatePicker components.
If you want the DatePicker to be opened, you can control the height of modal body. Something like this.
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
bodyStyle={{
height: 400
}}
>
Here is another suggestion:
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
centered
style={{ minHeight: `500px` }}
>

Use event handler to change button appearance

I would like to build out my functional component BoldButton in which when the user clicks either the lowercase a or uppercase A, the text of the button is changed to bold. Below is my work in progress.
import React, { useEffect, useState } from 'react';
const BoldButon = () => {
const [color, setColor] = useState("black")
useEffect(() => {
})
const changeColor = () => {
setColor("black")
}
return (
<div>
<button text={{style:color}} onClick={changeColor}>
A
</button>
<button text={{style:color}} onClick={changeColor}>
a
</button>
</div>
)
}
export default BoldButon;
This was one problem I had when doing a mock technical interview so I would like to know how to solve it when using a functional component. **Not sure if I need to utilize useEffect in order to solve this.
Currently, there are a few problems with syntax to address:
text={{style:color}} not sure what this is supposed to do: text is not a standard or custom prop that you have set anywhere on the button component. Also, say you were to change the color of the button's text (which you could do with style={{color}} then you would be able to change it from let's say black to gray or black to yellow for different emphasis, but you seemed to say that you wanted different font-weight (bold vs not bold) is controlled by the CSS property font-weight (and that can be set in HTML or JSX through the style property that all elements can have.
if you have nothing in useEffect probably you can/should get rid of it. useEffect is useful for if the state of something changes and you need a side effect you can put it there (or it can be used as a strange componentDidMount which will only run after all parents have had their useEffect run.
For something like this it might be better to use a class and then you can set a number of style properties with a single string: like is-emphasized is a commonly used class that can change the font-weight to 600 and the color to black from a dark gray (if necessary).
You probably want individual states for each individual button (as you want each button to be bold if it was clicked: it seems based on your question).
.is-emphasized {
font-weight: 600;
color: #000;
}
But if not the simplest fastest way to approach this is:
<button
style={{fontWeight: bold ? 'bold' : 'normal'}}
onClick={changeWeight}
>
A
</button>
<button
style={{fontWeight: !bold ? 'bold' : 'normal'}}
onClick={changeWeight}
>
a
</button>
function BoldButon() {
const [capitalABold, setCapitalABold] = React.useState(false)
const [aBold, setaBold] = React.useState(false);
const changeColor = () => {
setColor("black")
}
return (
<div>
<button
className={capitalABold ? 'is-emphasized' : ''}
onClick={() => setCapitalABold(!capitalABold)}
>
A
</button>
<button
className={aBold ? 'is-emphasized' : ''}
onClick={() => setaBold(!aBold)}
>
a
</button>
</div>
)
}
ReactDOM.render(<BoldButon/>, document.getElementById("root"));
* {
color: #333;
font-size: 14px;
}
.is-emphasized {
color: #000;
font-weight: 600;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You don't need useEffect for this kind of functionality, you can utilize the useState hook to manage the variable that determines if the user has clicked on the button. Also, you can use the useMemo hook to keep the style object which returns either bold or normal. Please note that the toggleBold toggles the font weight so if a user is clicking multiple times it will switch between the bold and normal.
import React, { useState, useMemo } from 'react';
const BoldButon = () => {
const [boldA, setBoldA] = useState(false)
const [boldB, setBoldB] = useState(false)
const toggleBold = (buttonType) => () => {
if(buttonType === 'firstButton') {
setBoldA(prevState => !prevState)
} else {
setBoldB(prevState => !prevState)
}
}
const buttonStyleA = useMemo(() => {
return {fontWeight: boldA ? 'bold' : 'normal'}
}, [boldA])
const buttonStyleB = useMemo(() => {
return {fontWeight: boldB ? 'bold' : 'normal'}
}, [boldB])
return (
<div>
<button style={buttonStyleA} onClick={toggleBold('firstButton')}>
A
</button>
<button style={buttonStyleB} onClick={toggleBold('secondButton')}>
B
</button>
</div>
)
}
export default BoldButon;

Dropdownlist alternative in material UI of react

I am currently using simple-menu of material UI as shown in the codesandbox here. In my react app, I am displaying this menu in a primereact dialog.
However, my main requirement is to display a dropdown list in a dialog so that when a user selects something, it can be selected and I can do something based on that.
For example, if a user selects Car, I can see it selected. Also, I have some values associated with each entries.
For example, Company has value 0,Car has value 1 and Office has value 2.
So I am planning to have some buttons in the dialog so that after an item from the list is selected, and Ok button is selected, I can send the value associated with the selected item in a webservice call.
The closest I could find is simplelist:
https://material-ui.com/components/lists/#simple-list
But nothing close to Drowpdown list. Am I missing on something here?
More info:
The dialog looks like this:
And let's say, when I select an item, let's say, Car, it won't show Car but will display Open Menu which I am not looking for.
What I have achieved is when the dropdown is opened and some option is selected then users can see what they have selected and dropdown doesn't close when some option is selected and in the console you can see what option is selected by index number.
You can follow this code:
import React, { useState } from "react";
import Button from "#material-ui/core/Button";
import Menu from "#material-ui/core/Menu";
import MenuItem from "#material-ui/core/MenuItem";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
maxWidth: 360,
backgroundColor: theme.palette.background.paper
}
}));
export default function SimpleMenu() {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [visval, setVisval] = useState("Open Menu");
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
//console.log(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const classes = useStyles();
const [selectedIndex, setSelectedIndex] = React.useState();
const handleListItemClick = (event, index) => {
setSelectedIndex(index);
handleClose();
//console.log(index);
if (index === 0) {
setVisval("Company");
} else if (index === 1) {
setVisval("Car");
} else {
setVisval("Office");
}
};
return (
<div>
<Button
aria-controls="simple-menu"
aria-haspopup="true"
onClick={handleClick}
>
{visval}
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem
data-my-value={1}
selected={selectedIndex === 0}
onClick={(event) => handleListItemClick(event, 0)}
>
Company
</MenuItem>
<MenuItem
data-my-value={2}
selected={selectedIndex === 1}
onClick={(event) => handleListItemClick(event, 1)}
>
Car
</MenuItem>
<MenuItem
data-my-value={3}
selected={selectedIndex === 2}
onClick={(event) => handleListItemClick(event, 2)}
>
Office
</MenuItem>
</Menu>
</div>
);
}
You can checkout the updated and working codesandbox here
EDIT :
I have achieved what you asked i.e, the menu showing the three options should close when we select some option and the same should be visible in the place of Open Menu. But what I saw is that the code is no longer reusable and is becoming too large (I was aware of it).
If you want your code to be minimised then follow the bellow suggestion
SUGGESTION :
I saw that Material-ui's autocomplete just does the work with a clean code.
It gives you a set of options like a dropdown menu and when the user select's something the selected option is seen by the user.
Link to the Working Demo
You can migrate the same code into your dialog's content it will work fine.

How can I reduce the number of buttons?

I need to have only one button doing two things one by one. I have two buttons "Обучить" and "Генерировать" and they both do something onClick. Is it possible to do it all with one button?
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={this.parseInput}
>
Обучить
</Button>
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={() => {
this.props.updateData(this.state.filterArray);
}}
>
Генерировать
</Button>
Of course you can. You can use a variable to decide what action you want to perform on onClick function
onClick={() => {
if(this.props.type == 'update')
this.props.updateData(this.state.filterArray);
else
this.parseInput()
}}
You can use same property type (or anything you like) to render different labels
{{this.props.type=='update'? 'Генерировать': 'Обучить'}}
I assume that you want to make a component reusable? In that case you might want to design your component like so.
const NewButton = ({onClick, children}) => (
<Button
variant="contained"
color="primary"
style={{
background: "linear-gradient(45deg, #00ACD3 30%, #00BE68)
}}
onClick={onClick}>
children
</Button>);
Then your above snip becomes
<NewButton onClick={someFunction}>Something</NewButton>
<NewButton onClick={otherFunction}>Something</NewButton>
This is the basic idea behind any component-based front-end framework and I suggest you go to the react tutorials to learn more.
Otherwise, there are plenty of good articles about the topic out there
If I understand you correctly, you want to use the same component but make them do different things, on click for example.
Here is an example of how you can do it.
import React from 'react';
const Button = ({onClick}) => {
return (
<button
onClick={onClick}
>
Click on me
</button>
)
}
export default Button;
So when you want to pass down a method to the button, you can do it like this.
import Button from './button';
clickerTicker() {
alert("First method, clickerticker");
}
secondaryClick() {
alert("Second method yo");
}
render() {
return (
<div>
<ButtonComponent onClick={this.clickerTicker.bind(this)}/>
<br/>
<ButtonComponent onClick={this.secondaryClick.bind(this)}/>
</div>
);
}
Just pass the onClick to the component

Resources