sendou.ink/app/components/Dialog.tsx
Kalle 35168111a6
Art (#1412)
* Add to nav

* Allow nav items on front page to take full width

* Initial+

* Fix vods page title

* Add page title

* Common art type

* ArtGrid to a different component

* User arts page initial

* Add art tab to user page

* Preview initial

* Fix art counting

* Fix link and onclick overlapping

* Link to user art page to arts they made

* Artist role initial

* Show description

* Make toggle in art page saved in search params

* Add white-space pre-wrap to plus comments

Not sure why it was removed in the first place?

* Commission open / text and edit those

* Add simple pagination

* New art link display logic

* New art initial

* Upload art

* Hide art from side nav too

* Show banner when waiting for approval

* Edit art

* Fix art sub nav link not showing active

* Relocate unvalidated art text

* Delete art

* Extract ImagePreview component

* Eliminate some layout shift

* BigImageDialog extract component + prevent layout shift

* i18n

* Fix unused var

* Fix tests
2023-07-09 11:48:28 +03:00

72 lines
1.7 KiB
TypeScript

import React from "react";
import invariant from "tiny-invariant";
export function Dialog({
children,
isOpen,
close,
className,
closeOnAnyClick,
}: {
children: React.ReactNode;
isOpen: boolean;
close?: () => void;
className?: string;
closeOnAnyClick?: boolean;
}) {
const ref = useDOMSync(isOpen);
// https://stackoverflow.com/a/26984690
const closeOnOutsideClick = close
? (event: React.MouseEvent<HTMLDialogElement, MouseEvent>) => {
if (closeOnAnyClick) return close();
const rect: DOMRect = ref.current.getBoundingClientRect();
const isInDialog =
rect.top <= event.clientY &&
event.clientY <= rect.top + rect.height &&
rect.left <= event.clientX &&
event.clientX <= rect.left + rect.width;
if (!isInDialog) {
close();
}
}
: undefined;
return (
<dialog className={className} ref={ref} onClick={closeOnOutsideClick}>
{children}
</dialog>
);
}
function useDOMSync(isOpen: boolean) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ref = React.useRef<any>(null);
React.useEffect(() => {
const dialog = ref.current;
if (dialog.open && isOpen) return;
if (!dialog.open && !isOpen) return;
const html = document.getElementsByTagName("html")[0];
invariant(html);
if (isOpen) {
dialog.showModal();
// TODO: can be replaced with https://twitter.com/argyleink/status/1529869352660439048 once gets control
html.classList.add("lock-scroll");
} else {
dialog.close();
html.classList.remove("lock-scroll");
}
return () => {
dialog.close();
html.classList.remove("lock-scroll");
};
}, [isOpen]);
return ref;
}