click to toggle outfit controls on mobile

On mobile, it was pretty annoying that you had to show the controls by tapping the preview area to simulate a hover—because it could also click the underlying elements, and do bad stuff!

Here, I add a click capture to prevent the clicks from going down if the controls aren't visible. And I add a toggle, so that you can dismiss the controls, like how YouTube feels :)
This commit is contained in:
Emi Matchu 2020-08-05 01:06:05 -07:00
parent 1efc1c0d42
commit 90b4fc8da4

View file

@ -62,6 +62,14 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
[dispatchToOutfit, toast] [dispatchToOutfit, toast]
); );
const maybeUnlockFocus = (e) => {
// We lock focus when a touch-device user taps the area. When they tap
// empty space, we treat that as a toggle and release the focus lock.
if (e.target === e.currentTarget) {
onUnlockFocus();
}
};
return ( return (
<Box <Box
role="group" role="group"
@ -83,16 +91,40 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
opacity: 0; opacity: 0;
transition: opacity 0.2s; transition: opacity 0.2s;
&:hover,
&:focus-within, &:focus-within,
&.focus-is-locked { &.focus-is-locked {
opacity: 1; opacity: 1;
} }
/* Ignore simulated hovers, only reveal for _real_ hovers. This helps
* us avoid state conflicts with the focus-lock from clicks. */
@media (hover: hover) {
&:hover {
opacity: 1;
}
}
`, `,
focusIsLocked && "focus-is-locked" focusIsLocked && "focus-is-locked"
)} )}
onClickCapture={(e) => {
const opacity = parseFloat(getComputedStyle(e.currentTarget).opacity);
if (opacity < 0.5) {
// If the controls aren't visible right now, then clicks on them are
// probably accidental. Ignore them! (We prevent default to block
// built-in behaviors like link nav, and we stop propagation to block
// our own custom click handlers. I don't know if I can prevent the
// select clicks though?)
e.preventDefault();
e.stopPropagation();
// We also show the controls, by locking focus. We'll undo this when
// the user taps elsewhere (because it will trigger a blur event from
// our child components), in `maybeUnlockFocus`.
setFocusIsLocked(true);
}
}}
> >
<Box gridArea="back"> <Box gridArea="back" onClick={maybeUnlockFocus}>
<ControlButton <ControlButton
as={Link} as={Link}
to="/" to="/"
@ -106,6 +138,7 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
alignSelf="flex-end" alignSelf="flex-end"
spacing={{ base: "2", lg: "4" }} spacing={{ base: "2", lg: "4" }}
align="flex-end" align="flex-end"
onClick={maybeUnlockFocus}
> >
<Box> <Box>
<DownloadButton outfitState={outfitState} /> <DownloadButton outfitState={outfitState} />
@ -114,8 +147,8 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
<CopyLinkButton outfitState={outfitState} /> <CopyLinkButton outfitState={outfitState} />
</Box> </Box>
</Stack> </Stack>
<Box gridArea="space" /> <Box gridArea="space" onClick={maybeUnlockFocus} />
<Flex gridArea="picker" justify="center"> <Flex gridArea="picker" justify="center" onClick={maybeUnlockFocus}>
{/** {/**
* We try to center the species/color picker, but the left spacer will * We try to center the species/color picker, but the left spacer will
* shrink more than the pose picker container if we run out of space! * shrink more than the pose picker container if we run out of space!