React Boostrap NavDropdown.Item closes modal when NavBar is closed - javascript

Hello i'm trying to open a Modal upon NavDropdown.Item click that is inside a NavBar,
If I do something like this
import { useState } from "react";
import { rockPositions } from "../../constant/markers"
import { CloseButton, NavDropdown, Alert } from "react-bootstrap";
import Modal from 'react-modal/lib/components/Modal';
import { RouteBadge } from "../RouteBadge/RouteBadge";
import { RouteTable } from "../RouteTable/RouteTable";
import { modalStyle } from '../RockModalMarker/RockModalMarker.css.js';
const RockDropDownModal = (props) => {
const [isOpen, setIsOpen] = useState(false);
const route = props.route;
const rock = rockPositions.find(rockPosition => rockPosition.name === route.rock);
const index = props.rockIndex;
const toggleModal = (e) => {
setIsOpen(!isOpen);
};
if (!isOpen) {
return (
<NavDropdown.Item key={index} href="#rock" onClick={toggleModal}><span className={"rock-name-dropdown"}>{route.rock}</span>: {route.name}</NavDropdown.Item>
)
}
return (
<Modal key={index}
defaultStyles={modalStyle}
isOpen={isOpen}
onRequestClose={toggleModal}
centered
ariaHideApp={false}
>
<CloseButton variant="white" onClick={toggleModal} />
<Alert variant="primary" style={{ marginTop: "20px", backgroundColor: "#01579B", borderColor: "#0277BD" }}>
<Alert.Heading style={{ color: "#FFF" }}><p className="routeName">{rock.name}</p></Alert.Heading>
</Alert>
<RouteBadge rock={rock} />
<RouteTable rock={rock} />
</Modal>
)
}
export { RockDropDownModal };
the modal opens fine but it's behind the NavBar and if I close the navbar the modal closes too.
I was trying to close the navbar and only show the modal but and I wrap the dropdown item like this
<Navbar.Toggle>
<NavDropdown.Item key={index} href="#rock" onClick={toggleModal}><span className={"rock-name-dropdown"}>{route.rock}</span>: {route.name}</NavDropdown.Item>
</Navbar.Toggle>
it closes the Navbar but also the Modal.
In the screenshot here you can see the NavBar, when the selected item is clicked the Modal should open and the navbar close.
How can I prevent the Modal from closing?

If one of the main problems here is that the navbar overlaps the modal, have you tried setting the z-index of the modal to a greater value? This would set the modal above the navbar and upon closing the modal, it will also close the navbar as well.
In addition to this, try to play around with expanded property of Navbar. You could create a state inside Navbar
const [isExpanded, setIsExpanded] = useState(`default_boolean_value`)
<Navbar expanded={isExpanded}/>
where-in upon clicking a dropdown item inside the child component, you could set the state of the Navbar to expanded=false
here is the documentation, you can find expanded prop here https://react-bootstrap.github.io/components/navbar/

Related

React Version 18 - How to reset a button to disabled soon as I click cancel on a modal using TextFields?

New to React.
How to reset a button back to initial state of disabled soon as I click cancel on a modal.
I have this dialog here. Soon as you click a button it will open up this dialog. The dialog has the ADJUST button disabled until you make write text in the input. It will set the adjust state upon onChange. Soon as you click cancel or click out of the modal and go back, the state is still being set as ADJUST as NOT disabled.
How do I make the button disabled when leaving the dialog?
Example:
import React, { useState } from "react";
import {
Button,
Dialog,
DialogContent,
DialogTitle,
MenuItem,
TextField,
} from "#mui/material";
const testDialog = (props) => {
const [open, setOpen] = useState(false);
const [adjust, setAdjust] = useState("");
const handleClose = () => {
setOpen(false);
setAdjust("");
};
const handleAdjustments = (event) => {
setAdjust(event.target.value);
};
return (
<div>
<Dialog
fullWidth
open={props.boxOpen}
onClose={props.handleClose}
>
<DialogTitle>
Test
</DialogTitle>
<DialogContent>
<div>
<div>
<TextField
sx={{
label: { fontSize: 13 },
input: { paddingTop: 1, paddingBottom: 2 },
}}
size="medium"
fullWidth
required
id="countProducts"
label="Count of products"
variant="outlined"
onChange={handleAdjustments}
/>
</div>
</DialogContent>
<div>
<Button onClick={props.handleClose}>CANCEL</Button>
<Button disabled={!adjust}>ADJUST</Button>
</div>
</Dialog>
</div>
);
};
export default testDialog;
I expect to always see the dialog button ADJUST as disabled soon as I leave and open the dialog page. if I try to do input in textfield, the button will turn orange. Once I click cancel or I click out of the dialog, the button will go back to disabled.
You're never calling handleClose() or using the open state. If props.boxOpen and props.handleClose control the visibility, you don't even appear to need a local open state.
What you can do is use your local handleClose() to modify the adjust state and call through to props.handleClose()
const handleClose = () => {
setAdjust("");
props.handleClose();
};
with
<Dialog
fullWidth
open={props.boxOpen}
onClose={handleClose}
>

