Browse Source

ensure contextMenu doesn't overflow viewport (#364)

David Luzar 5 năm trước cách đây
mục cha
commit
8104c8525d
2 tập tin đã thay đổi với 35 bổ sung4 xóa
  1. 6 1
      src/components/ContextMenu.tsx
  2. 29 3
      src/components/Popover.tsx

+ 6 - 1
src/components/ContextMenu.tsx

@@ -18,7 +18,12 @@ type Props = {
 
 function ContextMenu({ options, onCloseRequest, top, left }: Props) {
   return (
-    <Popover onCloseRequest={onCloseRequest} top={top} left={left}>
+    <Popover
+      onCloseRequest={onCloseRequest}
+      top={top}
+      left={left}
+      fitInViewport={true}
+    >
       <ul className="context-menu" onContextMenu={e => e.preventDefault()}>
         {options.map((option, idx) => (
           <li

+ 29 - 3
src/components/Popover.tsx

@@ -1,15 +1,41 @@
-import React from "react";
+import React, { useLayoutEffect, useRef } from "react";
 
 type Props = {
   top?: number;
   left?: number;
   children?: React.ReactNode;
   onCloseRequest?(): void;
+  fitInViewport?: boolean;
 };
 
-export function Popover({ children, left, onCloseRequest, top }: Props) {
+export function Popover({
+  children,
+  left,
+  top,
+  onCloseRequest,
+  fitInViewport = false
+}: Props) {
+  const popoverRef = useRef<HTMLDivElement>(null);
+
+  // ensure the popover doesn't overflow the viewport
+  useLayoutEffect(() => {
+    if (fitInViewport && popoverRef.current) {
+      const element = popoverRef.current;
+      const { x, y, width, height } = element.getBoundingClientRect();
+
+      const viewportWidth = window.innerWidth;
+      if (x + width > viewportWidth) {
+        element.style.left = viewportWidth - width + "px";
+      }
+      const viewportHeight = window.innerHeight;
+      if (y + height > viewportHeight) {
+        element.style.top = viewportHeight - height + "px";
+      }
+    }
+  }, [fitInViewport]);
+
   return (
-    <div className="popover" style={{ top: top, left: left }}>
+    <div className="popover" style={{ top: top, left: left }} ref={popoverRef}>
       <div
         className="cover"
         onClick={onCloseRequest}