I want a Material UI Popover to open/close on mouse press, with the opening transition starting from the location of the mouse when the mouse was pressed. How do I do this?
You need to set anchorReference to anchorPosition and then use the mouse coordinate for anchor position. So you will need to manage mouse position using state:
const [mouseX, setMouseX] = useState();
const [mouseY, setMouseY] = useState();
then in your click handler set the states:
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
setMouseX(event.clientX);
setMouseY(event.clientY);
}
and finally in your jsx use mouse position in anchorPosition:
return (
<div>
<Button aria-describedby={id} variant="contained" onClick={handleClick}>
Open Popover
</Button>
<Popover
id={id}
anchorReference="anchorPosition"
anchorPosition={{ top: mouseY, left: mouseX }}
open={open}
onClose={handleClose}
anchorOrigin={{
vertical: "top",
horizontal: "left",
}}
>
<Typography sx={{ p: 2 }}>The content of the Popover.</Typography>
</Popover>
</div>
);
Related
We use tooltips a lot and I wanted to use the tooltip text to find elements. This works fine the first time, as the tooltip text is just in the title in the element. But on mouse over the title proprerty is removed and a new tooltip element is added at the bottom of the page. After issueing a click on the element, the mouse stays over it and the next time I can't find it by the title.
Without mouse over:
<span class="" title="Save changes">
...
</span>
with mouse over:
<span class="" aria-describedby="mui-97465">
...
</span>
...
<div role="tooltip" class="MuiTooltip-popper" id="mui-97465" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(3063px, 116px, 0px);" x-placement="bottom">
<div class="MuiTooltip-tooltip MuiTooltip-tooltipPlacementBottom" style="opacity: 1; transform: none; transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, transform 133ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;">
Save changes
</div>
</div>
I tried building my own command, but that doesn't work either:
Cypress.Commands.add("findByTooltip", (text) => {
cy.get("body")
.then(($body) => {
$body.find(`[title="${text}"]`).length > 0;
})
.then((byTitle) => {
byTitle
? cy.findByTitle(text)
: cy
.findByRole("tooltip")
.contains(text)
.its("id")
.then((id) => cy.get(`[aria-describedby=${id}]`));
});
});
Has anyone done something like this?
This part is missing a return value
.then(($body) => {
$body.find(`[title="${text}"]`).length > 0;
})
so either
.then(($body) => {
return $body.find(`[title="${text}"]`).length > 0;
})
or remove the brackets for "implied return"
.then(($body) => $body.find(`[title="${text}"]`).length > 0 )
I'm not sure title="Save Changes" is on the page DOM, at least the one MUI example is missing that attribute.
I would go for the aria-label
.then(($body) => $body.find(`[aria-label="${text}"]`).length > 0 )
To make the tooltip show, you need a hover of some kind. The most reliable seems to be cypress-real-events
cy.get((`[aria-label="${text}"]`)).realHover();
cy.findByRole("tooltip")
.contains(text)
.its("id")
.then((id) => cy.get(`[aria-describedby=${id}]`))
I am trying to do a custom mui popover. My custom popover's children are set on the right place but the popover component it self is placed on top left of the screen.
I use forward ref to pass the initial ref to children to two neested level.
I have a Navbar that contains a button to witch i attach the ref, a second component that is my customPopover, in my customPopover it returns a popover containing children passed by customPopover: the code of my CustomPopover:
<AppPopoverArrow
open={open}
ref={ref}
placement={"bottom-end"}
>
<Card className={classes.card}>
<CardHeader
sx={{marginBottom: "20px"}}
title={<Typography sx={{marginBottom: "5px"}} variant="subtitle1">Add a new collaborator</Typography>}
subheader={ <Typography variant="subtitle2">Please enter the email adress to receive the invitation</Typography>
}
/>
<CardContent className={classes.cardContent}>
<TextField sx={{height: 35, width: 320, marginBottom: "20px"}} placeholder="Email" onKeyDown={e => addAdress(e)}/>
{ adresses && <Typography variant="subtitle1" sx={{marginBottom: "15px"}}>{adresses.length} emails adresses added</Typography>}
{ adresses && adresses.map((email: string) => <Typography variant="subtitle2">{email}</Typography>) }
</CardContent>
<div className={classes.cardActionsArea}>
<CardActions>
<CustomButton onClick={onClose} color="secondary">
Cancel
</CustomButton>
<CustomButton onClick={onAddUser} variant="contained" color="primary" disabled={!adresses}>
Add
</CustomButton>
</CardActions>
</div>
</Card>
</AppPopoverArrow>
I'm using WebdriverIO to test some basic functionality on an Ionic (+ Angular) application. The framework setup works all right, but I can't find a way to click on certain HTML elements. For instance, this is some HTML sample:
<div class="tabbar show-tabbar" role="tablist" style="top: 166px; display: flex;">
<a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-0" aria-controls="tabpanel-t0-0"
aria-selected="true">
<span class="tab-button-text">Blah</span>
<div class="button-effect"></div>
</a>
<a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-1" aria-controls="tabpanel-t0-1"
aria-selected="false">
<span class="tab-button-text">Foo</span>
<div class="button-effect"
style="transform: translate3d(83px, -103px, 0px) scale(1); height: 240px; width: 240px; opacity: 0; transition: transform 395ms ease 0s, opacity 277ms ease 118ms;"></div>
</a>
<a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-2" aria-controls="tabpanel-t0-2"
aria-selected="false">
<span class="tab-button-text">Bar</span>
<div class="button-effect"
style="transform: translate3d(3px, -99px, 0px) scale(1); height: 240px; width: 240px; opacity: 0; transition: transform 395ms ease 0s, opacity 277ms ease 118ms;"></div>
</a>
<div class="tab-highlight animate" style="transform: translate3d(570px, 0px, 0px) scaleX(285);"></div>
</div>
And this is a super-simple test case that I'm doing to test the functionality:
import { expect } from "chai";
describe("Some Test", () => {
const logingUrl: string = "url0";
const appUrl: string = "url1";
it("Some Test Again", () => {
browser.url(logingUrl);
browser.url(appUrl);
const tab = $("#tab-t0-2");
tab.click();
expect(tab.getAttribute("aria-selected")).to.equal("true");
});
});
..but every time I run it, I get some weird error message that the element is no clickable at some point. Any clues?
[0-0] element click intercepted in "Some Test Again"
element click intercepted: Element <a class="tab-button has-title has-title-only" href="#" role="tab" id="tab-t0-2" aria-controls="tabpanel-t0-2" aria-selected="false">...</a> is not clickable at point (666, 170). Other element would receive the click: <ion-backdrop disable-activated="" role="presentation" tappable="" class="backdrop-no-tappable" style="opacity: 0.5;"></ion-backdrop>
(Session info: headless chrome=75.0.3770.100)
This is one of those classic Angular/Ionic backdrop gotcha's.
Let's start with the error message: element #tab-t0-2 is not clickable at point (coordinates), another element would receive the click: ion-backdrop.
This tells us that your targeted element cannot be clicked as the ion-backdrop tag is rendered on top of it. The ion-backdrop component is a short animation (usually used for modals), in this case, the semi dimming of the background (opacity: 0.5).
✖ Solution 1: Easy way to counter it? Explicitly expect for it to disappear, then click the targeted element.
it("Some Test Again", () => {
browser.url(logingUrl);
browser.url(appUrl);
// Explicitly wait for the backdrop animation to disappear:
const backdrop = $('.backdrop-no-tappable');
backdrop.waitForExist(5000, true, 'Backdrop still present');
const tab = $("#tab-t0-2");
tab.click();
expect(tab.getAttribute("aria-selected")).to.equal("true");
});
✖ Solution 2: Another thing you can try is only click on the tab element, once it is fully visible and intractable in the DOM (this is kind of a best-practice):
const tab = $("#tab-t0-2");
tab.waitForDisplayed(5000);
// For 'wdio-v4' users:
// tab.waitForVisible(5000);
tab.click();
expect(tab.getAttribute("aria-selected")).to.equal("true");
I'm having problems creating a hoverable tooltip. The tooltip should have a button in it that can be used to open a popover. The problem I have is that once I open the popover it closes the tooltip. The popover is also displayed behind the tooltip.
<Tooltip
interactive
title={<Content />}
placement="right-start"
>
Content:
return (
<div>
<Button
aria-owns={open ? 'simple-popper' : undefined}
aria-haspopup="true"
variant="contained"
onClick={this.handleClick}
>
Open Popover
</Button>
<Popover
id="simple-popper"
open={open}
anchorEl={anchorEl}
onClose={this.handleClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
>
The content of the PopoverThe content of the the Popover.The content of the PopoverThe content of the the Popover.The content of the PopoverThe content of the the Popover.</Typography>
</Popover>
</div>
);
EDIT: created a code sandbox https://codesandbox.io/s/6w26o2ww0z
Hi I want to style three buttons with different colors but When those buttons are disabled the custom style I've added at the beginning overrides the default style disabledTextColor, which adds a default fade and transparency value, so users can see that the button is disabled. How can style the disabled state or which should be the correct way to style the labelStyle and/or disabledTextColor? Here is an example
const style = {
labelStyle: {
color: 'red;
}
}
<FlatButton
label='Mit Linkedin anmelden'
labelPosition='after'
icon={<LinkedinIcon />}
onClick={() => Meteor.loginWithLinkedin()}
disabled={true}
labelStyle={style.labelStyle}
/>
</div>
<div className='mdl-cell mdl-cell--12-col'>
<FlatButton
label='Mit Google anmelden'
labelPosition='after'
icon={<GoogleIcon />}
onClick={() => Meteor.loginWithGoogle()}
disabled={true}
labelStyle={style.labelStyle}
/>
</div>
in this case the button always stays red even though the disabled state in True
You can create a little wrapper component around FlatButton that conditionally fades the labelStyle when the button is disabled.
const CustomFlatButton = (props) => (
<FlatButton
{...props}
labelStyle={{ ...props.labelStyle, opacity: props.disabled ? 0.3 : 1 }}
/>
);
...
<CustomFlatButton label="Disabled Red" style={{ color: 'red' }} disabled />
https://jsfiddle.net/6rads3tt/2/