Open Modal in fullscreen

Is there a way to open a modal which will take entire screen just like in youtube video when you click on it's fullscreen it takes the entire screen view.
Right now this is what i have achieved so far
<Modal
title={false}
visible={visible}
footer={false}
centered
width="100vw"
onCancel={() => setVisible(false)}
>
<div style={{height: '100vh'}}>
some content
</div>
</Modal>
and this is how it looks like
i want it to look like this
With pure JavaScript you can do something like
const modal = document.querySelector('#myModalsClass')
modal.requestFullscreen()
If you look up the docs for the fullscreen API you will find other useful information about how to work with this.
If you're using React you need to use a ref to access the dom api
import React, { useRef } from "react";
const MyComponent = (props) => {
const myFullscreenComponent = useRef();
const openContentFullscreen = () => {
const element = myFullscreenComponent.current;
if (element && element.requestFullscreen) {
element.requestFullscreen();
}
};
return (
<div>
<button onClick={openContentFullscreen}>Full Screen</button>
<div className="modal" ref={myFullscreenComponent}>
content I want to be fullscreen
</div>
</div>
);
};
id recommend to use mui full-screen modal Here the link https://mui.com/material-ui/react-dialog/
let me know if you need any help
Check the following example
Note: set footer={null} if you want to hide OK and CANCEL buttons
App.js
import React, { useState } from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Button, Modal } from 'antd';
const App = () => {
const [visible, setVisible] = useState(false);
return (
<>
<Button type="primary" onClick={() => setVisible(true)}>
Open Full screen Modal
</Button>
<Modal
title="Full screen modal"
visible={visible}
//onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
footer={null} //If you want to hide OK and cancel buttons
>
<p>Full screen...</p>
<p>Full screen...</p>
<p>Full screen...</p>
<p>Full screen...</p>
<p>Full screen...</p>
</Modal>
</>
);
};
export default App;
index.css
.ant-modal,
.ant-modal-content {
height: 100vh;
width: 100vw;
top: 0;
margin: 0;
}
Screenshot
Demo

ClickAwayListener not working with Collapse or Fade transitions

I'm trying to create a notifications area. I show a notification icon, and when the user clicks on it, I show the list of notifications.
Here's a codesandbox
The problem is that I can't mix it with ClickAwayListener.
When I use ClickAwayListener it's not shown at all.
How should I fix this?
HeaderAction.js
import Tooltip from "#material-ui/core/Tooltip";
import Fade from "#material-ui/core/Fade";
import Collapse from "#material-ui/core/Collapse";
import React, { useState } from "react";
import ClickAwayListener from "#material-ui/core/ClickAwayListener";
import Icon from "#material-ui/core/Icon";
const HeaderAction = ({ icon, title, component }) => {
const Component = component || (() => <div>NA</div>);
const [showComponent, setShowComponent] = useState(false);
const handleClick = () => {
setShowComponent(!showComponent);
};
return (
<>
<Tooltip title={title || ""}>
<div onClick={() => handleClick()}>
<Icon>{icon}</Icon>
</div>
</Tooltip>
{/* This part is not working */}
{/* <ClickAwayListener onClickAway={() => setShowComponent(false)}>
<div>
<Fade in={showComponent}>
<div>
<Component />
</div>
</Fade>
</div>
</ClickAwayListener> */}
<Fade in={showComponent}>
<div>
<Component />
</div>
</Fade>
</>
);
};
export { HeaderAction };
When you click the icon button, handleClick is called and the showComponent state is set to true, but then onClickAway from ClickAwayListener is also called and set the showComponent state to false again. The fix is simple, don't let the onClickAway handler execute by stopping the propagation after clicking the button:
<div
onClick={(e) => {
e.stopPropagation();
handleClick();
}}
>

Is there a way to make chakra ui MenuList items always visible

