I want to get the scroll position and move it - reactjs

I'm using react and Typescript.
When I press a Button, I want to go to the next button.
For example, when I press a Button in the blue Box component, I want it to go to the red Box component below. Also, I don't want to use the a tag.I've been using codesandbox to implement this, but I can't figure out how to move the scrolling position.
https://codesandbox.io/s/eloquent-dust-ikdv1?file=/src/index.tsx

Just use anchors for jumping:
<Box height="400px" background="blue.100">
<Button></Button>
</Box>
<Box height="400px" background="red.100" id="red">
<Button></Button>
</Box>
And if you want smooth scrolling (proudly stolen from #Joseph Silber's answer):
const onClick = (e: any) => {
document.querySelector(e).scrollIntoView({
behavior: "smooth"
});
};
return (
<Box>
<Box height="400px" background="blue.100">
<Button onClick={(e) => onClick("#red")}></Button>
</Box>
<Box height="400px" background="red.100" id="red">
<Button></Button>
</Box>

Maybe you can use id but not sure what you are trying to achieve. Try this:
<Box height="400px" background="blue.100">
<Button as="a" href="#red"></Button>
</Box>
<Box height="400px" background="red.100">
<Button id="red"></Button>
</Box>
In this way you wont need to maintain ref.

Related

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} ... />

Adding Dynamic States to React JS project

I am creating an emojipedia app where it is expected to open a Modal, which contains the description of the emoji, when an emoji is pressed. As far as I know, to do so, I need to map the description(contained in emojipedia.js file) of the emoji to the EmojiContainer component in Components folder.
Here comes my problem where when I press a emoji, it is getting hanged. Why is this happening and how to fix this???
THANKS IN ADVANCE.
You are using a single state on EmojiContainer to control all modals in your emoji list. As a consequence, when you try and open a modal, all modals open. A better option would be to encapsulate all logic relative to a single modal in a separate, reusable component:
export default function Emoji({ item }) {
const [open, setOpen] = useState(false);
return (
<Grid item lg={2} md={3} xs={6}>
<ImageButton onClick={() => setOpen(true)}>
<CardMedia
sx={{
"&:hover": {
transform: "scale(1.3)"
}
}}
component="img"
height="100"
image={item.link}
alt="emoji"
/>
</ImageButton>
<Modal
open={open}
onClose={() => setOpen(false)}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Typography sx={style} variant="p">
{item.desc}
</Typography>
</Modal>
</Grid>
);
}
As you see this component has its own state and controls its own modal. In your EmojiContainer you can use it like this:
export default function EmojiContainer() {
return (
<Grid>
{emojipedia.map((item, index) => (
<Grid key={index} container>
<Emoji item={item} />
</Grid>
))}
</Grid>
);
}
From what I see you'll also need to adjust the modal styling. Here's the updated codesandbox

How to make the Collapse position to bottom-right after clicking on expand icon in AntD

I am using AntD Collapse for displaying a list of items after expand icon is clicked.
I want the position of expandIcon to go to bottom-right after all the list of the data when expand icon is clicked (just like in google news), but found only two options (left|right) for 'expandIconPosition', no option for top or bottom.
How can we align the expandIcon to bottom-right, when expand icon is clicked?
Few lines from the code for reference:
<Collapse
ghost
style={{ marginTop: "-1vh" }}
expandIcon={({ isActive }) => (
<DownOutlined
style={{ marginTop: "-2vh" }}
rotate={isActive ? 180 : 0}
/>
)}
expandIconPosition="right"
>
<Panel>
<div>
{list()} //list of items
</div>
</Panel>
</Collapse>
Here's one possible solution. Make Collapse a controlled component by specifying activeKey prop and then the value of it will be based on state. Then, by tracking the activeKeys state you can now do a conditional rendering (hide and show) on icons:
const [activePanelKeys, setActivePanelKeys] = useState([]);
const handlePanelIconClick = (panelKey, makeActive) => {
if (makeActive) {
setActivePanelKeys([...activePanelKeys, panelKey]);
} else {
setActivePanelKeys(activePanelKeys.filter((aPK) => aPK !== panelKey));
}
};
<Collapse
activeKey={activePanelKeys}
expandIconPosition="right"
expandIcon={() => <DownOutlined />}
// expandIcon={(panelProps) => (
// <DownOutlined
// onClick={() => handlePanelIconClick(panelProps.panelKey, true)}
// />
// )}
onChange={e => setActivePanelKeys(e)} //if you want to click only icon, comment this and uncomment the above expandedIcon
>
<Panel
header="This is panel header 1"
key="p1"
showArrow={activePanelKeys.indexOf("p1") === -1}
>
<div>{text}</div>
{activePanelKeys.indexOf("p1") !== -1 && (
<div style={{ textAlign: "right", marginTop: 10 }}>
<UpOutlined onClick={() => handlePanelIconClick("p1", false)} />
</div>
)}
</Panel>
{/* <PanelContent header="This is panel header 2" key="p2">
{text}
</PanelContent> */}
</Collapse>;
Here is the complete sample code:
Note: I tried to make a reusable Panel component but it seems that the reveal animation were gone. You can uncomment the commented PanelContent on the code to see the difference.
Hope that I hit what you want.

Google map does not shrink when user opens sidebar

I am new to both React and Grommet and have worked through the getting started tutorial. When I add a google map to the main container it renders and fills the whole screen. However, when I click the notification icon to load the sidebar it only renders in a tiny column on the side. Is there a way for me to edit the style to adjust the width automatically or do I need to have the container width as a property that changes when the button is clicked? (Please excuse any question format errors as this is my first post.)
I have tried looking through the Grommet box props and various CSS style settings without success.
App.js:
const { showSidebar } = this.state;
return (
<Grommet theme={theme} full>
<ResponsiveContext.Consumer>
{size => (
...
<Box direction='row' flex overflow={{ horizontal: 'hidden' }}>
<Box
align='start'
justify='start'
fill='horizontal'
responsive='true'
>
<MapContainer />
</Box>
{!showSidebar || size !== 'small' ? (
<Collapsible direction='horizontal' open={showSidebar}>
<Box
flex
width='medium'
background='light-2'
elevation='small'
align='center'
justify='center'
>
sidebar
</Box>
</Collapsible>
) : (
...
}
</Box>
</Box>
)}
</ResponsiveContext.Consumer>
</Grommet>
);
MapContainer.js:
return (
<Map google={this.props.google} zoom={14}/>
);
I would like the map to shrink to fill the container/the container to shrink when the sidebar loads.

Opening Unique modal or popper based on button click

I am using material-ui library where I have a popper inside a loop each loop has one event object stored in cards. I want to open popper based on button click which is placed on each cards but all the popper gets opened since on button click I am setting 'open' state as true. I want to make this value unique for each popper so that I set the value for that popper which needs to be opened.
I tried to make open as unique but don't know how.
this.state = {
open: false,
}
handleClickButton = event => {
console.log(event.target)
this.setState(state => ({
open: !state.open,
}));
};
Here is the render method code:
{this.props.events.map((event) =>
(
<Card>
<CardContent>
<Typography variant="h5" component="h2">
{event.completionIntent.toUpperCase()}
</Typography>
<Typography color="textSecondary" gutterBottom>
<span><FontAwesomeIcon icon="clock"/></span>
</Typography>
<Typography component="p">
{event.eventTime}
<br />
</Typography>
</CardContent>
<CardActions>
<Link href={event.audio?"":null} style={{color:event.audio?'#3f51b5':'#bdbdbd', fontSize:'12px',}}
underline="none"
>
Download Audio
</Link>
<Button
id={event.completionIntent+'Button'}
buttonRef={node => {
this.anchorEl = node;
}}
variant="contained"
onClick={this.handleClickButton}
aria-describedby={event.completionIntent}
title="Send"
style={{backgroundColor:!event.audio && '#3f51b5',color:'#eeeeee',padding:'2px 0px', marginLeft:'14px', }}
disabled={event.audio}
>
Send
<Send className={classes.rightIcon}/>
</Button>
<Popper
id={event.completionIntent}
open={open}
anchorEl={this.anchorEl}
placement='bottom'
disablePortal={false}
className={classes.popper}
modifiers={{
preventOverflow: {
enabled: false,
boundariesElement:'scrollParent'
},
}}
>
<Paper className={classes.paper}>
<DialogTitle>{"Manual Task Updation"}</DialogTitle>
<DialogContent>
<DialogContentText>
Are you sure you want to update {event.completionIntent.toUpperCase()}?
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClickButton} color="primary">
Disagree
</Button>
<Button onClick={this.handleClickButton} color="primary">
Agree
</Button>
</DialogActions>
</Paper>
</Popper>
</CardActions>
</Card>
</div>
))}
I want to open the popper only for one card where I clicked the button since open state variable is same for all popper then all popper gets opened. How to make it unique
It maybe too late, but i hope it will help someone out there.
You can use dom manipulation to do that.
In your button handler, set unique id:
<Button
...
onClick={() => this.handleClickButton(some-unique-id)}
...
>
...
</Button>
And then in your popper state:
<Popper
...
open={open[some-unique-id]}
...
>
...
</Popper>
And finally change your handler:
handleClickButton = (event,some-unique-id) => {
...
this.setState({
open: {
[some-unique-id]: true
}
});
};
Instead of making unique open values for all possible cards. It would be a better and simpler solution to make the card implementation as a seperate component. Each card would then have its own state, and you would only need one open value to handle the popper, thus seperating concerns.
So move the card into a seperate component, design some props that handles the data you need to pass down from the parent component, something like this:
{
this.props.events.map((event) =>
(<MyCustomCardImplementation key={someUniqueProperty {...myCustomCardProps} />)
}

Resources