Menu's dropdown on Chart is being offset - reactjs

I'm adding a chakra-ui menu dropdown button to a chart (from react-financial-charts, which is a library built over svg).
For some reason, when I click on the menu, there will be whitespace between the button and the dropdown menu. This only happens when I put the menu onto the chart. If I have the menu standalone in the browser, it'll work as expected.
This is the menu code:
function TestMenu() {
return (
<g className="react-financial-charts-enable-interaction">
<foreignObject
x={30}
y={30}
width={"100%"}
height={"100%"}
style={{ overflow: "auto" }}
>
<Menu>
<MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
Actions
</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>
</foreignObject>
</g>
);
}
This is the full codesandbox:
https://codesandbox.io/s/nervous-haze-3mz2c?file=/src/BasicLineSeries.tsx:511-1199
EDIT
If I remove x={0} and y={0} from foreignObject and include style={{ marginTop: "30px", marginLeft: "30px" }} into MenuButton instead, as suggested by one of the answers, this will solve the problem only if the chart is at the top of the page. Otherwise, if there is a div before the chart, then this will occur:
and here's the full codesandbox for that:
https://codesandbox.io/s/nostalgic-pare-c5rxu?file=/src/BasicLineSeries.tsx

UPDATED
According to the menu list position problem, you can make use of Portal to move the entire list options to the bottom of the DOM so that its style will not be affected by any style/component inside the Chart.
...
<Menu>
<MenuButton
as={Button}
rightIcon={<ChevronDownIcon />}
transition="all 0.001s"
borderRadius="md"
borderWidth="0px"
_hover={{ bg: "gray.400" }}
_expanded={{ bg: "blue.400" }}
_focus={{ boxShadow: "none" }}
style={{ marginTop: "30px", marginLeft: "30px" }} // better move the style to css file
>
Actions
</MenuButton>
<Portal>
<MenuList zIndex={10}>
<MenuItem>Download</MenuItem>
<MenuItem>Create a Copy</MenuItem>
<MenuItem>Mark as Draft</MenuItem>
<MenuItem>Delete</MenuItem>
<MenuItem>Attend a Workshop</MenuItem>
</MenuList>
</Portal>
</Menu>
...
The Updated Codesandbox
The white space is triggered by the foreignObject's x and y where the MenuList is respecting the space specified in foreignObject. (You can try to increase x and y, you will see a larger gap between the button and menu list)
To solve the problem, you can remove the x and y and apply the margin on MenuButton
...
<foreignObject
width={"100%"}
height={"100%"}
style={{ overflow: "auto" }}
>
<Menu>
<MenuButton
as={Button}
rightIcon={<ChevronDownIcon />}
transition="all 0.001s"
borderRadius="md"
borderWidth="0px"
_hover={{ bg: "gray.400" }}
_expanded={{ bg: "blue.400" }}
_focus={{ boxShadow: "none" }}
style={{ marginTop: "30px", marginLeft: "30px" }} // better move the style to css file
>
Actions
</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>
</foreignObject>
...
Here is the modified codesandbox

Related

Is there any way to use re-resizable in the MUI material popover?