I am using Chakra UI to create a menu. I have something like this:
<Menu>
<MenuButton>hover over this</MenuButton>
<MenuList>
<Flex>To show/hide this</Flex>
</MenuList>
</Menu>
I am trying to dynamically open the tag on hover. The MenuList default is to open on user click. When I click on the button and then hover over it, my hover state works. I am trying to figure out a way so that the user does not have to click on the MenuButton for hovering over it to work.
Adding on to Bassem's answer. We can add onMouseEnter and onMouseLeave to the menu list so that it doesn't close when we leave the button.
import React from "react";
import {
Flex,
MenuItem,
Menu,
MenuButton,
MenuList,
Button,
useDisclosure
} from "#chakra-ui/react";
export default function App() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<div className="App">
<Flex height="100vh" align="center" justifyContent="center" bg="gray.100">
<Menu isOpen={isOpen}>
<MenuButton
as={Button}
variant="solid"
colorScheme="teal"
onMouseEnter={onOpen}
onMouseLeave={onClose}
>
Hover Me
</MenuButton>
<MenuList onMouseEnter={onOpen} onMouseLeave={onClose}>
<MenuItem>Download</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuItem>Delete</MenuItem>
<MenuItem>Attend a Workshop</MenuItem>
</MenuList>
</Menu>
</Flex>
</div>
);
}
You can read more here https://www.coffeeclass.io/snippets/use-disclosure-menu-chakra-ui
For that you can use some event listeners: onMouseEnter & onMouseLeave together with useDisclosure hook that can be used to handle Menu open, close, and toggle.
import React from "react";
import {
Flex,
MenuItem,
Menu,
MenuButton,
MenuList,
Button,
useDisclosure
} from "#chakra-ui/react";
export default function App() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<div className="App">
<Flex height="100vh" align="center" justifyContent="center" bg="gray.100">
<Menu isOpen={isOpen}>
<MenuButton
as={Button}
variant="solid"
colorScheme="teal"
onMouseEnter={onOpen}
onMouseLeave={onClose}
>
Hover Me
</MenuButton>
<MenuList>
<MenuItem>Download</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuItem>Delete</MenuItem>
<MenuItem>Attend a Workshop</MenuItem>
</MenuList>
</Menu>
</Flex>
</div>
);
}
And here is a working CodeSandbox.
import React, { useRef, useState } from "react";
import { Menu, MenuButton, MenuItem, MenuList } from "#chakra-ui/menu";
import { Button } from "#chakra-ui/button";
// TODO: dynamic button text and items
const PopupNavItem = () => {
const timerRef = useRef();
const [isOpenMenu, setIsOpenMenu] = useState(false);
// menu list pops up automatically when cursor hovers over the button,
const btnMouseEnterEvent = () => {
setIsOpenMenu(true);
};
//,and vice versa,
const btnMouseLeaveEvent = () => {
// async
timerRef.current = window.setTimeout(() => {
setIsOpenMenu(false);
}, 150);
};
// when the cursor moves away from the button but entering the menu list,the menu list stays open
const menuListMouseEnterEvent = () => {
// when entered, the timer has been cleared
clearTimeout(timerRef.current);
timerRef.current = undefined;
setIsOpenMenu(true);
};
// finally, when the cursor moves away from the menu list, menu list closes
const menuListMouseLeaveEvent = () => {
setIsOpenMenu(false);
};
return (
<Menu isOpen={isOpenMenu} id={1}>
<MenuButton
as={Button}
variant="solid"
colorScheme="teal"
onMouseEnter={btnMouseEnterEvent}
onMouseLeave={btnMouseLeaveEvent}
>
Hover Me
</MenuButton>
<MenuList
onMouseEnter={menuListMouseEnterEvent}
onMouseLeave={menuListMouseLeaveEvent}
>
<MenuItem>Download</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuItem>Delete</MenuItem>
<MenuItem>Attend a Workshop</MenuItem>
</MenuList>
</Menu>
);
};
export default PopupNavItem;
For anyone having a hard time with hover rather than click, maybe you can try this one

OverlayTrigger Tooltip Not Showing

Created codesandbox to show issue:
https://codesandbox.io/s/agitated-https-2xjs2?fontsize=14&hidenavigation=1&theme=dark
I'm wanting a Tooltip to show whenever I'm hovering over a card. I need to pass in a value from the OverlayTrigger to the Tooltip component. With the following code, nothing is showing when hovering over a card:
Character.js:
import React from 'react'
import { Card, OverlayTrigger } from 'react-bootstrap'
import Infott from '../components/Infott'
const Character = ({ character }) => {
return (
<OverlayTrigger
trigger='hover'
placement='bottom'
overlay={<Infott test={'Test'} />}
>
<Card className='my-3 py-3 rounded'>
<a href={`/character/${character._id}`}>
<Card.Img src={character.image} />
</a>
</Card>
</OverlayTrigger>
)
}
export default Character
Infott.js:
import React from 'react'
import { Tooltip } from 'react-bootstrap'
const Infott = ({ test }) => {
return (
<Tooltip id='character-tooltip' placement='bottom'>
<strong>{test}</strong>
</Tooltip>
)
}
export default Infott
If I add className=show to the Tooltip component, it will show and the test value is passed, but it's no longer placed next to the card but rather the bottom left of the webpage. My guess is the OverlayTrigger and Tooltip are not on the same page.
I can get the Tooltip placement showing and in the correct placement if I change overlay to overlay={Infott} and then change my Tooltip component to
const Infott = (props) => {
return (
<Tooltip id='character-tooltip' placement='bottom' {...props}>
<strong>{test}</strong>
</Tooltip>
)
}
But then I'm not able to pass the test value that I need.
OverlayTrigger seems to use ref to the target Tooltip for some actions as well as some properties that it injects so in order to work properly you must forward a ref from your custom component to the target Tooltip you have wrapped inside.
So the correct solution for having your Tooltip wrapped in a custom component should be something like:
const Infott = React.forwardRef(({test, ...props}, ref) => {
return (
<Tooltip id='character-tooltip' ref={ref} placement='bottom' {...props}>
<strong>{test}</strong>
</Tooltip>
);
});

Categories

Resources