fix: click outside select input in popover event bubbling
This commit is contained in:
@@ -14,6 +14,7 @@ import Button, { Inner } from "~/components/Button";
|
|||||||
import Text from "~/components/Text";
|
import Text from "~/components/Text";
|
||||||
import useMenuHeight from "~/hooks/useMenuHeight";
|
import useMenuHeight from "~/hooks/useMenuHeight";
|
||||||
import useMobile from "~/hooks/useMobile";
|
import useMobile from "~/hooks/useMobile";
|
||||||
|
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||||
import { fadeAndScaleIn } from "~/styles/animations";
|
import { fadeAndScaleIn } from "~/styles/animations";
|
||||||
import {
|
import {
|
||||||
Position,
|
Position,
|
||||||
@@ -76,9 +77,9 @@ const InputSelect = (props: Props) => {
|
|||||||
selectedValue: value,
|
selectedValue: value,
|
||||||
});
|
});
|
||||||
|
|
||||||
const popOver = useSelectPopover({
|
const popover = useSelectPopover({
|
||||||
...select,
|
...select,
|
||||||
hideOnClickOutside: true,
|
hideOnClickOutside: false,
|
||||||
preventBodyScroll: true,
|
preventBodyScroll: true,
|
||||||
disabled,
|
disabled,
|
||||||
});
|
});
|
||||||
@@ -107,6 +108,16 @@ const InputSelect = (props: Props) => {
|
|||||||
(option) => option.value === select.selectedValue
|
(option) => option.value === select.selectedValue
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Custom click outside handling rather than using `hideOnClickOutside` from reakit so that we can
|
||||||
|
// prevent event bubbling.
|
||||||
|
useOnClickOutside(contentRef, (event) => {
|
||||||
|
if (select.visible) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
select.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
previousValue.current = value;
|
previousValue.current = value;
|
||||||
select.setSelectedValue(value);
|
select.setSelectedValue(value);
|
||||||
@@ -156,7 +167,7 @@ const InputSelect = (props: Props) => {
|
|||||||
</StyledButton>
|
</StyledButton>
|
||||||
)}
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
<SelectPopover {...select} {...popOver} aria-label={ariaLabel}>
|
<SelectPopover {...select} {...popover} aria-label={ariaLabel}>
|
||||||
{(props: InnerProps) => {
|
{(props: InnerProps) => {
|
||||||
const topAnchor = props.style?.top === "0";
|
const topAnchor = props.style?.top === "0";
|
||||||
const rightAnchor = props.placement === "bottom-end";
|
const rightAnchor = props.placement === "bottom-end";
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import breakpoint from "styled-components-breakpoint";
|
|||||||
import { depths, s } from "@shared/styles";
|
import { depths, s } from "@shared/styles";
|
||||||
import useKeyDown from "~/hooks/useKeyDown";
|
import useKeyDown from "~/hooks/useKeyDown";
|
||||||
import useMobile from "~/hooks/useMobile";
|
import useMobile from "~/hooks/useMobile";
|
||||||
|
import useOnClickOutside from "~/hooks/useOnClickOutside";
|
||||||
import { fadeAndScaleIn } from "~/styles/animations";
|
import { fadeAndScaleIn } from "~/styles/animations";
|
||||||
|
|
||||||
type Props = PopoverProps & {
|
type Props = PopoverProps & {
|
||||||
@@ -29,6 +30,7 @@ const Popover: React.FC<Props> = ({
|
|||||||
mobilePosition,
|
mobilePosition,
|
||||||
...rest
|
...rest
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const contentRef = React.useRef<HTMLDivElement>(null);
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
|
|
||||||
// Custom Escape handler rather than using hideOnEsc from reakit so we can
|
// Custom Escape handler rather than using hideOnEsc from reakit so we can
|
||||||
@@ -46,6 +48,16 @@ const Popover: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Custom click outside handling rather than using `hideOnClickOutside` from reakit so that we can
|
||||||
|
// respect event.defaultPrevented.
|
||||||
|
useOnClickOutside(contentRef, (event) => {
|
||||||
|
if (rest.visible && !event.defaultPrevented) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
rest.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return (
|
return (
|
||||||
<Dialog {...rest} modal>
|
<Dialog {...rest} modal>
|
||||||
@@ -62,8 +74,9 @@ const Popover: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReakitPopover {...rest} hideOnEsc={false}>
|
<ReakitPopover {...rest} hideOnEsc={false} hideOnClickOutside={false}>
|
||||||
<Contents
|
<Contents
|
||||||
|
ref={contentRef}
|
||||||
$shrink={shrink}
|
$shrink={shrink}
|
||||||
$width={width}
|
$width={width}
|
||||||
$scrollable={scrollable}
|
$scrollable={scrollable}
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ export default function useOnClickOutside(
|
|||||||
[ref, callback]
|
[ref, callback]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEventListener("mousedown", listener);
|
useEventListener("mousedown", listener, window);
|
||||||
useEventListener("touchstart", listener);
|
useEventListener("touchstart", listener, window);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user