reposition palette when it touches edges of screen

This commit is contained in:
Red Adaya 2024-10-08 09:48:30 +08:00
parent a8d4114775
commit 45b8470355
2 changed files with 23 additions and 7 deletions

View File

View File

@ -3,7 +3,7 @@
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions"; import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
import clsx from "clsx"; import clsx from "clsx";
import { memo, useEffect, useRef } from "react"; import { memo, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import "./palette.less"; import "./palette.less";
@ -17,6 +17,7 @@ interface PaletteProps {
const Palette = memo(({ children, className, anchorRef, scopeRef }: PaletteProps) => { const Palette = memo(({ children, className, anchorRef, scopeRef }: PaletteProps) => {
const paletteRef = useRef<HTMLDivElement | null>(null); const paletteRef = useRef<HTMLDivElement | null>(null);
const [position, setPosition] = useState({ top: 0, left: 0 });
const domRect = useDimensionsWithExistingRef(scopeRef); const domRect = useDimensionsWithExistingRef(scopeRef);
const width = domRect?.width ?? 0; const width = domRect?.width ?? 0;
const height = domRect?.height ?? 0; const height = domRect?.height ?? 0;
@ -25,15 +26,30 @@ const Palette = memo(({ children, className, anchorRef, scopeRef }: PaletteProps
const paletteEl = paletteRef.current; const paletteEl = paletteRef.current;
const anchorEl = anchorRef.current; const anchorEl = anchorRef.current;
if (paletteEl && anchorEl) { if (paletteEl && anchorEl) {
const { bottom, left } = anchorEl.getBoundingClientRect(); const anchorRect = anchorEl.getBoundingClientRect();
paletteEl.style.position = "absolute"; let { bottom, left } = anchorRect;
paletteEl.style.top = `${bottom}px`;
paletteEl.style.left = `${left}px`; // Check if the palette goes beyond the right edge of the window
const rightEdge = left + paletteEl.offsetWidth;
if (rightEdge > window.innerWidth) {
left = window.innerWidth - paletteEl.offsetWidth - 15;
}
// Check if the palette goes beyond the bottom edge of the window
if (bottom + paletteEl.offsetHeight > window.innerHeight) {
bottom = anchorRect.top - paletteEl.offsetHeight;
}
setPosition({ top: bottom, left });
} }
}, [width, height, anchorRef]); }, [anchorRef, scopeRef, width, height]);
return createPortal( return createPortal(
<div ref={paletteRef} className={clsx("palette", className)}> <div
ref={paletteRef}
style={{ top: `${position.top}px`, left: `${position.left}px` }}
className={clsx("palette", className)}
>
{children} {children}
</div>, </div>,
document.body document.body