Close modal on click outside

This commit is contained in:
Kalle (Sendou)
2022-01-19 18:27:01 +02:00
parent be10d4b460
commit b9a79103a2
3 changed files with 35 additions and 3 deletions

View File

@@ -1,5 +1,6 @@
import * as React from "react";
import { Link } from "remix";
import { Link, useNavigate } from "remix";
import { useOnClickOutside } from "~/hooks/common";
export default function Modal({
closeUrl,
@@ -10,9 +11,18 @@ export default function Modal({
title: React.ReactNode;
children: React.ReactNode;
}) {
const navigate = useNavigate();
const ref = React.useRef<HTMLDivElement>(null);
const useOnClickOutsideHandler = React.useCallback(
() => navigate(closeUrl),
[closeUrl]
);
useOnClickOutside(ref, useOnClickOutsideHandler);
return (
<div className="modal">
<div>
<div ref={ref}>
<Link to={closeUrl} className="modal-close">
Close
</Link>

View File

@@ -76,3 +76,24 @@ export const useTimeoutState = <T>(
);
return [state, setState];
};
/** @link https://usehooks.com/useOnClickOutside/ */
export function useOnClickOutside<T extends HTMLElement = HTMLElement>(
ref: React.RefObject<T>,
handler: (event: MouseEvent | TouchEvent) => void
) {
React.useEffect(() => {
const listener = (event: MouseEvent | TouchEvent) => {
if (!ref.current || ref.current.contains(event.target as Node)) {
return;
}
handler(event);
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener);
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
};
}, [ref, handler]);
}

View File

@@ -32,7 +32,7 @@ export function requireEvents(ctx: unknown) {
try {
const data = z.object({ events: z.unknown() }).parse(ctx);
// TODO:
// TODO: fix type assertion
return data.events as EventTargetRecorder;
} catch (e) {
console.error(e);
@@ -41,6 +41,7 @@ export function requireEvents(ctx: unknown) {
}
/** Asserts condition is truthy. Throws a new `Response` with status code 400 and given message if falsy. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- same format as TS docs: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions
export function validate(condition: any, message: string): asserts condition {
if (condition) return;