mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-12-06 21:44:13 +03:00
use dialog ref for popover portal
This commit is contained in:
parent
ee68752756
commit
24b514ec14
@ -6,7 +6,14 @@ import { useFormattedTimestamp } from "@/hooks/use-date-utils";
|
|||||||
import { getIconForLabel } from "@/utils/iconUtil";
|
import { getIconForLabel } from "@/utils/iconUtil";
|
||||||
import { useApiHost } from "@/api";
|
import { useApiHost } from "@/api";
|
||||||
import { Button } from "../../ui/button";
|
import { Button } from "../../ui/button";
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Textarea } from "../../ui/textarea";
|
import { Textarea } from "../../ui/textarea";
|
||||||
@ -91,6 +98,7 @@ type TabsWithActionsProps = {
|
|||||||
setSimilarity?: () => void;
|
setSimilarity?: () => void;
|
||||||
isPopoverOpen: boolean;
|
isPopoverOpen: boolean;
|
||||||
setIsPopoverOpen: (open: boolean) => void;
|
setIsPopoverOpen: (open: boolean) => void;
|
||||||
|
dialogContainer: HTMLDivElement | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function TabsWithActions({
|
function TabsWithActions({
|
||||||
@ -103,9 +111,16 @@ function TabsWithActions({
|
|||||||
setSimilarity,
|
setSimilarity,
|
||||||
isPopoverOpen,
|
isPopoverOpen,
|
||||||
setIsPopoverOpen,
|
setIsPopoverOpen,
|
||||||
|
dialogContainer,
|
||||||
}: TabsWithActionsProps) {
|
}: TabsWithActionsProps) {
|
||||||
const { t } = useTranslation(["views/explore", "views/faceLibrary"]);
|
const { t } = useTranslation(["views/explore", "views/faceLibrary"]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (pageToggle !== "tracking_details" && isPopoverOpen) {
|
||||||
|
setIsPopoverOpen(false);
|
||||||
|
}
|
||||||
|
}, [pageToggle, isPopoverOpen, setIsPopoverOpen]);
|
||||||
|
|
||||||
if (!search) return null;
|
if (!search) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -155,6 +170,7 @@ function TabsWithActions({
|
|||||||
search={search}
|
search={search}
|
||||||
open={isPopoverOpen}
|
open={isPopoverOpen}
|
||||||
setIsOpen={setIsPopoverOpen}
|
setIsOpen={setIsPopoverOpen}
|
||||||
|
container={dialogContainer}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -165,12 +181,14 @@ type AnnotationSettingsProps = {
|
|||||||
search: SearchResult;
|
search: SearchResult;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setIsOpen: (open: boolean) => void;
|
setIsOpen: (open: boolean) => void;
|
||||||
|
container?: HTMLElement | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function AnnotationSettings({
|
function AnnotationSettings({
|
||||||
search,
|
search,
|
||||||
open,
|
open,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
|
container,
|
||||||
}: AnnotationSettingsProps) {
|
}: AnnotationSettingsProps) {
|
||||||
const { t } = useTranslation(["views/explore"]);
|
const { t } = useTranslation(["views/explore"]);
|
||||||
const { annotationOffset, setAnnotationOffset } = useDetailStream();
|
const { annotationOffset, setAnnotationOffset } = useDetailStream();
|
||||||
@ -206,6 +224,9 @@ function AnnotationSettings({
|
|||||||
const Overlay = isDesktop ? Popover : Drawer;
|
const Overlay = isDesktop ? Popover : Drawer;
|
||||||
const Trigger = isDesktop ? PopoverTrigger : DrawerTrigger;
|
const Trigger = isDesktop ? PopoverTrigger : DrawerTrigger;
|
||||||
const Content = isDesktop ? PopoverContent : DrawerContent;
|
const Content = isDesktop ? PopoverContent : DrawerContent;
|
||||||
|
const contentProps = isDesktop
|
||||||
|
? { align: "end" as const, container: container ?? undefined }
|
||||||
|
: {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ml-2">
|
<div className="ml-2">
|
||||||
@ -234,7 +255,7 @@ function AnnotationSettings({
|
|||||||
? "w-[90vw] max-w-md p-0"
|
? "w-[90vw] max-w-md p-0"
|
||||||
: "mx-1 max-h-[75dvh] overflow-hidden rounded-t-2xl px-4 pb-4"
|
: "mx-1 max-h-[75dvh] overflow-hidden rounded-t-2xl px-4 pb-4"
|
||||||
}
|
}
|
||||||
{...(isDesktop ? { align: "end" } : {})}
|
{...contentProps}
|
||||||
data-annotation-popover
|
data-annotation-popover
|
||||||
>
|
>
|
||||||
<AnnotationSettingsPane
|
<AnnotationSettingsPane
|
||||||
@ -262,6 +283,7 @@ type DialogContentComponentProps = {
|
|||||||
setSimilarity?: () => void;
|
setSimilarity?: () => void;
|
||||||
isPopoverOpen: boolean;
|
isPopoverOpen: boolean;
|
||||||
setIsPopoverOpen: (open: boolean) => void;
|
setIsPopoverOpen: (open: boolean) => void;
|
||||||
|
dialogContainer: HTMLDivElement | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DialogContentComponent({
|
function DialogContentComponent({
|
||||||
@ -278,6 +300,7 @@ function DialogContentComponent({
|
|||||||
setSimilarity,
|
setSimilarity,
|
||||||
isPopoverOpen,
|
isPopoverOpen,
|
||||||
setIsPopoverOpen,
|
setIsPopoverOpen,
|
||||||
|
dialogContainer,
|
||||||
}: DialogContentComponentProps) {
|
}: DialogContentComponentProps) {
|
||||||
if (page === "tracking_details") {
|
if (page === "tracking_details") {
|
||||||
return (
|
return (
|
||||||
@ -296,6 +319,7 @@ function DialogContentComponent({
|
|||||||
setSimilarity={setSimilarity}
|
setSimilarity={setSimilarity}
|
||||||
isPopoverOpen={isPopoverOpen}
|
isPopoverOpen={isPopoverOpen}
|
||||||
setIsPopoverOpen={setIsPopoverOpen}
|
setIsPopoverOpen={setIsPopoverOpen}
|
||||||
|
dialogContainer={dialogContainer}
|
||||||
/>
|
/>
|
||||||
) : undefined
|
) : undefined
|
||||||
}
|
}
|
||||||
@ -354,6 +378,7 @@ function DialogContentComponent({
|
|||||||
setSimilarity={setSimilarity}
|
setSimilarity={setSimilarity}
|
||||||
isPopoverOpen={isPopoverOpen}
|
isPopoverOpen={isPopoverOpen}
|
||||||
setIsPopoverOpen={setIsPopoverOpen}
|
setIsPopoverOpen={setIsPopoverOpen}
|
||||||
|
dialogContainer={dialogContainer}
|
||||||
/>
|
/>
|
||||||
<div className="scrollbar-container flex-1 overflow-y-auto">
|
<div className="scrollbar-container flex-1 overflow-y-auto">
|
||||||
<ObjectDetailsTab
|
<ObjectDetailsTab
|
||||||
@ -421,12 +446,16 @@ export default function SearchDetailDialog({
|
|||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(search != undefined);
|
const [isOpen, setIsOpen] = useState(search != undefined);
|
||||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||||
|
const dialogContentRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const [dialogContainer, setDialogContainer] = useState<HTMLDivElement | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
const handleOpenChange = useCallback(
|
const handleOpenChange = useCallback(
|
||||||
(open: boolean) => {
|
(open: boolean) => {
|
||||||
setIsPopoverOpen(open);
|
|
||||||
setIsOpen(open);
|
setIsOpen(open);
|
||||||
if (!open) {
|
if (!open) {
|
||||||
|
setIsPopoverOpen(false);
|
||||||
// short timeout to allow the mobile page animation
|
// short timeout to allow the mobile page animation
|
||||||
// to complete before updating the state
|
// to complete before updating the state
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -437,6 +466,10 @@ export default function SearchDetailDialog({
|
|||||||
[setSearch],
|
[setSearch],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setDialogContainer(dialogContentRef.current);
|
||||||
|
}, [isOpen, search?.id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (search) {
|
if (search) {
|
||||||
setIsOpen(search != undefined);
|
setIsOpen(search != undefined);
|
||||||
@ -545,6 +578,7 @@ export default function SearchDetailDialog({
|
|||||||
</DialogPortal>
|
</DialogPortal>
|
||||||
)}
|
)}
|
||||||
<Content
|
<Content
|
||||||
|
ref={isDesktop ? dialogContentRef : undefined}
|
||||||
className={cn(
|
className={cn(
|
||||||
"scrollbar-container overflow-y-auto",
|
"scrollbar-container overflow-y-auto",
|
||||||
isDesktop &&
|
isDesktop &&
|
||||||
@ -581,6 +615,7 @@ export default function SearchDetailDialog({
|
|||||||
setSimilarity={setSimilarity}
|
setSimilarity={setSimilarity}
|
||||||
isPopoverOpen={isPopoverOpen}
|
isPopoverOpen={isPopoverOpen}
|
||||||
setIsPopoverOpen={setIsPopoverOpen}
|
setIsPopoverOpen={setIsPopoverOpen}
|
||||||
|
dialogContainer={dialogContainer}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -599,6 +634,7 @@ export default function SearchDetailDialog({
|
|||||||
setSimilarity={setSimilarity}
|
setSimilarity={setSimilarity}
|
||||||
isPopoverOpen={isPopoverOpen}
|
isPopoverOpen={isPopoverOpen}
|
||||||
setIsPopoverOpen={setIsPopoverOpen}
|
setIsPopoverOpen={setIsPopoverOpen}
|
||||||
|
dialogContainer={dialogContainer}
|
||||||
/>
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user