Trigger AntDesign (React) sider using custom button without this.state - reactjs

I'm using AntD Sider ... but I don't want to use the sider button which makes it pop out. I'm currently writing this entire thing in a function so I can't use this.state as specified in the antd docs examples.
const [collapsed, setcollapsed] = useState(false);
return (
<>
<Sider collapsible collapsed={collapsed} onCollapse={setcollapsed} collapsedWidth={0} reverseArrow>
<Menu>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
</Menu
</Sider
<Button shape="circle" style={styles.button} onClick={collapsed}>
<MenuOutlined />
</Button>
Is there a way to make this button trigger the sider? ^
unlike this ^[*]
<Sider collapsible collapsed={collapsed} onCollapse={setcollapsed} collapsedWidth={0} reverseArrow></Sider>
Code for [*]

Try this onClick handler please:
<Button shape="circle" style={styles.button} onClick={() => setcollapsed((prev) => !prev)}>
<MenuOutlined />
</Button>
And remove onCollapse from here
<Sider collapsible collapsed={collapsed} collapsedWidth={0} reverseArrow>
<Menu>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
<Menu.Item></Menu.Item>
</Menu
</Sider

Related

TypeError: Cannot set properties of undefined (setting 'hook')

TypeError: Cannot set properties of undefined (setting 'hook')
I am working on a Nextjs application but getting this error with antd library. I'm using the modal component and tooltip component which causes a re-render on open and close and spits out this error multiple times. Same goes for the tooltip when I mouse over it. Has anyone experienced this? and how did you fix it?. Answers appreciated!
import { Button, Modal, Tooltip } from 'antd';
const [isModalOpen, setIsModalOpen] = useState(false);
<div className="d-flex gap-2">
<Tooltip title="Edit">
<EditOutlined className="h5 pointer text-warning" />
</Tooltip>
<Tooltip title="Publish">
<CheckOutlined className="h5 pointer text-success ml-2" />
</Tooltip>
</div>
<Button
className="w-100"
onClick={() => setIsModalOpen(true)}
type="primary"
shape="round"
size="large"
icon={<UploadOutlined />}
>
Open modal
</Button>
<Modal
title="Modal title"
centered
open={isModalOpen}
onCancel={() => setIsModalOpen(false)}
footer={null}
>
<p>Some contents...</p>
</Modal>

How to programmatically expand a specific pannel in Ant design collapse

I want to expand a specific pannel of the Ant design collapse by clicking the next button it should expand the next panel. Here is the codesandbox link. Here is the screenshot of it as well.
You just need to save the key in state of panel that you want to open it. You want to open the second panel when button in first panel is clicked. You save that Panel key is state and need to pass that active key to Collapse as a prop.
const App: React.FC = () => {
const [activeKey, setActiveKey] = useState(1);
function handleClick(key) {
setActiveKey(key);
}
return (
<Collapse defaultActiveKey={["1"]} activeKey={activeKey} ghost>
<Panel header='This is panel header 1' key='1'>
<p>{text}</p>
<button onClick={() => handleClick("2")}>Next</button>
</Panel>
<Panel header='This is panel header 2' key='2'>
<p>{text}</p>
<button onClick={() => handleClick("3")}>Next</button>
</Panel>
<Panel header='This is panel header 3' key='3'>
<p>{text}</p>
</Panel>
</Collapse>
);
};
export default App;
Since you didn't provide specify whether it should close the existing panel or not. It does close the existing panel then above solution fines. But if you want to open multiple panels at a time then you need to change the code.
<Collapse activeKey={activeKey}>
You can activeKey as an array instead of string or number. In array you can pass any number of Panel keys like this: ['1', '2', ...].
Check the Antd Collapse API
I found a solution finally
const App: React.FC = () => {
const [activeKey, setActiveKey] = useState(['1']);
function handleClick(key) {
console.log(key)
setActiveKey(key);
}
return (
<Collapse
defaultActiveKey={["1"]}
activeKey={activeKey}
ghost
onChange={handleClick}
>
<Panel header="This is panel header 1" key="1">
<p>{text}</p>
<button value='2' onClick={(e) => handleClick(e.target.value)}>Next</button>
</Panel>
<Panel header="This is panel header 2" key="2">
<p>{text}</p>
<button value='3' onClick={(e) => handleClick(e.target.value)}>Next</button>
</Panel>
<Panel header="This is panel header 3" key="3">
<p>{text}</p>
</Panel>
</Collapse>
);
};
export default App;
Here is the codesandbox link

How to use custom isOpen with a chakra component

I am relatively new to react and not sure why isOpen is not working as expected.
Please see the code below for the example that I am working with
I have a menu icon that is using isOpen to open navlinks:
const { isOpen, onOpen, onClose } = useDisclosure();
<IconButton variant={"unstyled"} bgColor={"white"} color={"black"} size={"s"} icon={isOpen ? <Hamburger size={"24"} /> : <Hamburger size={"24"} />} aria-label={"Open Menu"} display={{ md: "none" }} onClick={isOpen ? onClose : onOpen} />
{isOpen ? (
<Box color={"#b8860b"} pb={4} display={{ md: "none" }}>
<Stack as={"nav"} spacing={5}>
{Links.map(link => (
<Link key={link.name} href={link.route}>
<Flex paddingBottom="40px" h="40px" borderBottom="1px" borderColor="black" justifyContent={'left'}>
<Flex paddingLeft={"10px"} paddingTop={"3%"}> {link.icon}</Flex>
<Text p={2} color={"black"} >
{link.name}
</Text>
</Flex>
</Link>
))}
</Stack>
</Box>
) : null}
When I try using a custom isOpen to open a drawer component, i just cant get it to work..
What am I doing wrong?:
const { isOpenMenu, onOpenMenu, onCloseMenu } = useDisclosure()
<Button
bgColor={"white"}
onClick={isOpenMenu}
>
<BsCart4 size={"26px"} color={"black"} />
{cartItemCount > 0 && <Badge ml='1' fontSize='0.9em' colorScheme='green'>{cartItemCount}</Badge>}
</Button>
<Drawer
isOpen={isOpenMenu}
placement='right'
onClose={onCloseMenu}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Create your account</DrawerHeader>
<DrawerBody>
<Input placeholder='Type here...' />
</DrawerBody>
<DrawerFooter>
<Button variant='outline' mr={3} onClick={onCloseMenu}>
Cancel
</Button>
<Button colorScheme='blue'>Save</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
When I use isOpen for the drawer it works fine so I thought having another isOpen but custom would open the drawer but its not working as expected.
Can someone help understand why my thinking isnt right based on how to use isOpen correctly?
It seems like only isOpen works when I switch it from using the menu bar and drawer
First of all, if you want to use custom names to the useDisclosure states, you have to set them like this:
const { isOpen: isOpenMenu, onOpen: onOpenMenu, onClose: onCloseMenu } = useDisclosure()
Also, the onClose prop of the drawer component is just a event handler, dont put your onCloseMenu function ther, just call it when you want to close the drawer, as you made on the cancel button, example:
<Button onClick={onCloseMenu} ... />

Is there a way to use <Collapse> as my Transition component while using the <Popper> component to display a Menu onHover?

The following question is regarding React and Material-UI:
I am trying to use the <Collapse> transition component when displaying my <Menu> onMouseEnter. However, there seems to be an issue in the Material-UI library when it comes to the way the <Collapse> component and the <Popper> / <Popover> component. The issue is currently open and can be seen here.
Has anyone found a good workaround for this? Basically, I am just hoping to have a subnav Menu appear when you hover over a link with this specific transition.
I have tried using the <Grow> component and the transition works just fine, but we specifically are trying to use the <Collapse> transition.
export const NavBarItem = ({ navItem }) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
function handleToggle() {
setOpen(prevOpen => !prevOpen);
}
function handleClose(event) {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
}
return (
<React.Fragment>
<Link className={classes.link} href={BASE_HOMEPAGE + navItem.path}>
<Typography
className={classes.title}
ref={anchorRef}
aria-controls="menu-list-grow"
aria-haspopup="true"
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
>
{navItem.title}
</Typography>
</Link>
<Popper
open={open}
anchorEl={anchorRef.current}
onMouseEnter={handleToggle}
onMouseLeave={handleToggle}
transition
disablePortal
placement="bottom-start"
>
<Collapse in={open}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={handleClose}>
<MenuList className={classes.paperMenu}>
{navItem.menuItems.map(item => (
<Link
className={classes.link}
href={
item.external ? item.path : BASE_HOMEPAGE + item.path
}
>
<MenuItem
className={classes.paperMenuItem}
onClick={handleClose}
>
{item.text}
</MenuItem>
</Link>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Collapse>
</Popper>
</React.Fragment>
);
};
The code shown above is for a specific NavItem in a NavComponent. It is essentially just a dropdown component to show a subnav when you hover over a specific link.
Thank you for your help and please let me know if you need anymore additional information.
You can try to use the TransitionProps given by the Popper when using the transition props, as shown in the documentation
<Popper id={id} open={open} anchorEl={anchorEl} transition>
{({ TransitionProps }) => (
<Fade {...TransitionProps} timeout={350}>
<div className={classes.paper}>The content of the Popper.</div>
</Fade>
)}
</Popper>
For smoother UI you can also use the keepMounted property in Popper:
<Popper id={id} open={open} anchorEl={anchorEl} transition keepMounted>

how do i open only one panel when I use mapping in react for panels

I have created a panel to map through my users and display their songs below their name.
The problem im having is that when I click on the {username} it opens all of the accordion panels. I'd like it to only open the accordion for the panel being clicked.
<PanelGroup accordion id="accordion-example">
{this.state.allUsersList.map((user, index) => (
<Panel>
<Panel.Heading>
<Panel.Title toggle >
<Button key={index} className="btn-uvideo">{user.Username}</Button>
</Panel.Title>
</Panel.Heading>
<Panel.Body collapsible>
<ListGroup>
{user.songs.map((song, index) => (
<ListGroupItem key={index}>
<Button className="btn-video" onClick={() => this.handleSongChange(song)}>
<p>{song.SongName}</p>
</Button>
</ListGroupItem>
))}
</ListGroup>
</Panel.Body>
</Panel>
))}
</PanelGroup>
I'm assuming you're using React-Bootstrap. Looks like you're missing eventKey:
A unique identifier for the Component, the eventKey makes it distinguishable from others in a set. Similar to React's key prop, in that it only needs to be unique amoungst the Components siblings, not globally.
https://react-bootstrap.github.io/components/panel/#panels-accordion
<PanelGroup accordion id="accordion-example">
<Panel eventKey="1">
...
</Panel>
<Panel eventKey="2">
...
</Panel>
<Panel eventKey="3">
...
</Panel>
</PanelGroup>
Assuming your usernames are unique you can use that value for your eventKey:
<PanelGroup accordion id="accordion-example">
{this.state.allUsersList.map((user, index) => (
<Panel eventKey={user.Username}>
...

Resources