I am trying to use the re-resizable resizable to change the size of the popover but it is not working, is it impossible? and if so is there another way to resize the popover?
return (
<Resizable>
<Popover
open={!isStoredTabsNull()}
onClose={handleClose}
anchorEl={anchorEl}>
<Paper
style={{
backgroundColor: DefaultStyle.backgroundColor,
overflow: 'auto'}}>
{ storedTabs?.map((tabsGroup) => (
<StoredTabsItem
key={tabsGroup.id}
storedTabsGroup={tabsGroup}
projectFolder={projectFolder}
openFiles={openFiles}
overwriteState={overwriteState}
tabs={tabs}
/>
))}
</Paper>
</Popover>
</Resizable>
)
TL;DR
In a nutshell, wrap your Popover content (children) in <Resizable>, and not the Popover itself, to make it re-size.
Explanation
Yes, it is possible to resize an MUI Popover with re-resizable. Like the underlying Modal component, Popover's sizing is driven, by default, by its content. Adding a child[ren] wrapped in Resizable will give you the ability to resize the Popover. For example:
<Popover
open={!isStoredTabsNull()}
onClose={handleClose}
anchorEl={anchorEl}
anchorOrigin={{
vertical: "bottom",
horizontal: "left"
}}
>
<Paper
style={{
backgroundColor: DefaultStyle.backgroundColor,
overflow: "auto"
}}
>
<Resizable>
{storedTabs?.map((tabsGroup) => (
<StoredTabsItem
key={tabsGroup.id}
storedTabsGroup={tabsGroup}
projectFolder={projectFolder}
openFiles={openFiles}
overwriteState={overwriteState}
tabs={tabs}
/>
))}
</Resizable>
</Paper>
</Popover>
(In this example using your code, I added Resizable inside of Paper because Paper also gets its height from its content, unless otherwise defined.)
Which will result in:
Working CodeSandbox: https://codesandbox.io/s/mui-popover-with-re-resizeable-forked-t96dko?file=/demo.js
After some digging I found a different way. If anyone else is looking for a simpler answer that doesn't require to install another library you can use the CSS property resize (both meaning: "The element displays a mechanism for allowing the user to resize it, which may be resized both horizontally and vertically."(Source:developer.mozilla.org)
return (
<Popover
open={!isStoredTabsNull()}
onClose={handleClose}
anchorEl={anchorEl}>
<Paper
style={{
backgroundColor: DefaultStyle.backgroundColor,
overflow: 'auto',
resize: "both",
}}>
{ storedTabs?.map((tabsGroup) => (
<StoredTabsItem
key={tabsGroup.id}
storedTabsGroup={tabsGroup}
projectFolder={projectFolder}
openFiles={openFiles}
overwriteState={overwriteState}
tabs={tabs}
/>
))}
</Paper>
</Popover>
)
You can use "PaperProps" to give height and width like this. No need to use Resizeable.
<Popover
open={!isStoredTabsNull()}
onClose={handleClose}
anchorEl={anchorEl}
PaperProps={{
style: { width: 400, height: 400 },
}}
>
<Paper
style={{
backgroundColor: DefaultStyle.backgroundColor,
overflow: "auto",
}}
>
{storedTabs?.map((tabsGroup) => (
<StoredTabsItem
key={tabsGroup.id}
storedTabsGroup={tabsGroup}
projectFolder={projectFolder}
openFiles={openFiles}
overwriteState={overwriteState}
tabs={tabs}
/>
))}
</Paper>
</Popover>;

React DnD draggable ListItem won't stay inline

