From 3cb96f6f54902074aa1e44adbe86e4d8a6497eba Mon Sep 17 00:00:00 2001 From: novykh Date: Thu, 21 Nov 2024 19:09:03 +0200 Subject: [PATCH] v4.8.0 --- package.json | 2 +- src/components/drops/drop/index.js | 57 ++++++++++++++++++++++--- src/components/tabs/tab.js | 2 +- src/components/templates/layer/index.js | 4 +- src/hooks/useOutsideClick/index.js | 5 ++- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 3297e50f..770b42e9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@netdata/netdata-ui", - "version": "4.7.11", + "version": "4.8.0", "description": "netdata UI kit", "main": "dist/index.js", "module": "dist/es6/index.js", diff --git a/src/components/drops/drop/index.js b/src/components/drops/drop/index.js index 8e50bf4c..716a83f0 100644 --- a/src/components/drops/drop/index.js +++ b/src/components/drops/drop/index.js @@ -1,4 +1,4 @@ -import React, { forwardRef, useLayoutEffect } from "react" +import React, { forwardRef, useState, useLayoutEffect } from "react" import ReactDOM from "react-dom" import useDropElement from "@/hooks/useDropElement" import useKeyboardEsc from "@/hooks/useKeyboardEsc" @@ -20,25 +20,39 @@ const Backdrop = styled.div` } ` -const defaultAlign = { top: "bottom", left: "left" } +const leftTopAlign = { right: "left", bottom: "top" } +const leftBottomAlign = { right: "right", top: "bottom" } +const rightTopAlign = { left: "right", bottom: "top" } +const rightBottomAlign = { left: "left", top: "bottom" } + +const getAlign = (left, top) => { + if (left && top) return leftTopAlign + if (left) return leftBottomAlign + if (top) return rightTopAlign + return rightBottomAlign +} + +const defaultAlignValue = { top: "bottom", left: "left" } const Drop = forwardRef( ( { backdrop = false, target, - align = defaultAlign, + align: defaultAlign = defaultAlignValue, stretch = "width", onClickOutside, onEsc, children, canHideTarget = true, keepHorizontal, + dataDrop, ...rest }, parentRef ) => { const [ref, setRef] = useForwardRef(parentRef) + const [align, setAlign] = useState(defaultAlign) const updatePosition = useMakeUpdatePosition( target, @@ -49,13 +63,28 @@ const Drop = forwardRef( keepHorizontal ) + useLayoutEffect(() => { + if (!target?.getBoundingClientRect || !ref.current) return + + const { right: targetRight, bottom: targetBottom } = target.getBoundingClientRect() + + const winHeight = window.innerHeight + const winWidth = window.innerWidth + + const { width, height } = ref.current.getBoundingClientRect() + const left = targetRight + width > winWidth + const top = targetBottom + height > winHeight + + setAlign(getAlign(left, top)) + }, [target]) + useLayoutEffect(() => { updatePosition() }, [updatePosition]) useDimensionChange(target, updatePosition) - useOutsideClick(ref, onClickOutside, target) + useOutsideClick(ref, onClickOutside, target, backdrop, dataDrop) useKeyboardEsc(onEsc) const el = useDropElement() @@ -63,13 +92,27 @@ const Drop = forwardRef( return ReactDOM.createPortal( backdrop ? ( <> - + {children} - + ) : ( - + {children} ), diff --git a/src/components/tabs/tab.js b/src/components/tabs/tab.js index 87666c68..e8b35cb2 100644 --- a/src/components/tabs/tab.js +++ b/src/components/tabs/tab.js @@ -2,7 +2,7 @@ import React, { useCallback } from "react" import { StyledTab, StyledTabMenu } from "./styled" export const Tab = ({ index, isMenuItem, onChange, ...rest }) => { - const onClick = useCallback(() => onChange && onChange(index || 0), [index, onChange]) + const onClick = useCallback(e => onChange && onChange(index || 0, e), [index, onChange]) const TabComponent = isMenuItem ? StyledTabMenu : StyledTab return ( diff --git a/src/components/templates/layer/index.js b/src/components/templates/layer/index.js index 5b664ca3..bc662178 100644 --- a/src/components/templates/layer/index.js +++ b/src/components/templates/layer/index.js @@ -19,11 +19,12 @@ const Layer = ({ children, backdropContainerProps, backdropProps, + dataDrop = "", ...rest }) => { const ref = useRef() - useOutsideClick(ref, onClickOutside, null, backdrop) + useOutsideClick(ref, onClickOutside, null, backdrop, dataDrop) useKeyboardEsc(onEsc) const el = useDropElement() @@ -37,6 +38,7 @@ const Layer = ({ margin={margin} borderShadow={borderShadow} data-testid="layer-container" + data-drop={dataDrop} {...rest} > {children} diff --git a/src/hooks/useOutsideClick/index.js b/src/hooks/useOutsideClick/index.js index fafa8b4b..3885dd33 100644 --- a/src/hooks/useOutsideClick/index.js +++ b/src/hooks/useOutsideClick/index.js @@ -1,7 +1,7 @@ import { useEffect } from "react" import isAncestor from "@/components/drops/mixins/isAncestor" -export default (dropRef, onClickOutside, target, hasBackdrop) => { +export default (dropRef, onClickOutside, target, hasBackdrop, dataDrop = "") => { useEffect(() => { if (!onClickOutside || hasBackdrop) return @@ -11,7 +11,8 @@ export default (dropRef, onClickOutside, target, hasBackdrop) => { // dont fire when clicking in drop !isAncestor(dropRef.current, event.target) && // dont fire when clicking dropdown-button - !isAncestor(target, event.target) + !isAncestor(target, event.target) && + !event.target.closest(`[data-drop="${dataDrop}"]`) ) { onClickOutside(event) }