I'm trying to make ListItems inside a List draggable without changing too much structure, it seems to work but the styling is very off:
The icons and its names should be on one line but for some reason the <ListItemText> keeps being shoved into the next line when it shouldn't be. Here's my draggable code:
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable" direction="vertical">
{(provided) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
>
{menuList.map((text, index) => (
<Draggable key={text} draggableId={text} index={index}>
{(provided) => (
<ListItem key={text} disablePadding}}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}>
<IconButton id={text} onClick={handleFav} disableRipple sx={{
minWidth: 0,
maxWidth: 1,
mr: 1,
justifyContent: 'center',
}}>
<StarRateRoundedIcon/>
</IconButton>
<IconButton sx={{ padding: 0, mr: 1 }}>
<VisibilityIcon sx={{ position: 'relative', verticalAlign: 'bottom', bottom: 1, color: '#00417d' }} />
</IconButton>
<ListItemText primary={text} sx={{ width: '16px', margin: 0 }} />
</ListItem>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
I did something similar for table cells and the items were inline, but this one isn't. I've tried setting the ListItem iteself to inline but that didn't seem to fix it. It seems that there's a div that either belongs to the draggable or the listitem itself that isn't the right size, but I can't tell which one:
The ListItemText component was causing it to wrap into its own line. I couldn't find a way to stop the component itself so I decided to just ditch it for a normal typography component, it now looks like how I want:
If anyone knows how to achieve the same but with a normal ListItemText I'd also love to know. This is how I got around it with Typography for now:
<Typography display={'inline'}>{text}</Typography>

react-infinite-scroll not working inside Material UI Drawer

I am currently using react-infinite-scroll-component to paginate the comments from a certain post. There is a button in the comment section which shows a drawer that is supposed to show the paginated comments. The problem is, the react-infinite-scroll-component doesn't work, as it does not fire
the "next" function.
Here is the code:
<div>
<Drawer
anchor={"bottom"}
open={open}
onClose={handleDrawer}
style={{ height: "100vh", overflow: "auto", margin: "0px 4px" }}
>
<Toolbar>
<Typography variant="h4" style={{ flexGrow: 1 }}>
Comments
</Typography>
<IconButton onClick={handleDrawer}>
<CloseIcon />
</IconButton>
</Toolbar>
<Divider />
<br />
<CommentForm
comment={comment}
handleChange={handleChange}
handleSubmit={handleSubmit}
/>
<InfiniteScroll
dataLength={page}
next={More}
hasMore={hasMore}
loader={
<>
<br />
<CircularProgress />
</>
}
style={{
overflow: "hidden",
}}
scrollThreshold={1}
>
<CommentList comments={comments} id={session.id} />
</InfiniteScroll>
</Drawer>
</div>
The drawer is mostly similar to Youtube's comment drawer on the mobile app. Is there anything I am missing here?
Probably, the problem is the relation with Drawer and Infinite Scroll height. The height of Infinite Scroll is not reaching the right point to trigger next function. If you provide the demo in Codesandbox would be easier to understand.
Fixed height of infinite scroll container
<Box sx={{ height: 500 }}>
<InfiniteScroll
dataLength={page}
next={More}
hasMore={hasMore}
loader={
<>
<br />
<CircularProgress />
</>
}
style={{
overflow: "hidden",
}}
scrollThreshold={1}
>
<CommentList comments={comments} id={session.id} />
</InfiniteScroll>
</Box>

Unable to show icon when i hover using reactjs

I'm new to the framework. My objective is to show the icon when i hover on the tab, But i couldn't able to perform hover.
I've tried by giving css as display: none and hover too, but didn't worked.
Can anyone help me in solving this issue?
Here is the code:
showIcon: {
// display: "none",
"&.hover": {
display: "visible"
}
}
<Card>
<CardHeader
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div>
<IconButton
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu id="simple-menu" keepMounted anchorEl={this.state.menu}>
<MenuItem>Profile</MenuItem>
<MenuItem>change password</MenuItem>
<MenuItem>Logout</MenuItem>
</Menu>
</div>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
</Card>
Here is the sample code
I forked your code and fixed it for you;
What was wrong? All css pseudo classes need to have a : delimiter, not a .. Additionally, the hover was on the wrong element

Unable to show icon after showing menu Items in reactjs

I have created a dropdown for the icon where when the icon is clicked, it will show the dropdown. Once we hover on Card then the three dots icon will appear. But my objective is even after showing dropdown the icon should appear. but here is my code, it is disappearing. Can anyone help me with this query?
Here is the code:
<Card>
<CardHeader
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div>
<IconButton
id="simple-menu"
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
style={{ marginTop: "35px" }}
id="simple-menu"
keepMounted
anchorEl={this.state.menu}
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>change password</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>
</Card>
Here is the sample code
Create a style className which sets the icon visibility to visible. Conditionally assign the class to the parent div only when the menu is open i.e. check for this.state.menu && classes.menu.
Style
const styles = theme => ({
header: {
background: "grey",
"&:hover": {
background: "yellow",
"& $showIcon": {
visibility: "visible"
}
}
},
showIcon: {
visibility: "hidden"
},
menu: {
"& $showIcon": {
visibility: "visible"
}
}
});
JSX
<Card>
<CardHeader
className={classes.header}
avatar={<Avatar aria-label="recipe">R</Avatar>}
action={
<div className={this.state.menu && classes.menu}>
<IconButton
id="simple-menu"
className={classes.showIcon}
aria-label="settings"
aria-controls="simple-menu"
onClick={this.handleClick}
>
<MoreVertIcon />
</IconButton>
...
Working copy of your code is here

Resources